static void nlPrepareClose(NLsocket socket) { if(nlIsValidSocket(socket) != NL_TRUE) return; struct Unlocker { NLsocket socket; ~Unlocker() { nlUnlockSocket(socket, NL_BOTH); } Unlocker(NLsocket s) : socket(s) {} }; if(nlLockSocket(socket, NL_BOTH) == NL_FALSE) { return; } Unlocker unlocker(socket); // code copied&modified from sock_Close // The advantage we have here is that we don't lock the whole socket array. // nlClose is doing this, so if we would hang in nlClose, we block the // *whole* HawkNL system (or at least actions like opening new sockets etc.)! nl_socket_t *sock = nlSockets[socket]; struct ip_mreq mreq; if(sock->type == NL_UDP_MULTICAST) { /* leave the multicast group */ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)&sock->addressout)->sin_addr.s_addr; mreq.imr_interface.s_addr = INADDR_ANY; //bindaddress; (void)setsockopt((SOCKET)sock->realsocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, (int)sizeof(mreq)); } if(sock->type == NL_RELIABLE_PACKETS) { /* check for unsent data */ if(sock->sendlen > 0) { int tries = 200; /* 200 * 50 ms = up to a 10 second delay to allow data to be sent */ while(tries-- > 0 && sock->sendlen > 0) { SDL_Delay(50); } } // oh just f**k it sock->sendlen = 0; } if((sock->type == NL_RELIABLE_PACKETS || sock->type == NL_RELIABLE) && sock->listen == NL_FALSE) { struct linger l = {1, 10}; (void)setsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_LINGER, (const char *)&l, (int)sizeof(l)); } (void)closesocket((SOCKET)sock->realsocket); }
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; }
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; }
// 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; }