/* Remove socket */ int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t* fd) { tnet_transport_t *transport = (tnet_transport_t*)handle; transport_context_t *context; int ret = -1; tsk_size_t i; tsk_bool_t found = tsk_false; if (!transport || !(context = (transport_context_t*)transport->context)) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } for (i = 0; i < context->count; i++) { if (context->sockets[i]->fd == *fd) { removeSocket((int)i, context); found = tsk_true; TSK_RUNNABLE_ENQUEUE(transport, event_removed, transport->callback_data, *fd); *fd = TNET_INVALID_FD; break; } } if (found) { /* Signal */ if (WSASetEvent(context->events[0])) { TSK_DEBUG_INFO("Old socket removed from the network transport."); return 0; } } // ... return -1; }
void __CFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) { // Extract the context tnet_transport_t *transport = (tnet_transport_t *) clientCallBackInfo; transport_context_t *context = transport->context; /* lock context */ tsk_safeobj_lock(context); // Extract the native socket CFDataRef data = CFWriteStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle); CFSocketNativeHandle fd; CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd); CFRelease(data); transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd); switch(eventType) { case kCFStreamEventOpenCompleted: { TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventOpenCompleted"); if (TNET_SOCKET_TYPE_IS_SECURE(sock->type)) { #if !TARGET_OS_IPHONE SSLContextRef sslContext = NULL; data = CFWriteStreamCopyProperty(stream, kCFStreamPropertySocketSSLContext); CFDataGetBytes(data, CFRangeMake(0, sizeof(SSLContextRef)), (UInt8*) &sslContext); CFRelease(data); // TODO: Set the client certificates #endif } break; } case kCFStreamEventEndEncountered: case kCFStreamEventErrorOccurred: { // Get the error code CFErrorRef error = CFWriteStreamCopyError(stream); CFIndex index = CFErrorGetCode(error); CFRelease(error); TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> Error %lu", index); TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, sock->fd); removeSocket(sock, context); break; } default: { // Not Implemented assert(42 == 0); break; } } /* unlock context */ tsk_safeobj_unlock(context); }
/* Remove socket */ int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t *pfd) { tnet_transport_t *transport = (tnet_transport_t*)handle; transport_context_t *context; int ret = -1; tsk_size_t i; tsk_bool_t found = tsk_false; tnet_fd_t fd = *pfd; TSK_DEBUG_INFO("Removing socket %d", fd); if(!transport) { TSK_DEBUG_ERROR("Invalid server handle."); return ret; } if(!(context = (transport_context_t*)transport->context)) { TSK_DEBUG_ERROR("Invalid context."); return -2; } tsk_safeobj_lock(context); for(i=0; i<context->count; i++) { if(context->sockets[i]->fd == fd) { tsk_bool_t self_ref = (&context->sockets[i]->fd == pfd); removeSocket(i, context); // sockets[i] will be destroyed found = tsk_true; TSK_RUNNABLE_ENQUEUE(transport, event_removed, transport->callback_data, fd); if(!self_ref) { // if self_ref then, pfd no longer valid after removeSocket() *pfd = TNET_INVALID_FD; } break; } } tsk_safeobj_unlock(context); if(found) { /* Signal */ static char c = '\0'; ret = write(context->pipeW, &c, 1); return (ret > 0 ? 0 : ret); } // ... return -1; }
void __CFSocketCallBack(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) { // Extract the context tnet_transport_t *transport = (tnet_transport_t *) info; transport_context_t *context = transport->context; // Extract the native socket int fd = CFSocketGetNative(s); transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd); /* lock context */ tsk_safeobj_lock(context); switch (callbackType) { case kCFSocketReadCallBack: { int ret; tsk_size_t len = 0; void* buffer = 0; tnet_transport_event_t* e; if (tnet_ioctlt(sock->fd, FIONREAD, &len) < 0) { TNET_PRINT_LAST_ERROR("IOCTLT FAILED."); break; } if (!len) { TSK_DEBUG_WARN("IOCTLT returned zero."); TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, sock->fd); removeSocket(sock, context); break; } if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) { TSK_DEBUG_ERROR("TSK_CALLOC FAILED."); break; } if ((ret = tnet_sockfd_recv(sock->fd, buffer, len, 0)) < 0) { TSK_FREE(buffer); removeSocket(sock, context); TNET_PRINT_LAST_ERROR("recv have failed."); break; } else if ((len != (tsk_size_t)ret) && len) { // useless test ? len = (tsk_size_t)ret; // buffer = tsk_realloc(buffer, len); } TSK_DEBUG_INFO("__CFSocketCallBack -> %u bytes read", len); e = tnet_transport_event_create(event_data, transport->callback_data, sock->fd); e->data = buffer; e->size = len; TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(transport), e); break; } case kCFSocketAcceptCallBack: case kCFSocketConnectCallBack: case kCFSocketDataCallBack: case kCFSocketWriteCallBack: default: { // Not Implemented assert(42 == 0); break; } } /* unlock context */ tsk_safeobj_unlock(context); }
void __CFReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) { // Extract the context tnet_transport_t *transport = (tnet_transport_t *) clientCallBackInfo; transport_context_t *context = transport->context; /* lock context */ tsk_safeobj_lock(context); // Extract the native socket CFDataRef data = CFReadStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle); CFSocketNativeHandle fd; CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd); CFRelease(data); transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd); switch(eventType) { case kCFStreamEventOpenCompleted: { TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> kCFStreamEventOpenCompleted"); break; } case kCFStreamEventHasBytesAvailable: { tsk_size_t len = 0; void *buffer = 0; tnet_transport_event_t* e; // Allocate a standard buffer len = TNET_BUFFER_SIZE; if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) { TSK_DEBUG_ERROR("TSK_CALLOC FAILED."); break; } // Process to read data CFIndex index = CFReadStreamRead(stream, buffer, TNET_BUFFER_SIZE); len = index; TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> %u bytes read", len); e = tnet_transport_event_create(event_data, transport->callback_data, sock->fd); e->data = buffer; e->size = len; TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(transport), e); break; } case kCFStreamEventEndEncountered: case kCFStreamEventErrorOccurred: { // Get the error code CFErrorRef error = CFReadStreamCopyError(stream); CFIndex index = CFErrorGetCode(error); CFRelease(error); TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> Error %lu", index); TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, sock->fd); removeSocket(sock, context); break; } default: { // Not Implemented assert(42 == 0); break; } } /* unlock context */ tsk_safeobj_unlock(context); }
/*=== Main thread */ void *tnet_transport_mainthread(void *param) { tnet_transport_t *transport = param; transport_context_t *context = transport->context; int ret, status; tsk_size_t i; tsk_bool_t is_stream; tnet_fd_t fd; struct sockaddr_storage remote_addr = {0}; transport_socket_xt* active_socket; /* check whether the transport is already prepared */ if(!transport->prepared) { TSK_DEBUG_ERROR("Transport must be prepared before strating."); goto bail; } is_stream = TNET_SOCKET_TYPE_IS_STREAM(transport->master->type); TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} using master fd {%d} with type {%d} with max_fds {%lu}...", transport->description, transport->master->ip, transport->master->port, transport->master->fd, transport->master->type, sizeof(context->ufds)/sizeof(context->ufds[0])); while(TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started) { context->polling = tsk_true; ret = tnet_poll(context->ufds, context->count, -1); context->polling = tsk_false; if(ret < 0) { TNET_PRINT_LAST_ERROR("poll() have failed."); goto bail; } if(!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started) { TSK_DEBUG_INFO("Stopping [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type); goto bail; } /* lock context */ tsk_safeobj_lock(context); /* == == */ for(i=0; i<context->count; i++) { if(!context->ufds[i].revents) { continue; } // TSK_DEBUG_INFO("REVENTS(i=%d) = %d", i, context->ufds[i].revents); if(context->ufds[i].fd == context->pipeR) { TSK_DEBUG_INFO("PipeR event = %d", context->ufds[i].revents); if(context->ufds[i].revents & TNET_POLLIN) { static char __buffer[1024]; if(read(context->pipeR, __buffer, sizeof(__buffer)) < 0) { TNET_PRINT_LAST_ERROR("Failed to read from the Pipe"); } } else if(context->ufds[i].revents & TNET_POLLHUP) { TNET_PRINT_LAST_ERROR("Pipe Error"); goto bail; } context->ufds[i].revents = 0; continue; } /* Get active event and socket */ active_socket = context->sockets[i]; /*================== TNET_POLLHUP ==================*/ if(context->ufds[i].revents & (TNET_POLLHUP)) { if(context->ufds[i].revents & TNET_POLLOUT) { TSK_DEBUG_INFO("POLLOUT and POLLHUP are exclusive"); } else { fd = active_socket->fd; TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLHUP(%d)", transport->description, fd); tnet_transport_remove_socket(transport, &active_socket->fd); TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd); continue; } } /*================== TNET_POLLERR ==================*/ if(context->ufds[i].revents & (TNET_POLLERR)) { fd = active_socket->fd; TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLERR(%d)", transport->description, fd); tnet_transport_remove_socket(transport, &active_socket->fd); TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd); continue; } /*================== TNET_POLLNVAL ==================*/ if(context->ufds[i].revents & (TNET_POLLNVAL)) { fd = active_socket->fd; TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLNVAL(%d)", transport->description, fd); tnet_transport_remove_socket(transport, &active_socket->fd); TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd); continue; } /*================== POLLIN ==================*/ if(context->ufds[i].revents & TNET_POLLIN) { tsk_size_t len = 0; void* buffer = tsk_null; tnet_transport_event_t* e; // TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLIN(%d)", transport->description, active_socket->fd); /* check whether the socket is paused or not */ if(active_socket->paused) { TSK_DEBUG_INFO("Socket is paused"); goto TNET_POLLIN_DONE; } /* Retrieve the amount of pending data. * IMPORTANT: If you are using Symbian please update your SDK to the latest build (August 2009) to have 'FIONREAD'. * This apply whatever you are using the 3rd or 5th edition. * Download link: http://wiki.forum.nokia.com/index.php/Open_C/C%2B%2B_Release_History */ ret = tnet_ioctlt(active_socket->fd, FIONREAD, &len); if((ret < 0 || !len) && is_stream) { /* It's probably an incoming connection --> try to accept() it */ int listening = 0, remove_socket = 0; socklen_t socklen = sizeof(listening); TSK_DEBUG_INFO("ioctlt(%d), len=%u returned zero or failed", active_socket->fd, (unsigned)len); // check if socket is listening if(getsockopt(active_socket->fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &socklen) != 0) { #if defined(BSD) /* old FreeBSD versions (and OSX up to Lion) do not support SO_ACCEPTCONN */ listening = 1; #else TNET_PRINT_LAST_ERROR("getsockopt(SO_ACCEPTCONN, %d) failed\n", active_socket->fd); /* not socket accepted -> no socket to remove */ goto TNET_POLLIN_DONE; #endif } if (listening) { if((fd = accept(active_socket->fd, tsk_null, tsk_null)) != TNET_INVALID_SOCKET) { TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT(fd=%d)", transport->description, fd); addSocket(fd, transport->master->type, transport, tsk_true, tsk_false, tsk_null); TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd); if(active_socket->tlshandle) { transport_socket_xt* tls_socket; if((tls_socket = getSocket(context, fd))) { if(tnet_tls_socket_accept(tls_socket->tlshandle) != 0) { TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd); tnet_transport_remove_socket(transport, &fd); TNET_PRINT_LAST_ERROR("SSL_accept() failed"); continue; } } } } else { TNET_PRINT_LAST_ERROR("accept(%d) failed", active_socket->fd); remove_socket = 1; } } else { TSK_DEBUG_INFO("Closing socket with fd = %d because ioctlt() returned zero or failed", active_socket->fd); remove_socket = 1; } if(remove_socket) { fd = active_socket->fd; tnet_transport_remove_socket(transport, &active_socket->fd); TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd); continue; } goto TNET_POLLIN_DONE; } if(len <= 0) { #if defined(__ANDROID__) || defined(ANDROID) // workaround for indoona OSX which sends bodiless UDP packets // vand Android requires to call recv() even if len is equal to zero if(len == 0 && ret == 0) { static char __fake_buff[1]; ret = recv(active_socket->fd, __fake_buff, len, 0); } #endif goto TNET_POLLIN_DONE; } if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) { TSK_DEBUG_ERROR("TSK_CALLOC FAILED"); goto TNET_POLLIN_DONE; } // Retrieve the remote address if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) { ret = tnet_getpeername(active_socket->fd, &remote_addr); } // Receive the waiting data if (active_socket->tlshandle) { int isEncrypted; tsk_size_t tlslen = len; if ((ret = tnet_tls_socket_recv(active_socket->tlshandle, &buffer, &tlslen, &isEncrypted)) == 0) { if (isEncrypted) { TSK_FREE(buffer); goto TNET_POLLIN_DONE; } if (ret == 0) { len = ret = tlslen; } } } else { if (is_stream) { ret = tnet_sockfd_recv(active_socket->fd, buffer, len, 0); } else { ret = tnet_sockfd_recvfrom(active_socket->fd, buffer, len, 0, (struct sockaddr*)&remote_addr); } } if(ret < 0) { TSK_FREE(buffer); status = tnet_geterrno(); // do not remove the socket for i/o pending errors if (status == TNET_ERROR_WOULDBLOCK || status == TNET_ERROR_INPROGRESS || status == TNET_ERROR_EAGAIN) { TSK_DEBUG_WARN("recv returned error code:%d", status); } else { TNET_PRINT_LAST_ERROR("recv/recvfrom have failed"); removeSocket(i, context); } goto TNET_POLLIN_DONE; } if((len != (tsk_size_t)ret) && len) { len = (tsk_size_t)ret; // buffer = tsk_realloc(buffer, len); } if(len > 0) { transport->bytes_in += len; e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd); e->data = buffer, buffer = tsk_null; e->size = len; e->remote_addr = remote_addr; TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e); } TSK_FREE(buffer); TNET_POLLIN_DONE: /*context->ufds[i].revents &= ~TNET_POLLIN*/ ; } /*================== TNET_POLLOUT ==================*/ if(context->ufds[i].revents & TNET_POLLOUT) { TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLOUT", transport->description); if(!active_socket->connected) { active_socket->connected = tsk_true; TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd); } //else{ context->ufds[i].events &= ~TNET_POLLOUT; //} } /*================== TNET_POLLPRI ==================*/ if(context->ufds[i].revents & TNET_POLLPRI) { TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLPRI", transport->description); } context->ufds[i].revents = 0; }/* for */ done: /* unlock context */ tsk_safeobj_unlock(context); } /* while */ bail: TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d}", transport->description, transport->master->ip, transport->master->port); return 0; }
/*=== Main thread */ void* TSK_STDCALL tnet_transport_mainthread(void *param) { tnet_transport_t *transport = (tnet_transport_t*)param; transport_context_t *context = (transport_context_t*)transport->context; DWORD evt; WSANETWORKEVENTS networkEvents; DWORD flags = 0; int ret; struct sockaddr_storage remote_addr = { 0 }; WSAEVENT active_event; transport_socket_xt* active_socket; int index; TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type); while (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started) { /* Wait for multiple events */ if ((evt = WSAWaitForMultipleEvents((DWORD)context->count, context->events, FALSE, WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED) { TNET_PRINT_LAST_ERROR("WSAWaitForMultipleEvents have failed."); goto bail; } if (!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started) { goto bail; } /* lock context */ tsk_safeobj_lock(context); /* Get active event and socket */ index = (evt - WSA_WAIT_EVENT_0); active_event = context->events[index]; if (!(active_socket = context->sockets[index])) { goto done; } /* Get the network events flags */ if (WSAEnumNetworkEvents(active_socket->fd, active_event, &networkEvents) == SOCKET_ERROR) { TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd); TNET_PRINT_LAST_ERROR("WSAEnumNetworkEvents have failed."); tsk_safeobj_unlock(context); goto bail; } /*================== FD_ACCEPT ==================*/ if (networkEvents.lNetworkEvents & FD_ACCEPT) { tnet_fd_t fd; TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT", transport->description); if (networkEvents.iErrorCode[FD_ACCEPT_BIT]) { TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd); TNET_PRINT_LAST_ERROR("ACCEPT FAILED."); goto done; } /* Accept the connection */ if ((fd = (tnet_fd_t)WSAAccept(active_socket->fd, NULL, NULL, AcceptCondFunc, (DWORD_PTR)context)) != INVALID_SOCKET) { /* Add the new fd to the server context */ addSocket(fd, transport->master->type, transport, tsk_true, tsk_false, tsk_null); if (active_socket->tlshandle) { transport_socket_xt* tls_socket; if ((tls_socket = getSocket(context, fd))) { if (tnet_tls_socket_accept(tls_socket->tlshandle)) { tnet_transport_remove_socket(transport, &fd); TNET_PRINT_LAST_ERROR("SSL_accept() failed"); goto done; } } } if (WSAEventSelect(fd, context->events[context->count - 1], FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR) { tnet_transport_remove_socket(transport, &fd); TNET_PRINT_LAST_ERROR("WSAEventSelect() have failed."); goto done; } TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd); } else { TNET_PRINT_LAST_ERROR("ACCEPT FAILED."); goto done; } } /*================== FD_CONNECT ==================*/ if (networkEvents.lNetworkEvents & FD_CONNECT) { TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CONNECT", transport->description); if (networkEvents.iErrorCode[FD_CONNECT_BIT]) { tnet_fd_t fd = active_socket->fd; TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd); tnet_transport_remove_socket(transport, &fd); TNET_PRINT_LAST_ERROR("CONNECT FAILED."); goto done; } else { TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd); active_socket->connected = 1; } } /*================== FD_READ ==================*/ if (networkEvents.lNetworkEvents & FD_READ) { DWORD readCount = 0; WSABUF wsaBuffer; /* TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_READ", transport->description); */ /* check whether the socket is paused or not */ if (active_socket->paused) { TSK_DEBUG_INFO("Socket is paused"); goto FD_READ_DONE; } if (networkEvents.iErrorCode[FD_READ_BIT]) { TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd); TNET_PRINT_LAST_ERROR("READ FAILED."); goto done; } /* Retrieve the amount of pending data */ if (tnet_ioctlt(active_socket->fd, FIONREAD, &(wsaBuffer.len)) < 0) { TNET_PRINT_LAST_ERROR("IOCTLT FAILED."); goto done; } if (!wsaBuffer.len) { goto done; } /* Alloc data */ if (!(wsaBuffer.buf = tsk_calloc(wsaBuffer.len, sizeof(uint8_t)))) { goto done; } /* Retrieve the remote address */ if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) { ret = tnet_getpeername(active_socket->fd, &remote_addr); } /* Receive the waiting data. */ if (active_socket->tlshandle) { int isEncrypted; tsk_size_t len = wsaBuffer.len; if (!(ret = tnet_tls_socket_recv(active_socket->tlshandle, &wsaBuffer.buf, &len, &isEncrypted))) { if (isEncrypted) { TSK_FREE(wsaBuffer.buf); goto done; } wsaBuffer.len = (ULONG)len; } } else { if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) { ret = WSARecv(active_socket->fd, &wsaBuffer, 1, &readCount, &flags, 0, 0); } else { int len = sizeof(remote_addr); ret = WSARecvFrom(active_socket->fd, &wsaBuffer, 1, &readCount, &flags, (struct sockaddr*)&remote_addr, &len, 0, 0); } if (readCount < wsaBuffer.len) { wsaBuffer.len = readCount; /* wsaBuffer.buf = tsk_realloc(wsaBuffer.buf, readCount); */ } } if (ret) { ret = WSAGetLastError(); if (ret == WSAEWOULDBLOCK) { // Doesn't (always) mean congestion but... another thread is also poll()ing the FD. For example, when TURN session has a reference to the fd. TSK_DEBUG_WARN("WSAEWOULDBLOCK error for READ SSESSION"); } else if (ret == WSAECONNRESET && TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)) { /* For DGRAM ==> The sent packet gernerated "ICMP Destination/Port unreachable" result. */ TSK_FREE(wsaBuffer.buf); goto done; // ignore and retry. } else { TSK_FREE(wsaBuffer.buf); removeSocket(index, context); TNET_PRINT_LAST_ERROR("WSARecv have failed."); goto done; } } else { tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd); transport->bytes_in += wsaBuffer.len; e->data = wsaBuffer.buf; e->size = wsaBuffer.len; e->remote_addr = remote_addr; TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e); } FD_READ_DONE: ; } /*================== FD_WRITE ==================*/ if (networkEvents.lNetworkEvents & FD_WRITE) { TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_WRITE", transport->description); if (networkEvents.iErrorCode[FD_WRITE_BIT]) { TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd); TNET_PRINT_LAST_ERROR("WRITE FAILED."); goto done; } } /*================== FD_CLOSE ==================*/ if (networkEvents.lNetworkEvents & FD_CLOSE) { TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CLOSE", transport->description); TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, active_socket->fd); removeSocket(index, context); } /* http://msdn.microsoft.com/en-us/library/ms741690(VS.85).aspx The proper way to reset the state of an event object used with the WSAEventSelect function is to pass the handle of the event object to the WSAEnumNetworkEvents function in the hEventObject parameter. This will reset the event object and adjust the status of active FD events on the socket in an atomic fashion. */ /* WSAResetEvent(active_event); <== DO NOT USE (see above) */ done: /* unlock context */ tsk_safeobj_unlock(context); } /* while(transport->running) */ bail: TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type); return tsk_null; }