NL_EXP NLboolean NL_APIENTRY nlMutexDestroy(NLmutex *mutex) { if(mutex == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } if(*mutex == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } else { NLmutex mx = *mutex; #ifdef NL_WIN_THREADS /* native Windows */ DeleteCriticalSection(&mx->mutex); #else /* POSIX */ (void)pthread_mutex_destroy((pthread_mutex_t *)&mx->mutex); #endif } free(*mutex); *mutex = NULL; return NL_TRUE; }
NLboolean nlGroupGetSocketsINT(NLint group, NLsocket *socket, NLint *number) { NLint realgroup = group - NL_FIRST_GROUP; NLint len, i; nl_group_t *pgroup = NULL; if(socket == NULL || number == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } if(groups == NULL) { nlSetError(NL_NO_NETWORK); return NL_FALSE; } if(realgroup < 0) { nlSetError(NL_INVALID_GROUP); *number = 0; return NL_FALSE; } pgroup = groups[realgroup]; len = *number; if(len > pgroup->numsockets) { len = pgroup->numsockets; } for(i=0;i<len;i++) { socket[i] = pgroup->sockets[i]; } *number = len; return NL_TRUE; }
NL_EXP NLboolean NL_APIENTRY nlCondInit(NLcond *cond) { if(cond == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } else { #ifdef NL_WIN_THREADS NLcond cv = NULL; cv = (NLcond)malloc(sizeof(struct nl_cond_t)); if(cv == NULL) { nlSetError(NL_OUT_OF_MEMORY); return NL_FALSE; } cv->events_[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL); cv->events_[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL); #else int result; NLcond cv = NULL; cv = (NLcond)malloc(sizeof(struct nl_cond_t)); if(cv == NULL) { nlSetError(NL_OUT_OF_MEMORY); return NL_FALSE; } result = pthread_cond_init((pthread_cond_t *)&cv->cond, NULL); if(result != 0) { free(cv); #ifdef WINDOWS_APP SetLastError((DWORD)result); #endif nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } result = pthread_mutex_init((pthread_mutex_t *)&cv->mutex, NULL); if(result != 0) { (void)pthread_cond_destroy((pthread_cond_t *)&cv->cond); free(cv); #ifdef WINDOWS_APP SetLastError((DWORD)result); #endif nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } #endif *cond = cv; } return NL_TRUE; }
NL_EXP NLboolean NL_APIENTRY nlMutexLock(NLmutex *mutex) { if(mutex == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } if(*mutex == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } else { NLmutex mx = *mutex; #ifdef NL_WIN_THREADS DWORD threadid = GetCurrentThreadId(); /* native Windows */ /* this call will not stop recursion on a single thread */ EnterCriticalSection(&mx->mutex); /* check for recursion */ if(mx->thread == threadid) { nlSetError(NL_MUTEX_RECURSION); /* must call LeaveCriticalSection for each EnterCriticalSection */ /* so this nullifies the above call to EnterCriticalSection*/ LeaveCriticalSection(&mx->mutex); return NL_FALSE; } else { mx->thread = threadid; } #else int result; /* POSIX */ result = pthread_mutex_lock((pthread_mutex_t *)&mx->mutex); if(result == EDEADLK) { nlSetError(NL_MUTEX_RECURSION); return NL_FALSE; } else if(result != 0) { #ifdef WINDOWS_APP SetLastError((DWORD)result); #endif nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } #endif } return NL_TRUE; }
NL_EXP NLboolean NL_APIENTRY nlMutexInit(NLmutex *mutex) { if(mutex == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } else { NLmutex mx; #ifdef NL_WIN_THREADS /* native Windows */ mx = (NLmutex)malloc(sizeof(struct nl_mutex_t)); if(mx == NULL) { nlSetError(NL_OUT_OF_MEMORY); return NL_FALSE; } InitializeCriticalSection(&mx->mutex); mx->thread = 0; #else /* POSIX */ pthread_mutexattr_t attr; int result; mx = (NLmutex)malloc(sizeof(struct nl_mutex_t)); if(mx == NULL) { nlSetError(NL_OUT_OF_MEMORY); return NL_FALSE; } (void)pthread_mutexattr_init(&attr); #if defined Macintosh /* GUSI is not fully POSIX compliant, and does not define PTHREAD_MUTEX_ERRORCHECK */ (void)pthread_mutexattr_settype(&attr, NULL); #else (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); #endif result = pthread_mutex_init((pthread_mutex_t *)&mx->mutex, &attr); (void)pthread_mutexattr_destroy(&attr); if(result != 0) { #ifdef WINDOWS_APP SetLastError((DWORD)result); #endif nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } #endif *mutex = mx; } return NL_TRUE; }
NLboolean loopback_Connect(NLsocket socket, NLaddress *address) { nl_socket_t *sock = nlSockets[socket]; NLushort port; NLint numsockets = NL_MAX_GROUP_SOCKETS; NLsocket temp[NL_MAX_GROUP_SOCKETS]; /* no need to connect a broadcast socket */ if(sock->type == NL_BROADCAST) { nlSetError(NL_WRONG_TYPE); } port = loopback_GetPortFromAddr(address); /* make sure socket is not already connected */ if(sock->connected == NL_TRUE || sock->connecting == NL_TRUE) { nlSetError(NL_CON_REFUSED); return NL_FALSE; } nlGroupGetSockets(loopgroup, (NLint *)&temp, &numsockets); if(numsockets <= 0) { return NL_FALSE; } while(numsockets-- > 0) { nl_socket_t *othersock = nlSockets[temp[numsockets]]; if(sock->type == othersock->type && port == othersock->localport && othersock->listen == NL_TRUE && othersock->connected == NL_FALSE && othersock->connecting == NL_FALSE) { /* we found the right socket, so connect */ NLint i; for(i=0;i<NL_MAX_ACCEPT;i++) { if(othersock->accept[i] == NL_INVALID) { othersock->accept[i] = socket; sock->connecting = NL_TRUE; sock->consock = temp[numsockets]; return NL_TRUE; } } } } nlSetError(NL_CON_REFUSED); return NL_FALSE; }
SOCKET nlGroupGetFdset(NLint group, fd_set *fd) { NLint realgroup = group - NL_FIRST_GROUP; nl_group_t *pgroup = NULL; if(groups == NULL) { nlSetError(NL_NO_NETWORK); return INVALID_SOCKET; } if(realgroup < 0) { nlSetError(NL_INVALID_GROUP); return INVALID_SOCKET; } pgroup = groups[realgroup]; if(pgroup == NULL) { nlSetError(NL_INVALID_GROUP); return INVALID_SOCKET; } /* if fdset is NULL, then create it */ if(pgroup->fdset == NULL) { int i; SOCKET realsock; /* create the fd_set */ pgroup->fdset = (fd_set *)malloc(sizeof(fd_set)); if(pgroup->fdset == NULL) { (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_MEMORY); return INVALID_SOCKET; } FD_ZERO(pgroup->fdset); pgroup->highest = 0; for(i=0;i<pgroup->numsockets;i++) { realsock = (SOCKET)nlSockets[pgroup->sockets[i]]->realsocket; FD_SET(realsock, pgroup->fdset); if(pgroup->highest < realsock + 1) { pgroup->highest = realsock + 1; } } } memcpy(fd, pgroup->fdset, sizeof(fd_set)); return pgroup->highest; }
NL_EXP NLboolean NL_APIENTRY nlMutexUnlock(NLmutex *mutex) { if(mutex == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } if(*mutex == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } else { NLmutex mx = *mutex; #ifdef NL_WIN_THREADS DWORD threadid = GetCurrentThreadId(); /* native Windows */ if((mx->thread == 0) ||(mx->thread != threadid)) { nlSetError(NL_MUTEX_OWNER); return NL_FALSE; } mx->thread = 0; LeaveCriticalSection(&mx->mutex); #else int result; /* POSIX */ result = pthread_mutex_unlock((pthread_mutex_t *)&mx->mutex); if(result == EPERM) { nlSetError(NL_MUTEX_OWNER); return NL_FALSE; } else if(result != 0) { #ifdef WINDOWS_APP SetLastError((DWORD)result); #endif nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } #endif } return NL_TRUE; }
NLsocket loopback_AcceptConnection(NLsocket socket) { nl_socket_t *sock = nlSockets[socket]; NLint i; if(sock->listen == NL_FALSE) { nlSetError(NL_NOT_LISTEN); return NL_INVALID; } /* look for a valid socket */ for(i=0;i<NL_MAX_ACCEPT;i++) { if(sock->accept[i] != NL_INVALID) { NLsocket newsocket = loopback_Open(0, sock->type); NLsocket osock = sock->accept[i]; nl_socket_t *othersock = nlSockets[osock]; sock->accept[i] = NL_INVALID; if(newsocket != NL_INVALID) { nl_socket_t *newsock = nlSockets[newsocket]; nlLockSocket(osock, NL_BOTH); /* do the connecting */ newsock->consock = osock; newsock->remoteport = othersock->localport; othersock->consock = newsocket; othersock->remoteport = newsock->localport; newsock->connected = NL_TRUE; othersock->connected = NL_TRUE; othersock->connecting = NL_FALSE; loopback_SetAddrPort(&othersock->address, othersock->remoteport); loopback_SetAddrPort(&newsock->address, newsock->remoteport); nlUnlockSocket(osock, NL_BOTH); return newsocket; } } } nlSetError(NL_NO_PENDING); return NL_INVALID; }
NLint loopback_Read(NLsocket socket, NLvoid *buffer, NLint nbytes) { nl_socket_t *sock = nlSockets[socket]; NLint len = sock->inlen[sock->nextinused]; NLint c = 0; NLushort port; if(len > 0) { if(len > nbytes) { nlSetError(NL_BUFFER_SIZE); return NL_INVALID; } if(sock->connecting == NL_TRUE) { nlSetError(NL_CON_PENDING); return NL_INVALID; } /* get the port number */ readShort(sock->inpacket[sock->nextinused], c, port); loopback_SetAddrPort(&sock->address, port); /* copy the packet */ memcpy(buffer, sock->inpacket[sock->nextinused] + 2, (size_t)len); /* zero out length and set up for next packet */ sock->inlen[sock->nextinused] = 0; sock->nextinused++; if(sock->nextinused >= NL_NUM_PACKETS) { sock->nextinused = 0; } } /* check for broken connection */ if(sock->connected == NL_TRUE && sock->consock == NL_INVALID) { nlSetError(NL_CON_TERM); return NL_INVALID; } return len; }
void loopback_Hint(NLenum name, NLint arg) { switch (name) { case NL_REUSE_ADDRESS: reuseaddress = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE); break; default: nlSetError(NL_INVALID_ENUM); break; } }
NL_EXP NLboolean NL_APIENTRY nlGroupDestroy(NLint group) { NLint realgroup = group - NL_FIRST_GROUP; if(groups == NULL) { nlSetError(NL_NO_NETWORK); return NL_FALSE; } if(realgroup < 0) { nlSetError(NL_INVALID_GROUP); return NL_FALSE; } if(nlMutexLock(&grouplock) == NL_FALSE) { return NL_FALSE; } if(groups[realgroup] != NULL) { if(groups[realgroup]->fdset != NULL) { free(groups[realgroup]->fdset); } if(groups[realgroup]->sockets != NULL) { free(groups[realgroup]->sockets); } free(groups[realgroup]); groups[realgroup] = NULL; nlnumgroups--; } if(nlMutexUnlock(&grouplock) == NL_FALSE) { return NL_FALSE; } return NL_TRUE; }
NLboolean loopback_Listen(NLsocket socket) { nl_socket_t *sock = nlSockets[socket]; NLint i = NL_MAX_ACCEPT; if(sock->type == NL_BROADCAST) { nlSetError(NL_WRONG_TYPE); return NL_FALSE; } sock->listen = NL_TRUE; while(i-- > 0) { sock->accept[i] = NL_INVALID; } return NL_TRUE; }
NLboolean nlGroupInit(void) { if(groups == NULL) { groups = (nl_group_t **)malloc(NL_MAX_GROUPS * sizeof(nl_group_t *)); } if(groups == NULL) { nlSetError(NL_OUT_OF_MEMORY); return NL_FALSE; } memset(groups, 0, NL_MAX_GROUPS * sizeof(nl_group_t *)); if(nlMutexInit(&grouplock) == NL_FALSE) { /* error code is already set */ return NL_FALSE; } return NL_TRUE; }
// copied from HawkNL sock.c and modified to not use nlStringToNetAddr static bool GetAddrFromNameAsync_Internal(const NLchar* name, NLaddress* address) { struct hostent *hostentry; NLushort port = 0; int pos; NLbyte temp[NL_MAX_STRING_LENGTH]; #ifdef _UNICODE /* convert from wide char string to multibyte char string */ (void)wcstombs(temp, (const NLchar *)name, NL_MAX_STRING_LENGTH); #else strncpy(temp, name, NL_MAX_STRING_LENGTH); #endif temp[NL_MAX_STRING_LENGTH - 1] = (NLbyte)'\0'; pos = (int)strcspn(temp, (const char *)":"); if(pos > 0) { NLbyte *p = &temp[pos+1]; temp[pos] = (NLbyte)'\0'; (void)sscanf(p, "%hu", &port); } hostentry = gethostbyname((const char *)temp); if(hostentry != NULL) { ((struct sockaddr_in *)address)->sin_family = AF_INET; ((struct sockaddr_in *)address)->sin_port = htons(port); ((struct sockaddr_in *)address)->sin_addr.s_addr = *(NLulong *)hostentry->h_addr_list[0]; address->valid = NL_TRUE; } else { ((struct sockaddr_in *)address)->sin_family = AF_INET; ((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_NONE; ((struct sockaddr_in *)address)->sin_port = 0; nlSetError(NL_SYSTEM_ERROR); return false; } return true; }
NL_EXP NLboolean NL_APIENTRY nlGroupAddSocket(NLint group, NLsocket socket) { NLint realgroup = group - NL_FIRST_GROUP; NLint i; nl_group_t *pgroup = NULL; if(groups == NULL) { nlSetError(NL_NO_NETWORK); return NL_FALSE; } if(realgroup < 0) { nlSetError(NL_INVALID_GROUP); return NL_FALSE; } /* add the socket to the group */ if(nlMutexLock(&grouplock) == NL_FALSE) { return NL_FALSE; } pgroup = groups[realgroup]; /* allocate more sockets as needed */ if(pgroup->numsockets == pgroup->maxsockets) { NLint oldmax = pgroup->maxsockets; NLint j; NLsocket *newsockets; if(oldmax == NL_MAX_GROUP_SOCKETS) { (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_GROUP_SOCKETS); return NL_FALSE; } pgroup->maxsockets *= 2; if(pgroup->maxsockets > NL_MAX_GROUP_SOCKETS) { pgroup->maxsockets = NL_MAX_GROUP_SOCKETS; } if((newsockets = (NLsocket *)realloc(pgroup->sockets, pgroup->maxsockets * sizeof(NLsocket *))) == NULL) { pgroup->maxsockets = oldmax; (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_MEMORY); return NL_FALSE; } /* set the new sockets to -1 */ for(j=oldmax;j<pgroup->maxsockets;j++) { newsockets[j] = -1; } pgroup->sockets = newsockets; } for(i=0;i<pgroup->maxsockets;i++) { if(pgroup->sockets[i] == -1) { pgroup->sockets[i] = socket; if(pgroup->fdset != NULL) { SOCKET realsock; /* make sure the socket is valid */ if(nlIsValidSocket(socket) == NL_FALSE) { (void)nlMutexUnlock(&grouplock); nlSetError(NL_INVALID_SOCKET); return NL_FALSE; } realsock = (SOCKET)nlSockets[socket]->realsocket; FD_SET(realsock, pgroup->fdset); if(pgroup->highest < realsock + 1) { pgroup->highest = realsock + 1; } } break; } } if(i == pgroup->maxsockets) { (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_GROUP_SOCKETS); return NL_FALSE; } pgroup->numsockets++; if(nlMutexUnlock(&grouplock) == NL_FALSE) { return NL_FALSE; } return NL_TRUE; }
NL_EXP NLint NL_APIENTRY nlGroupCreate(void) { NLint newgroup = NL_INVALID; nl_group_t *pgroup = NULL; if(groups == NULL) { nlSetError(NL_NO_NETWORK); return NL_INVALID; } if(nlMutexLock(&grouplock) == NL_FALSE) { return NL_INVALID; } if(nlnumgroups == NL_MAX_GROUPS) { (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_GROUPS); return NL_INVALID; } /* get a group number */ if(nlnumgroups == nlnextgroup) { /* do not increment nlnextgroup here, wait in case of malloc failure */ newgroup = nlnextgroup + 1; } else /* there is an open group slot somewhere below nlnextgroup */ { NLint i; for(i=0;i<nlnextgroup;i++) { if(groups[i] == NULL) { /* found an open group slot */ newgroup = i; } } /* let's check just to make sure we did find a group */ if(newgroup == NL_INVALID) { (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_MEMORY); return NL_INVALID; } } /* allocate the memory */ pgroup = (nl_group_t *)malloc((size_t)(sizeof(nl_group_t))); if(pgroup == NULL) { (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_MEMORY); return NL_INVALID; } else { NLint i; pgroup->sockets = (NLsocket *)malloc(NL_MIN_SOCKETS * sizeof(NLsocket *)); if(pgroup->sockets == NULL) { free(pgroup); (void)nlMutexUnlock(&grouplock); nlSetError(NL_OUT_OF_MEMORY); return NL_INVALID; } pgroup->maxsockets = NL_MIN_SOCKETS; /* fill with -1, since 0 is a valid socket number */ for(i=0;i<pgroup->maxsockets;i++) { pgroup->sockets[i] = -1; } pgroup->numsockets = 0; pgroup->fdset = NULL; pgroup->highest = 0; groups[newgroup] = pgroup; } nlnumgroups++; if(nlnumgroups == newgroup) { nlnextgroup = nlnumgroups; } if(nlMutexUnlock(&grouplock) == NL_FALSE) { return NL_INVALID; } /* adjust the group number */ return (newgroup + NL_FIRST_GROUP); }
void ResetSocketError() { if (!bNetworkInited) return; nlSetError(NL_NO_ERROR); }
NL_EXP NLboolean NL_APIENTRY nlCondWait(NLcond *cond, NLint timeout) { if(cond == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } if(*cond == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } if(timeout <= 0) { NLcond cv = *cond; #ifdef NL_WIN_THREADS DWORD result; result = WaitForMultipleObjects (2,cv->events_, FALSE, INFINITE); if(result == WAIT_FAILED) { nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } #else int result = 0; (void)pthread_mutex_lock((pthread_mutex_t *)&cv->mutex); result = pthread_cond_wait((pthread_cond_t *)&cv->cond, (pthread_mutex_t *)&cv->mutex); if(result != 0) { #ifdef WINDOWS_APP SetLastError((DWORD)result); #endif nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } (void)pthread_mutex_unlock((pthread_mutex_t *)&cv->mutex); #endif } else { NLcond cv = *cond; #ifdef NL_WIN_THREADS DWORD result; result = WaitForMultipleObjects (2, cv->events_, FALSE, (DWORD)timeout); if(result == WAIT_FAILED) { nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } else if(result == WAIT_TIMEOUT) { nlSetError(NL_TIMED_OUT); return NL_FALSE; } } #else int result = 0; struct timespec tv; NLtime t; NLlong ms; /* convert timeout to an absolute time */ (void)nlTime(&t); ms = t.mseconds + timeout; tv.tv_sec = t.seconds + (ms / 1000); tv.tv_nsec = (ms % 1000) * 1000; (void)pthread_mutex_lock((pthread_mutex_t *)&cv->mutex); result = pthread_cond_timedwait((pthread_cond_t *)&cv->cond, (pthread_mutex_t *)&cv->mutex, &tv); if(result == ETIMEDOUT) { nlSetError(NL_TIMED_OUT); (void)pthread_mutex_unlock((pthread_mutex_t *)&cv->mutex); return NL_FALSE; } else if(result != 0) { #ifdef WINDOWS_APP SetLastError((DWORD)result); #endif nlSetError(NL_SYSTEM_ERROR); return NL_FALSE; } (void)pthread_mutex_unlock((pthread_mutex_t *)&cv->mutex); }
NLint loopback_PollGroup(NLint group, NLenum name, NLsocket *sockets, NLint number, NLint timeout) { NLint count = 0; NLint numsockets = NL_MAX_GROUP_SOCKETS; NLsocket temp[NL_MAX_GROUP_SOCKETS]; nlGroupGetSockets(group, (NLint *)&temp, &numsockets); if(numsockets < 0) { /* any error is set by nlGroupGetSockets */ return NL_INVALID; } if(numsockets == 0) { return 0; } switch(name) { case NL_READ_STATUS: { NLint i = 0; while(numsockets-- > 0) { /* check for a packet */ nl_socket_t *sock; if(nlIsValidSocket(temp[i]) != NL_TRUE) { nlSetError(NL_INVALID_SOCKET); return NL_INVALID; } sock = nlSockets[temp[i]]; if(sock->inlen[sock->nextinused] > 0) { *sockets = temp[i]; sockets++; count++; if(count > number) { nlSetError(NL_BUFFER_SIZE); return NL_INVALID; } } i++; } } break; case NL_WRITE_STATUS: { NLint i = 0; while(numsockets-- > 0) { nl_socket_t *sock; if(nlIsValidSocket(temp[i]) != NL_TRUE) { nlSetError(NL_INVALID_SOCKET); return NL_INVALID; } sock = nlSockets[temp[i]]; /* check for a free packet if reliable and connected */ if((sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS) && (sock->connecting == NL_TRUE || sock->connected == NL_TRUE)) { nl_socket_t *othersock = nlSockets[sock->consock]; if(othersock->nextinfree == NL_INVALID) { continue; } } /* add the socket to the list */ *sockets = temp[i]; sockets++; count++; if(count > number) { nlSetError(NL_BUFFER_SIZE); return NL_INVALID; } i++; } } break; default: nlSetError(NL_INVALID_ENUM); return NL_INVALID; } return count; }
NLint loopback_Write(NLsocket socket, NLvoid *buffer, NLint nbytes) { nl_socket_t *sock = nlSockets[socket]; nl_socket_t *othersock; NLint s[NL_MAX_GROUP_SOCKETS]; NLint number = NL_MAX_GROUP_SOCKETS; NLint i; NLint count; switch (sock->type) { case NL_RELIABLE: case NL_UNRELIABLE: case NL_RELIABLE_PACKETS: default: { if(sock->connected == NL_TRUE) { /* check for broken connection */ if(sock->consock == NL_INVALID) { nlSetError(NL_CON_TERM); return NL_INVALID; } count = loopback_WritePacket(sock->consock, buffer, nbytes, sock->localport); } else if(sock->connecting == NL_TRUE) { nlSetError(NL_CON_PENDING); return NL_INVALID; } count = nbytes; nlGroupGetSockets(loopgroup, s, &number); for(i=0;i<number;i++) { if(nlIsValidSocket(s[i]) == NL_TRUE) { othersock = nlSockets[s[i]]; if(sock->remoteport == othersock->localport && othersock->connected == NL_FALSE && sock->type == othersock->type) { (void)loopback_WritePacket(s[i], buffer, nbytes, sock->localport); } } } } break; case NL_BROADCAST: { count = nbytes; nlGroupGetSockets(loopgroup, s, &number); for(i=0;i<number;i++) { if(nlIsValidSocket(s[i]) == NL_TRUE) { othersock = nlSockets[s[i]]; if(sock->localport == othersock->localport && sock->type == othersock->type) { (void)loopback_WritePacket(s[i], buffer, nbytes, sock->localport); } } } } } return count; }
// modified sock_Write of sock.c from HawkNL // returns true if socket is connected and data could be send static bool nlUpdateState(NLsocket socket) { if(nlIsValidSocket(socket) != NL_TRUE) return false; struct Unlocker { NLsocket socket; ~Unlocker() { nlUnlockSocket(socket, NL_BOTH); } Unlocker(NLsocket s) : socket(s) {} }; if(nlLockSocket(socket, NL_BOTH) == NL_FALSE) { return false; } Unlocker unlocker(socket); nl_socket_t *sock = nlSockets[socket]; NLint count = 0; if((sock->type == NL_RELIABLE) || (sock->type == NL_RELIABLE_PACKETS)) /* TCP */ { if(sock->connecting == NL_TRUE) { fd_set fdset; struct timeval t = {0,0}; int serrval = -1; socklen_t serrsize = (socklen_t)sizeof(serrval); FD_ZERO(&fdset); FD_SET((SOCKET)sock->realsocket, &fdset); if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1) { /* Check the socket status */ (void)getsockopt( sock->realsocket, SOL_SOCKET, SO_ERROR, (char *)&serrval, &serrsize ); if(serrval != 0) { if(serrval == ECONNREFUSED) { nlSetError(NL_CON_REFUSED); } else if(serrval == EINPROGRESS || serrval == EWOULDBLOCK) { nlSetError(NL_CON_PENDING); } return false; } /* the connect has completed */ sock->connected = NL_TRUE; sock->connecting = NL_FALSE; } else { /* check for a failed connect */ FD_ZERO(&fdset); FD_SET((SOCKET)sock->realsocket, &fdset); if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1) { nlSetError(NL_CON_REFUSED); } else { nlSetError(NL_CON_PENDING); } return false; } } /* check for reliable packets */ if(sock->type == NL_RELIABLE_PACKETS) { return true; } return true; } else /* unconnected UDP */ { /* check for a non-blocking connection pending */ if(sock->connecting == NL_TRUE) { nlSetError(NL_CON_PENDING); return false; } /* check for a connection error */ if(sock->conerror == NL_TRUE) { nlSetError(NL_CON_REFUSED); return false; } if(sock->type == NL_BROADCAST) { ((struct sockaddr_in *)&sock->addressin)->sin_addr.s_addr = INADDR_BROADCAST; } if(sock->type == NL_UDP_MULTICAST) { return true; } else if(sock->connected == NL_TRUE) { return true; } else { return true; } } if(count == SOCKET_ERROR) { return false; } return false; }
NL_EXP NLboolean NL_APIENTRY nlGroupDeleteSocket(NLint group, NLsocket socket) { NLint realgroup = group - NL_FIRST_GROUP; NLint i; nl_group_t *pgroup = NULL; if(groups == NULL) { nlSetError(NL_NO_NETWORK); return NL_FALSE; } if(realgroup < 0) { nlSetError(NL_INVALID_GROUP); return NL_FALSE; } /* delete the socket from the group */ if(nlMutexLock(&grouplock) == NL_FALSE) { return NL_FALSE; } pgroup = groups[realgroup]; for(i=0;i<pgroup->numsockets;i++) { /* check for match */ if(pgroup->sockets[i] == socket) break; } if(i == pgroup->numsockets) { /* did not find the socket */ (void)nlMutexUnlock(&grouplock); nlSetError(NL_SOCKET_NOT_FOUND); return NL_FALSE; } /* now pgroup[i] points to the socket to delete */ /* shift all other sockets down to close the gap */ i++; for(;i<pgroup->maxsockets;i++) { pgroup->sockets[i - 1] = pgroup->sockets[i]; /* check for end of list */ if(pgroup->sockets[i] == -1) break; } pgroup->numsockets--; if(pgroup->fdset != NULL) { /* make sure the socket is valid */ if(nlIsValidSocket(socket) == NL_TRUE) { SOCKET realsock; realsock = (SOCKET)nlSockets[socket]->realsocket; FD_CLR(realsock, pgroup->fdset); } else { /* the socket was already closed */ /* free the fdset so that it can be rebuilt */ free(pgroup->fdset); pgroup->fdset = NULL; (void)nlMutexUnlock(&grouplock); nlSetError(NL_INVALID_SOCKET); return NL_FALSE; } } if(nlMutexUnlock(&grouplock) == NL_FALSE) { return NL_FALSE; } return NL_TRUE; }
NLsocket loopback_Open(NLushort port, NLenum type) { nl_socket_t *newsock; NLsocket newsocket; NLint i; NLushort lport; switch (type) { case NL_RELIABLE: case NL_UNRELIABLE: case NL_RELIABLE_PACKETS: case NL_BROADCAST: break; default: nlSetError(NL_INVALID_ENUM); return NL_INVALID; } lport = loopback_TryPort(port, type); if(lport == 0) { nlSetError(NL_INVALID_PORT); return NL_INVALID; } newsocket = nlGetNewSocket(); if(newsocket == NL_INVALID) { return NL_INVALID; } newsock = nlSockets[newsocket]; newsock->type = type; newsock->localport = lport; if(type == NL_BROADCAST) { newsock->remoteport = lport; } for(i=0;i<NL_NUM_PACKETS;i++) { NLboolean err = NL_FALSE; /* malloc the max packet length plus two bytes for the port number */ if((newsock->inpacket[i] = (NLbyte *)malloc((size_t)(NL_MAX_PACKET_LENGTH + 2))) == NULL) { nlSetError(NL_OUT_OF_MEMORY); err = NL_TRUE; } if(err == NL_TRUE) { while(i-- > 0) { free(newsock->inpacket[i]); } sock_Close(newsocket); return NL_INVALID; } } (void)nlGroupAddSocket(loopgroup, newsocket); return newsocket; }
static NLint loopback_WritePacket(NLsocket to, NLvoid *buffer, NLint nbytes, NLushort fromport) { nl_socket_t *sock = nlSockets[to]; NLint i, j; NLint c = 0; /* check the packet size */ if(nbytes > NL_MAX_PACKET_LENGTH) { nlSetError(NL_PACKET_SIZE); return NL_INVALID; } nlLockSocket(to, NL_READ); /* make sure we have an empty packet buffer */ if(sock->nextinfree == NL_INVALID) { /* all buffers were filled by last write */ /* check to see if any were emptied by a read */ i = NL_NUM_PACKETS; j = sock->nextinused; while(i-- > 0) { if(sock->inlen[j] == 0) { /* found the first free */ sock->nextinfree = j; break; } j++; if(j >= NL_NUM_PACKETS) { j = 0; } } if(sock->nextinfree == NL_INVALID) { nlUnlockSocket(to, NL_READ); /* none are free */ if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS) { return 0; } else { /* silently fail */ return nbytes; } } } /* write the port number */ writeShort(sock->inpacket[sock->nextinfree], c, fromport); /* copy the packet buffer */ memcpy(sock->inpacket[sock->nextinfree] + 2, buffer, (size_t)nbytes); sock->inlen[sock->nextinfree] = nbytes; sock->nextinfree++; if(sock->nextinfree >= NL_NUM_PACKETS) { sock->nextinfree = 0; } /* check for full packet buffers */ if(sock->inlen[sock->nextinfree] != 0) { sock->nextinfree = NL_INVALID; } nlUnlockSocket(to, NL_READ); return nbytes; }
NL_EXP NLboolean NL_APIENTRY nlTime(NLtime *t) { #ifdef WINDOWS_APP static NLboolean needinit = NL_TRUE; static NLboolean haspcounter = NL_FALSE; static LARGE_INTEGER freq; static LARGE_INTEGER lastcount; static NLtime currenttime; if(t == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } if(needinit == NL_TRUE) { if(QueryPerformanceFrequency(&freq) != 0) { if(QueryPerformanceCounter(&lastcount) != 0) { /* get the current time */ struct mytimeb tb; myftime(&tb); currenttime.seconds = (NLlong)(tb.time); currenttime.useconds = (NLlong)(tb.millitm * 1000); haspcounter = NL_TRUE; } } needinit = NL_FALSE; } if(haspcounter == NL_TRUE) { LARGE_INTEGER currentcount; LARGE_INTEGER diffcount; (void)QueryPerformanceCounter(¤tcount); diffcount.QuadPart = currentcount.QuadPart - lastcount.QuadPart; lastcount.QuadPart = currentcount.QuadPart; while(diffcount.QuadPart >= freq.QuadPart) { diffcount.QuadPart -= freq.QuadPart; currenttime.seconds++; } currenttime.useconds += (NLlong)(diffcount.QuadPart * 1000000 / freq.QuadPart); if(currenttime.useconds >= 1000000) { currenttime.useconds -= 1000000; currenttime.seconds++; } t->seconds = currenttime.seconds; t->mseconds = currenttime.useconds / 1000; t->useconds = currenttime.useconds; } else { /* fall back to myftime */ struct mytimeb tb; myftime(&tb); t->seconds = (NLlong)(tb.time); t->mseconds = (NLlong)(tb.millitm); t->useconds = (NLlong)(tb.millitm * 1000); } #else /* !WINDOWS_APP */ struct timeval tv; if(t == NULL) { nlSetError(NL_NULL_POINTER); return NL_FALSE; } gettimeofday(&tv, NULL); t->seconds = (NLlong)(tv.tv_sec); t->mseconds = (NLlong)(tv.tv_usec / 1000); t->useconds = (NLlong)(tv.tv_usec); #endif /* !WINDOWS_APP */ return NL_TRUE; }