github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/ChaparKhane/user-connections.go (about)

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package chaparkhane
     4  
     5  import (
     6  	"hash/crc32"
     7  
     8  	"../chapar"
     9  	"../crypto"
    10  	"../uuid"
    11  )
    12  
    13  // userConnections store pools of connection to retrieve in many ways!
    14  type userConnections struct {
    15  	old            *userConnections // use just in expanding
    16  	pathsPool      [254][]*UserConnection
    17  	usersGPPoolLen uint32
    18  	usersGPPool    []userGPBucket
    19  	usersPoolLen   uint32
    20  	usersPool      []userBucket
    21  }
    22  
    23  type userGPBucket struct {
    24  	FreeID   uint8
    25  	UserGPID [8]uint32
    26  	Conn     [8]*UserConnection
    27  }
    28  
    29  type userBucket struct {
    30  	FreeID uint8
    31  	UserID [8][16]byte
    32  	Conn   [8][]*UserConnection
    33  }
    34  
    35  func (uc *userConnections) init() {
    36  	// TotalHop = 1 or One hop frame use just in p2p networks and not pass here!!
    37  	// TotalHop = 2 or Two hop implement by just one Chapar switch device!
    38  	uc.pathsPool[0] = make([]*UserConnection, 256)
    39  	// TotalHop > 2 or More than two hop implement by more than one Chapar switch device!
    40  	var i uint8
    41  	for i = 1; i < 255; i++ {
    42  		uc.pathsPool[i] = make([]*UserConnection, 2048)
    43  	}
    44  
    45  	uc.usersGPPool = make([]userGPBucket, 2048)
    46  	uc.usersGPPoolLen = 2048
    47  
    48  	uc.usersPool = make([]userBucket, 2048)
    49  	uc.usersPoolLen = 2048
    50  }
    51  
    52  func (uc *userConnections) expandPathPool(hopNum uint8) (newPoolLen uint32) {
    53  	var poolLen uint32 = uint32(len(uc.pathsPool[hopNum]))
    54  	newPoolLen = poolLen * 2
    55  
    56  	var new = make([]*UserConnection, newPoolLen)
    57  
    58  	// Copy old paths
    59  	var existingConn *UserConnection
    60  	var loc uint32
    61  	var i uint32
    62  	for i = 0; i < poolLen; i++ {
    63  		existingConn = uc.pathsPool[hopNum][i]
    64  		if existingConn != nil {
    65  			loc = crc32.ChecksumIEEE(existingConn.Path) % newPoolLen
    66  			new[loc] = existingConn
    67  		}
    68  	}
    69  	uc.pathsPool[hopNum] = new
    70  
    71  	return
    72  }
    73  
    74  func (uc *userConnections) expandUsersGPPool() {
    75  	var newPoolLen uint32 = uc.usersGPPoolLen * 2
    76  	var new = make([]userGPBucket, newPoolLen)
    77  
    78  	// Copy old records
    79  	var loc uint32
    80  	var i uint32
    81  	var j uint8
    82  	var f uint8
    83  	for i = 0; i < uc.usersGPPoolLen; i++ {
    84  		f = uc.usersGPPool[i].FreeID
    85  		for j = 0; j < f; j++ {
    86  			loc = uc.usersGPPool[i].Conn[j].UserGPID % newPoolLen
    87  			new[loc].UserGPID[f] = uc.usersGPPool[i].Conn[j].UserGPID
    88  			new[loc].Conn[f] = uc.usersGPPool[i].Conn[j]
    89  			uc.usersGPPool[i].FreeID++
    90  		}
    91  	}
    92  
    93  	uc.usersGPPool = new
    94  	uc.usersGPPoolLen = newPoolLen
    95  }
    96  
    97  func (uc *userConnections) expandUsersPool() {
    98  	var newPoolLen uint32 = uc.usersPoolLen * 2
    99  	var newPool = make([]userBucket, newPoolLen)
   100  
   101  	// Copy old records
   102  	var loc uint32
   103  	var i uint32
   104  	var j uint8
   105  	for i = 0; i < uc.usersGPPoolLen; i++ {
   106  		for j = 0; j < uc.usersPool[i].FreeID; j++ {
   107  			// TODO::: change finding loc algorithm!!
   108  			loc = uuid.GetFirstUint32(uc.usersPool[i].UserID[j]) % newPoolLen
   109  			newPool[loc].UserID[uc.usersPool[i].FreeID] = uc.usersPool[i].UserID[j]
   110  			newPool[loc].Conn[uc.usersPool[i].FreeID] = uc.usersPool[i].Conn[j]
   111  			uc.usersPool[i].FreeID++
   112  		}
   113  	}
   114  
   115  	uc.usersPool = newPool
   116  	uc.usersPoolLen = newPoolLen
   117  }
   118  
   119  // registerNewPath use to register or overwrite a path in the related pool!
   120  func (uc *userConnections) registerNewPath(conn *UserConnection, path []byte) {
   121  	var pathLen uint8 = uint8(len(conn.Path))
   122  	var poolLen uint32 = uint32(len(uc.pathsPool[pathLen]))
   123  	var loc = crc32.ChecksumIEEE(conn.Path) % poolLen
   124  
   125  	// Check collision!!
   126  	var existingConn = uc.pathsPool[pathLen][loc]
   127  	if existingConn != nil && existingConn.UserID != conn.UserID {
   128  		poolLen = uc.expandPathPool(pathLen)
   129  		loc = crc32.ChecksumIEEE(conn.Path) % poolLen
   130  	}
   131  
   132  	uc.pathsPool[pathLen][loc] = conn
   133  }
   134  
   135  // registerNewUser use to register or overwrite a user in the related pool!
   136  func (uc *userConnections) registerNewUser(conn *UserConnection) {
   137  	// TODO:::
   138  }
   139  
   140  // MakeNewUserConnectionReq is the request structure of MakeNewUserConnection()
   141  type MakeNewUserConnectionReq struct {
   142  	UserID        [16]byte
   143  	ThingID       [16]byte
   144  	UserPublicKey [32]byte
   145  	Path          []byte
   146  	MaxBandwidth  uint64
   147  	Signature     [256]byte
   148  }
   149  
   150  // MakeNewUserConnection use to make new connection!
   151  func (uc *userConnections) MakeNewUserConnection(req *MakeNewUserConnectionReq) {
   152  	// TODO::: Check signature first!
   153  
   154  	var conns []*UserConnection
   155  	var conn *UserConnection
   156  	conns = uc.GetConnectionsByUserID(req.UserID)
   157  	// Check if just new way to exiting user in specific thing!!
   158  	if conns != nil {
   159  		var i int
   160  		var ln int = len(conns)
   161  		for i = 0; i < ln; i++ {
   162  			if conns[i].UserID == req.UserID && conns[i].ThingID == req.ThingID {
   163  				conn = conns[i]
   164  				break
   165  			}
   166  		}
   167  	}
   168  
   169  	if conn != nil {
   170  		conn.AlternativePath = append(conn.AlternativePath, req.Path)
   171  		uc.registerNewPath(conn, req.Path)
   172  	} else {
   173  		// TODO::: Check user can make new connection
   174  
   175  		conn = &UserConnection{
   176  			UserID:        req.UserID,
   177  			Path:          req.Path,
   178  			ReversePath:   chapar.ReversePath(req.Path),
   179  			ThingID:       req.ThingID,
   180  			Status:        routerConnectionStateOpen,
   181  			MaxBandwidth:  req.MaxBandwidth,
   182  			PeerPublicKey: req.UserPublicKey,
   183  			Cipher:        crypto.NewGCM(crypto.NewAES256([32]byte{})),
   184  		}
   185  		uc.RegisterConnection(conn)
   186  	}
   187  }
   188  
   189  // RegisterConnection use to register new connection in server connection pool!!
   190  func (uc *userConnections) RegisterConnection(conn *UserConnection) {
   191  	uc.registerNewPath(conn, conn.Path)
   192  	uc.registerNewUser(conn)
   193  }
   194  
   195  // GetConnectionByPath use to get a connection by peer GP from connections pool!!
   196  func (uc *userConnections) GetConnectionByPath(path []byte) (conn *UserConnection) {
   197  	var pathLen = len(path)
   198  	var poolLen uint32 = uint32(len(uc.pathsPool[pathLen]))
   199  	var loc = crc32.ChecksumIEEE(path) % poolLen
   200  
   201  	conn = uc.pathsPool[pathLen][loc]
   202  	return
   203  }
   204  
   205  // GetConnectionsByUserID use to get connections by peer UserID from connections pool!!
   206  func (uc *userConnections) GetConnectionsByUserID(userID [16]byte) (conns []*UserConnection) {
   207  	// TODO::: change finding loc algorithm!!
   208  	var loc = uuid.GetFirstUint32(userID) % uc.usersPoolLen
   209  
   210  	var i uint8
   211  	for i = 0; i < uc.usersPool[loc].FreeID; i++ {
   212  		if uc.usersPool[loc].UserID[i] == userID {
   213  			conns = uc.usersPool[loc].Conn[i]
   214  			break
   215  		}
   216  		// check if connection is in not ready status
   217  	}
   218  	return
   219  }
   220  
   221  // GetConnectionByUserGPID use to get a connection by user GP ID part from connections pool!!
   222  func (uc *userConnections) GetConnectionByUserGPID(userGPID uint32) (conn *UserConnection) {
   223  	// TODO::: change finding loc algorithm!!
   224  	var loc = userGPID % uc.usersGPPoolLen
   225  
   226  	var i uint8
   227  	for i = 0; i < uc.usersGPPool[loc].FreeID; i++ {
   228  		if uc.usersGPPool[loc].UserGPID[i] == userGPID {
   229  			conn = uc.usersGPPool[loc].Conn[i]
   230  			break
   231  		}
   232  		// check if connection is in not ready status
   233  	}
   234  	return
   235  }
   236  
   237  // CloseConnection use to un-register exiting connection in server connection pool!!
   238  func (uc *userConnections) CloseConnection(conn *UserConnection) {
   239  	// TODO::: Check GC performance : delete connection vs just reset it and send it to pool of unused connection!!
   240  	var pathLen = len(conn.Path)
   241  	var poolLen uint32 = uint32(len(uc.pathsPool[pathLen]))
   242  	var loc = crc32.ChecksumIEEE(conn.Path) % poolLen
   243  
   244  	uc.pathsPool[pathLen][loc] = nil
   245  
   246  	loc = conn.UserGPID % uc.usersGPPoolLen
   247  	var eGPPool = uc.usersGPPool[loc]
   248  	var f = eGPPool.FreeID
   249  	var i uint8
   250  	for i = 0; i < f; i++ {
   251  		if eGPPool.UserGPID[i] == conn.UserGPID {
   252  			eGPPool.UserGPID[i] = 0
   253  			eGPPool.Conn[i] = nil
   254  			break
   255  		}
   256  	}
   257  
   258  	loc = uuid.GetFirstUint32(conn.UserID) % uc.usersPoolLen
   259  	var eUserPool = uc.usersPool[loc]
   260  	f = eUserPool.FreeID
   261  	for i = 0; i < f; i++ {
   262  		if eUserPool.UserID[i] == conn.UserID {
   263  			var conns = eUserPool.Conn[i]
   264  			var j = len(conns) - 1
   265  			for ; j >= 0; j-- {
   266  				if conns[j].UserGPID == conn.UserGPID {
   267  					// TODO::: is it worth to delete an item in middle of array!!?
   268  					conns[j] = nil
   269  					break
   270  				}
   271  			}
   272  
   273  			break
   274  		}
   275  	}
   276  }