static void connectCallback(NetDescriptor *nd) { // Called by the NetManager when a connection has been established. ConnectState *connectState = (ConnectState *) NetDescriptor_getExtra(nd); int err; if (connectState->alarm != NULL) { Alarm_remove(connectState->alarm); connectState->alarm = NULL; } if (connectState->state == Connect_closed) { // The connection attempt has been aborted. #ifdef DEBUG log_add(log_Debug, "Connection attempt was aborted."); #endif ConnectState_decRef(connectState); return; } if (Socket_getError(NetDescriptor_getSocket(nd), &err) == -1) { log_add(log_Fatal, "Socket_getError() failed: %s.", strerror(errno)); explode(); } if (err != 0) { #ifdef DEBUG log_add(log_Debug, "connect() failed: %s.", strerror(err)); #endif NetDescriptor_close(nd); connectState->nd = NULL; connectState->infoPtr = connectState->infoPtr->ai_next; connectHostNext(connectState); return; } #ifdef DEBUG log_add(log_Debug, "Connection established."); #endif // Notify the higher layer. connectState->nd = NULL; // The callback function takes over ownership of the // NetDescriptor. NetDescriptor_setWriteCallback(nd, NULL); // Note that connectState->info and connectState->infoPtr are cleaned up // when ConnectState_close() is called by the callback function. ConnectState_incRef(connectState); doConnectCallback(connectState, nd, connectState->infoPtr->ai_addr, connectState->infoPtr->ai_addrlen); { // The callback called should release the last reference to // the connectState, by calling ConnectState_close(). bool released = ConnectState_decRef(connectState); assert(released); (void) released; // In case assert() evaluates to nothing. } }
static void connectTimeoutCallback(ConnectState *connectState) { connectState->alarm = NULL; NetDescriptor_close(connectState->nd); connectState->nd = NULL; connectState->infoPtr = connectState->infoPtr->ai_next; connectHostNext(connectState); }
// Close and release a NetConnection. void NetConnection_close(NetConnection *conn) { if (conn->nd != NULL) { NetDescriptor_setCloseCallback(conn->nd, NULL); // We're not interested in the close callback of the // NetDescriptor anymore. NetDescriptor_close(conn->nd); // This would queue the close callback. conn->nd = NULL; } if (!conn->stateFlags.disconnected) NetConnection_doClose(conn); NetConnection_delete(conn); }
// Decrements ref count byh 1 void ListenState_close(ListenState *listenState) { if (listenState->resolveState != NULL) { Resolve_close(listenState->resolveState); listenState->resolveState = NULL; } if (listenState->nds != NULL) { while (listenState->numNd > 0) { listenState->numNd--; NetDescriptor_close(listenState->nds[listenState->numNd]); } free(listenState->nds); listenState->nds = NULL; } listenState->state = Listen_closed; ListenState_decRef(listenState); }
// decrements ref count by 1 void ConnectState_close(ConnectState *connectState) { if (connectState->resolveState != NULL) { Resolve_close(connectState->resolveState); connectState->resolveState = NULL; } if (connectState->alarm != NULL) { Alarm_remove(connectState->alarm); connectState->alarm = NULL; } if (connectState->nd != NULL) { NetDescriptor_close(connectState->nd); connectState->nd = NULL; } if (connectState->info != NULL) { freeaddrinfo(connectState->info); connectState->info = NULL; connectState->infoPtr = NULL; } connectState->state = Connect_closed; ConnectState_decRef(connectState); }
void dataReadyCallback(NetDescriptor *nd) { NetConnection *conn = (NetConnection *) NetDescriptor_getExtra(nd); Socket *socket = NetDescriptor_getSocket(nd); for (;;) { ssize_t numRead; ssize_t numProcessed; numRead = Socket_recv(socket, conn->readEnd, NETPLAY_READBUFSIZE - (conn->readEnd - conn->readBuf), 0); if (numRead == 0) { // Other side closed the connection. NetDescriptor_close(nd); return; } if (numRead == -1) { switch (errno) { case EAGAIN: // No more data for now. return; case EINTR: // System call was interrupted. Retry. continue; default: { int savedErrno = errno; log_add(log_Error, "recv() failed: %s.\n", strerror(errno)); NetConnection_doErrorCallback(conn, savedErrno); NetDescriptor_close(nd); return; } } } conn->readEnd += numRead; numProcessed = dataReceivedMulti(conn, conn->readBuf, conn->readEnd - conn->readBuf); if (numProcessed == -1) { // An error occured during processing. // errno is set. NetConnection_doErrorCallback(conn, errno); NetDescriptor_close(nd); return; } if (numProcessed == 0) { // No packets could be processed. This means we need to receive // more data first. return; } // Some packets have been processed. // We more any rest to the front of the buffer, to make room // for more data. // A cyclic buffer would obviate the need for this move, // but it would complicate things a lot. memmove(conn->readBuf, conn->readBuf + numProcessed, (conn->readEnd - conn->readBuf) - numProcessed); conn->readEnd -= numProcessed; } }
static inline int NetManager_processEvent(size_t index) { WSANETWORKEVENTS networkEvents; int enumRes; enumRes = WSAEnumNetworkEvents(netDescriptors[index]->socket->sock, events[index], &networkEvents); if (enumRes == SOCKET_ERROR) { errno = getWinsockErrno(); return -1; } if (networkEvents.lNetworkEvents & FD_READ) { bool closed; if (networkEvents.iErrorCode[FD_READ_BIT] != 0) { // No special handling is required; the callback function // will try to do a recv() and will get the error then. } closed = NetManager_doReadCallback(netDescriptors[index]); if (closed) goto closed; } if (networkEvents.lNetworkEvents & FD_WRITE) { bool closed; if (networkEvents.iErrorCode[FD_WRITE_BIT] != 0) { // No special handling is required; the callback function // will try to do a send() and will get the error then. } closed = NetManager_doWriteCallback(netDescriptors[index]); if (closed) goto closed; } if (networkEvents.lNetworkEvents & FD_OOB) { bool closed; if (networkEvents.iErrorCode[FD_OOB_BIT] != 0) { // No special handling is required; the callback function // will get the error then when it tries to do a recv(). } closed = NetManager_doExceptionCallback(netDescriptors[index]); if (closed) goto closed; } if (networkEvents.lNetworkEvents & FD_ACCEPT) { // There is no specific accept callback (because the BSD sockets // don't work with specific notification for accept); we use // the read callback instead. bool closed; if (networkEvents.iErrorCode[FD_READ_BIT] != 0) { // No special handling is required; the callback function // will try to do an accept() and will get the error then. } closed = NetManager_doReadCallback(netDescriptors[index]); if (closed) goto closed; } #if 0 // No need for this. Windows also sets FD_WRITE in this case, and // writability is what we check for anyhow. if (networkEvents.lNetworkEvents & FD_CONNECT) { // There is no specific connect callback (because the BSD sockets // don't work with specific notification for connect); we use // the write callback instead. bool closed; if (networkEvents.iErrorCode[FD_WRITE_BIT] != 0) { // No special handling is required; the callback function // should do getsockopt() with SO_ERROR to get the error. } closed = NetManager_doWriteCallback(netDescriptors[index]); if (closed) goto closed; } #endif if (networkEvents.lNetworkEvents & FD_CLOSE) { // The close event is handled last, in case there was still // data in the buffers which could be processed. NetDescriptor_close(netDescriptors[index]); goto closed; } closed: /* No special actions required for now. */ return 0; }