/*! * @brief Closes the server socket and brings down the client connections. * @param channel Pointer to the TCP channel to close. * @param request The request packet. * @param context The channel context. * @returns Indication of success or failure. * @retval ERROR_SUCCESS This value is always returned. */ DWORD tcp_channel_server_close(Channel * channel, Packet * request, LPVOID context) { TcpServerContext * ctx = (TcpServerContext *)context; do { dprintf("[TCP-SERVER] tcp_channel_server_close. channel=0x%08X, ctx=0x%08X", channel, ctx); if (!ctx) { break; } // Set the context channel to NULL so we don't try to close the // channel (since it's already being closed) ctx->channel = NULL; // Free the context free_tcp_server_context(ctx); // Set the native channel operations context to NULL channel_set_native_io_context(channel, NULL); } while (0); return ERROR_SUCCESS; }
/* * Bring down a UDP channel an free up the context. */ DWORD udp_channel_close( Channel * channel, Packet * request, LPVOID context ) { UdpClientContext * ctx = (UdpClientContext *)context; do { dprintf( "[UDP] udp_channel_close. channel=0x%08X, ctx=0x%08X", channel, ctx ); if( !ctx ) break; // Set the context channel to NULL so we don't try to close the // channel (since it's already being closed) ctx->sock.channel = NULL; // Free the context free_udp_context( ctx ); // Set the native channel operations context to NULL channel_set_native_io_context( channel, NULL ); } while( 0 ); return ERROR_SUCCESS; }
/* * Closes the established connection and cleans up stale state */ static DWORD tcp_channel_client_close(Channel *channel, Packet *request, LPVOID context) { TcpClientContext *ctx = (TcpClientContext *)context; if (ctx) { // Set the context channel to NULL so we don't try to close the // channel (since it's already being closed) ctx->channel = NULL; // Free the context free_tcp_client_context(ctx); // Set the native channel operations context to NULL channel_set_native_io_context(channel, NULL); } return ERROR_SUCCESS; }
/* * Callback for when there is data available on the local side of the TCP client connection */ DWORD tcp_channel_client_local_notify( Remote * remote, TcpClientContext * ctx ) { struct timeval tv = {0}; fd_set set = {0}; UCHAR buf[16384] = {0}; LONG dwBytesRead = 0; // We select in a loop with a zero second timeout because it's possible // that we could get a recv notification and a close notification at once, // so we need some way to make sure that we see them both, otherwise the // event handle wont get re set to notify us. do { // Reset the notification event ResetEvent( ctx->notify ); FD_ZERO( &set ); FD_SET( ctx->fd, &set ); tv.tv_sec = 0; tv.tv_usec = 0; // Read data from the client connection dwBytesRead = recv( ctx->fd, buf, sizeof(buf), 0 ); if( dwBytesRead == SOCKET_ERROR ) { DWORD dwError = WSAGetLastError(); // WSAECONNRESET: The connection was forcibly closed by the remote host. // WSAECONNABORTED: The connection was terminated due to a time-out or other failure. if( dwError == WSAECONNRESET || dwError == WSAECONNABORTED ) { dprintf( "[TCP] tcp_channel_client_local_notify. [error] closing down channel gracefully. WSAGetLastError=%d", dwError ); // By setting bytesRead to zero, we can ensure we close down the channel gracefully... dwBytesRead = 0; } else if( dwError == WSAEWOULDBLOCK ) { dprintf( "[TCP] tcp_channel_client_local_notify. channel=0x%08X. recv generated a WSAEWOULDBLOCK", ctx->channel ); // break and let the scheduler notify us again if needed. break; } else { dprintf( "[TCP] tcp_channel_client_local_notify. [error] channel=0x%08X read=0x%.8x (ignored). WSAGetLastError=%d", ctx->channel, dwBytesRead, dwError ); // we loop again because bytesRead is -1. } } if( dwBytesRead == 0 ) { dprintf( "[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, dwBytesRead ); // Set the native channel operations context to NULL channel_set_native_io_context( ctx->channel, NULL ); // Sleep for a quarter second Sleep( 250 ); // Free the context free_tcp_client_context( ctx ); // Stop processing break; } else if( dwBytesRead > 0 ) { if( ctx->channel ) { dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=%d", ctx->channel, dwBytesRead ); channel_write( ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0 ); } else { dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=<invalid> read=0x%.8x", dwBytesRead ); } } } while( select( 1, &set, NULL, NULL, &tv ) > 0 ); return ERROR_SUCCESS; }
/* * The notify routine for all FD_READ events on the UDP socket. */ DWORD udp_channel_notify( Remote * remote, UdpClientContext * ctx ) { DWORD dwResult = ERROR_SUCCESS; SOCKADDR_IN from = {0}; DWORD dwFromLength = 0; DWORD dwBytesRead = 0; BYTE bBuffer[65535]; do { ResetEvent( ctx->sock.notify ); dwFromLength = sizeof( SOCKADDR_IN ); dwBytesRead = recvfrom( ctx->sock.fd, bBuffer, 65535, 0, (SOCKADDR *)&from, &dwFromLength ); if( dwBytesRead == SOCKET_ERROR ) { DWORD dwError = WSAGetLastError(); if( dwError == WSAECONNRESET ) { dprintf( "[UDP] udp_channel_notify. WSAECONNRESET for channel=0x%08X, WSAGetLastError=%d", ctx->sock.channel, dwError ); // sf: here we have a valid host which sent back an ICMP Port Unreachable message for a previous sendto() // we should not close the socket (ctx->sock.fd) } else { dprintf( "[UDP] udp_channel_notify. Error on recvfrom with channel=0x%08X, WSAGetLastError=%d", ctx->sock.channel, dwError ); } break; } if( dwBytesRead == 0 ) { dprintf( "[UDP] udp_channel_notify. channel=0x%08X is being gracefully closed...", ctx->sock.channel ); channel_set_native_io_context( ctx->sock.channel, NULL ); Sleep( 250 ); free_udp_context( ctx ); break; } else if( dwBytesRead > 0 ) { char * cpPeerHost = NULL; Tlv addend[2] = {0}; DWORD dwPeerPort = 0; if( !ctx->sock.channel ) break; cpPeerHost = inet_ntoa( from.sin_addr ); if( !cpPeerHost ) cpPeerHost = "0.0.0.0"; dwPeerPort = htonl( ntohs( from.sin_port ) ); addend[0].header.type = TLV_TYPE_PEER_HOST; addend[0].header.length = (DWORD)(strlen(cpPeerHost) + 1); addend[0].buffer = cpPeerHost; addend[1].header.type = TLV_TYPE_PEER_PORT; addend[1].header.length = sizeof(DWORD); addend[1].buffer = (PUCHAR)&dwPeerPort; dprintf( "[UDP] udp_channel_notify. Data on channel=0x%08X, read %d bytes from %s:%d", ctx->sock.channel, dwBytesRead, cpPeerHost, ntohs( from.sin_port ) ); channel_write( ctx->sock.channel, ctx->sock.remote, addend, 2, bBuffer, dwBytesRead, NULL ); } } while( 0 ); return ERROR_SUCCESS; }