// Called when the NetDescriptor is shut down. static void closeCallback(NetDescriptor *nd) { NetConnection *conn = (NetConnection *) NetDescriptor_getExtra(nd); if (conn == NULL) return; conn->nd = NULL; NetConnection_doClose(conn); }
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.\n"); #endif ConnectState_decRef(connectState); return; } if (Socket_getError(NetDescriptor_getSocket(nd), &err) == -1) { log_add(log_Fatal, "Socket_getError() failed: %s.\n", strerror(errno)); explode(); } if (err != 0) { #ifdef DEBUG log_add(log_Debug, "connect() failed: %s.\n", strerror(err)); #endif NetDescriptor_close(nd); connectState->nd = NULL; connectState->infoPtr = connectState->infoPtr->ai_next; connectHostNext(connectState); return; } // 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. } }
// Called when select() has indicated readability on a listening socket, // i.e. when a connection is in the queue. static void acceptCallback(NetDescriptor *nd) { ListenState *listenState = (ListenState *) NetDescriptor_getExtra(nd); acceptSingleConnection(listenState, nd); }
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; } }