/* * Enables or disables interactivity with the standard output handle on the channel */ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context, BOOLEAN interact) { ProcessChannelContext *ctx = (ProcessChannelContext *)context; DWORD result = ERROR_SUCCESS; dprintf( "[PROCESS] process_channel_interact. channel=0x%08X, ctx=0x%08X, interact=%d", channel, ctx, interact ); if (!channel_exists(channel) || ctx == NULL) { return result; } // If the remote side wants to interact with us, schedule the stdout handle // as a waitable item if (interact) { // try to resume it first, if it's not there, we can create a new entry if( (result = scheduler_signal_waitable( ctx->pStdout, Resume )) == ERROR_NOT_FOUND ) { result = scheduler_insert_waitable( ctx->pStdout, channel, context, (WaitableNotifyRoutine)process_channel_interact_notify, (WaitableDestroyRoutine)process_channel_interact_destroy ); } } else { // Otherwise, pause it result = scheduler_signal_waitable( ctx->pStdout, Pause ); } return result; }
/* * Enables or disables interactivity with the standard output handle on the channel */ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context, BOOLEAN interact) { ProcessChannelContext *ctx = (ProcessChannelContext *)context; DWORD result = ERROR_SUCCESS; dprintf( "[PROCESS] process_channel_interact. channel=0x%08X, ctx=0x%08X, interact=%d", channel, ctx, interact ); // If the remote side wants to interact with us, schedule the stdout handle // as a waitable item if (interact) result = scheduler_insert_waitable(ctx->pStdout, channel, (WaitableNotifyRoutine)process_channel_interact_notify); else // Otherwise, remove it result = scheduler_remove_waitable(ctx->pStdout); return result; }
/* * Completion routine for opening a TCP channel */ DWORD portfwd_open_tcp_channel_complete(Remote *remote, Packet *packet, LPVOID context, LPCSTR method, DWORD res) { PortForwardClientContext *pcctx = (PortForwardClientContext *)context; if (res == ERROR_SUCCESS) { DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); // Create a channel from the response if (channelId) pcctx->channel = channel_create(channelId); // Override the default dio handler if (pcctx->channel) { channel_set_type(pcctx->channel, "network_tcp"); channel_set_local_io_handler(pcctx->channel, pcctx, portfwd_client_dio); } // Create a waitable event for this client connection // and insert it into the scheduler's waitable list if ((pcctx->notify = WSACreateEvent())) { WSAEventSelect(pcctx->clientFd, pcctx->notify, FD_READ|FD_CLOSE); scheduler_insert_waitable(pcctx->notify, pcctx, (WaitableNotifyRoutine)portfwd_local_client_notify); } } else { console_generic_response_output(remote, packet, "NETWORK", "open_tcp_channel"); portfwd_destroy_client(pcctx); } return ERROR_SUCCESS; }
/* * Create a local listener and associate it with a remote host and port */ PortForwardListenerContext *portfwd_create_listener(LPCSTR lhost, USHORT lport, LPCSTR rhost, USHORT rport) { PortForwardListenerContext *plctx = NULL; struct sockaddr_in s; BOOL success = FALSE; DWORD on = 1; if (!lhost) lhost = "0.0.0.0"; do { // Allocate storage for the listener context if (!(plctx = (PortForwardListenerContext *)malloc( sizeof(PortForwardListenerContext)))) break; memset(plctx, 0, sizeof(PortForwardListenerContext)); // Resolve the local host if ((plctx->lhost = inet_addr(lhost)) == (DWORD)-1) { struct hostent *h; if (!(h = gethostbyname(lhost))) break; memcpy(&plctx->lhost, h->h_addr, h->h_length); } plctx->slhost = strdup(lhost); plctx->lport = lport; plctx->rhost = strdup(rhost); plctx->rport = rport; // Create the listener socket if ((plctx->listenFd = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0)) == SOCKET_ERROR) break; s.sin_family = AF_INET; s.sin_port = htons(lport); s.sin_addr.s_addr = plctx->lhost; // Set the re-use address flag if (setsockopt(plctx->listenFd, SOL_SOCKET, SO_REUSEADDR, (PCHAR)&on, sizeof(on)) == SOCKET_ERROR) break; // Bind to the port if (bind(plctx->listenFd, (struct sockaddr *)&s, sizeof(s)) == SOCKET_ERROR) break; // Set up the backlog if (listen(plctx->listenFd, 5) < 0) break; // Create a notification event if (!(plctx->notify = WSACreateEvent())) break; // Associate the event with the socket if (WSAEventSelect(plctx->listenFd, plctx->notify, FD_ACCEPT) == SOCKET_ERROR) break; // Insert the notification event into the schedulers waitable // object list so that asynchronous notifications can be handled if (scheduler_insert_waitable(plctx->notify, (LPVOID)plctx, (WaitableNotifyRoutine)portfwd_local_listener_notify) != ERROR_SUCCESS) break; // Insert the listener into the listener list plctx->next = listeners; plctx->prev = NULL; if (listeners) listeners->prev = plctx; listeners = plctx; // Success success = TRUE; } while (0); // Clean up on failure if ((!success) && (plctx)) { if (plctx->listenFd) closesocket(plctx->listenFd); free(plctx); plctx = NULL; } return plctx; }
/*! * @brief Allocates a streaming TCP server channel. * @param remote Pointer to the remote instance. * @param packet Pointer to the request packet. * @returns Indication of success or failure. * @retval ERROR_SUCCESS Opening the server channel completed successfully. */ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet) { DWORD dwResult = ERROR_SUCCESS; TcpServerContext * ctx = NULL; Packet * response = NULL; char * localHost = NULL; StreamChannelOps chops = { 0 }; USHORT localPort = 0; BOOL v4Fallback = FALSE; do { response = packet_create_response(packet); if (!response) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY); } ctx = (TcpServerContext *)malloc(sizeof(TcpServerContext)); if (!ctx) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY); } memset(ctx, 0, sizeof(TcpServerContext)); ctx->remote = remote; localPort = (USHORT)(packet_get_tlv_value_uint(packet, TLV_TYPE_LOCAL_PORT) & 0xFFFF); if (!localPort) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. localPort == NULL", ERROR_INVALID_HANDLE); } localHost = packet_get_tlv_value_string(packet, TLV_TYPE_LOCAL_HOST); ctx->fd = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); if (ctx->fd == INVALID_SOCKET) { v4Fallback = TRUE; } else { int no = 0; if (setsockopt(ctx->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) == SOCKET_ERROR) { // fallback to ipv4 - we're probably running on Windows XP or earlier here, which means that to // support IPv4 and IPv6 we'd need to create two separate sockets. IPv6 on XP isn't that common // so instead, we'll just revert back to v4 and listen on that one address instead. closesocket(ctx->fd); v4Fallback = TRUE; } } struct sockaddr_in6 sockAddr = { 0 }; DWORD sockAddrSize = 0; if (v4Fallback) { struct sockaddr_in* v4Addr = (struct sockaddr_in*)&sockAddr; v4Addr->sin_addr.s_addr = localHost == NULL ? htons(INADDR_ANY) : inet_addr(localHost); v4Addr->sin_family = AF_INET; v4Addr->sin_port = htons(localPort); sockAddrSize = sizeof(struct sockaddr_in); } else { // TODO: add IPv6 address binding support sockAddr.sin6_addr = in6addr_any; sockAddr.sin6_family = AF_INET6; sockAddr.sin6_port = htons(localPort); sockAddrSize = sizeof(struct sockaddr_in6); } if (bind(ctx->fd, (SOCKADDR *)&sockAddr, sockAddrSize) == SOCKET_ERROR) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. bind failed"); } if (listen(ctx->fd, SOMAXCONN) == SOCKET_ERROR) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. listen failed"); } ctx->notify = WSACreateEvent(); if (ctx->notify == WSA_INVALID_EVENT) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSACreateEvent failed"); } if (WSAEventSelect(ctx->fd, ctx->notify, FD_ACCEPT) == SOCKET_ERROR) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSAEventSelect failed"); } ctx->ipv6 = !v4Fallback; memset(&chops, 0, sizeof(StreamChannelOps)); chops.native.context = ctx; chops.native.close = tcp_channel_server_close; ctx->channel = channel_create_stream(0, CHANNEL_FLAG_SYNCHRONOUS, &chops); if (!ctx->channel) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE); } scheduler_insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL); packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->channel)); dprintf("[TCP-SERVER] request_net_tcp_server_channel_open. tcp server %s:%d on channel %d", localHost, localPort, channel_get_id(ctx->channel)); } while (0); packet_transmit_response(dwResult, remote, response); do { if (dwResult == ERROR_SUCCESS) { break; } dprintf("[TCP-SERVER] Error encountered %u 0x%x", dwResult, dwResult); if (!ctx) { break; } if (ctx->fd) { dprintf("[TCP-SERVER] Destroying socket"); closesocket(ctx->fd); } if (ctx->channel) { dprintf("[TCP-SERVER] Destroying channel"); channel_destroy(ctx->channel, packet); } free(ctx); } while (0); return dwResult; }
/*! * @brief Create a TCP client channel from a socket. * @param serverCtx Pointer to the TCP server context. * @param sock The socket handle. * @returns Pointer to the newly created client context. */ TcpClientContext * tcp_channel_server_create_client(TcpServerContext * serverCtx, SOCKET sock) { DWORD dwResult = ERROR_SUCCESS; TcpClientContext * clientctx = NULL; StreamChannelOps chops = { 0 }; do { if (!serverCtx) { BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_create_client. serverCtx == NULL", ERROR_INVALID_HANDLE); } clientctx = (TcpClientContext *)malloc(sizeof(TcpClientContext)); if (!clientctx) { BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_create_client. clientctx == NULL", ERROR_NOT_ENOUGH_MEMORY); } memset(clientctx, 0, sizeof(TcpClientContext)); clientctx->remote = serverCtx->remote; clientctx->fd = sock; clientctx->notify = WSACreateEvent(); if (clientctx->notify == WSA_INVALID_EVENT) { BREAK_ON_WSAERROR("[TCP-SERVER] tcp_channel_server_create_client. WSACreateEvent failed"); } if (WSAEventSelect(clientctx->fd, clientctx->notify, FD_READ | FD_CLOSE) == SOCKET_ERROR) { BREAK_ON_WSAERROR("[TCP-SERVER] tcp_channel_server_create_client. WSAEventSelect failed"); } memset(&chops, 0, sizeof(StreamChannelOps)); chops.native.context = clientctx; chops.native.write = tcp_channel_client_write; chops.native.close = tcp_channel_client_close; clientctx->channel = channel_create_stream(0, 0, &chops); if (!clientctx->channel) { BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_create_client. clientctx->channel == NULL", ERROR_INVALID_HANDLE); } dwResult = scheduler_insert_waitable(clientctx->notify, clientctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL); } while (0); if (dwResult != ERROR_SUCCESS) { if (clientctx) { free(clientctx); clientctx = NULL; } } return clientctx; }
/* * Creates a connection to a remote host and builds a logical channel to * represent it. * */ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remotePort, Channel **outChannel) { StreamChannelOps chops; TcpClientContext *ctx = NULL; DWORD result = ERROR_SUCCESS; Channel *channel = NULL; struct sockaddr_in s; SOCKET clientFd = 0; if (outChannel) *outChannel = NULL; dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d", remoteHost, remotePort ); do { // Allocate a client socket if ((clientFd = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0)) == INVALID_SOCKET) { clientFd = 0; result = GetLastError(); break; } s.sin_family = AF_INET; s.sin_port = htons(remotePort); s.sin_addr.s_addr = inet_addr(remoteHost); // Resolve the host name locally if (s.sin_addr.s_addr == (DWORD)-1) { struct hostent *h; if (!(h = gethostbyname(remoteHost))) { result = GetLastError(); break; } memcpy(&s.sin_addr.s_addr, h->h_addr, h->h_length); } dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d connecting...", remoteHost, remotePort ); // Try to connect to the host/port if (connect(clientFd, (struct sockaddr *)&s, sizeof(s)) == SOCKET_ERROR) { result = GetLastError(); break; } dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d connected!", remoteHost, remotePort ); // Allocate the client context for tracking the connection if (!(ctx = (TcpClientContext *)malloc( sizeof(TcpClientContext)))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Initialize the context attributes memset(ctx, 0, sizeof(TcpClientContext)); ctx->remote = remote; ctx->fd = clientFd; // Initialize the channel operations structure memset(&chops, 0, sizeof(chops)); chops.native.context = ctx; chops.native.write = tcp_channel_client_write; chops.native.close = tcp_channel_client_close; dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d creating the channel", remoteHost, remotePort ); // Allocate an uninitialized channel for associated with this connection if (!(channel = channel_create_stream(0, 0,&chops))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Save the channel context association ctx->channel = channel; // Finally, create a waitable event and insert it into the scheduler's // waitable list dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d creating the notify", remoteHost, remotePort ); if ((ctx->notify = WSACreateEvent())) { WSAEventSelect(ctx->fd, ctx->notify, FD_READ|FD_CLOSE); dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d created the notify %.8x", remoteHost, remotePort, ctx->notify ); scheduler_insert_waitable( ctx->notify, ctx, (WaitableNotifyRoutine)tcp_channel_client_local_notify); } } while (0); dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d all done", remoteHost, remotePort ); // Clean up on failure if (result != ERROR_SUCCESS) { dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d cleaning up failed connection", remoteHost, remotePort ); if (ctx) free_tcp_client_context(ctx); if (clientFd) closesocket(clientFd); channel = NULL; } if (outChannel) *outChannel = channel; return result; }
/* * Create a new UDP socket channel, optionally bound to a local address/port and optionaly specify * a remote peer host/port for future writes. */ DWORD request_net_udp_channel_open( Remote * remote, Packet * packet ) { DWORD dwResult = ERROR_SUCCESS; UdpClientContext * ctx = NULL; Packet * response = NULL; char * lhost = NULL; char * phost = NULL; SOCKADDR_IN saddr = {0}; DatagramChannelOps chops = {0}; do { response = packet_create_response( packet ); if( !response ) BREAK_WITH_ERROR( "[UDP] request_net_udp_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY ); ctx = (UdpClientContext *)malloc( sizeof(UdpClientContext) ); if( !ctx ) BREAK_WITH_ERROR( "[UDP] request_net_udp_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY ); memset( ctx, 0, sizeof(UdpClientContext) ); ctx->sock.remote = remote; ctx->localport = (USHORT)( packet_get_tlv_value_uint( packet, TLV_TYPE_LOCAL_PORT ) & 0xFFFF ); if( !ctx->localport ) ctx->localport = 0; ctx->peerport = (USHORT)( packet_get_tlv_value_uint( packet, TLV_TYPE_PEER_PORT ) & 0xFFFF ); if( !ctx->peerport ) ctx->peerport = 0; lhost = packet_get_tlv_value_string( packet, TLV_TYPE_LOCAL_HOST ); if( lhost ) ctx->localhost.s_addr = inet_addr( lhost ); else ctx->localhost.s_addr = INADDR_ANY; phost = packet_get_tlv_value_string( packet, TLV_TYPE_PEER_HOST ); if( phost ) { dprintf( "[UDP] request_net_udp_channel_open. phost=%s", phost ); ctx->peerhost.s_addr = inet_addr( phost ); } ctx->sock.fd = WSASocket( AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, 0, 0 ); if( ctx->sock.fd == INVALID_SOCKET ) BREAK_ON_WSAERROR( "[UDP] request_net_udp_channel_open. WSASocket failed" ); saddr.sin_family = AF_INET; saddr.sin_port = htons( ctx->localport ); saddr.sin_addr.s_addr = ctx->localhost.s_addr; if( bind( ctx->sock.fd, (SOCKADDR *)&saddr, sizeof(SOCKADDR_IN) ) == SOCKET_ERROR ) BREAK_ON_WSAERROR( "[UDP] request_net_udp_channel_open. bind failed" ); ctx->sock.notify = WSACreateEvent(); if( ctx->sock.notify == WSA_INVALID_EVENT ) BREAK_ON_WSAERROR( "[UDP] request_net_udp_channel_open. WSACreateEvent failed" ); if( WSAEventSelect( ctx->sock.fd, ctx->sock.notify, FD_READ ) == SOCKET_ERROR ) BREAK_ON_WSAERROR( "[UDP] request_net_udp_channel_open. WSAEventSelect failed" ); memset( &chops, 0, sizeof(DatagramChannelOps) ); chops.native.context = ctx; chops.native.write = udp_channel_write; chops.native.close = udp_channel_close; ctx->sock.channel = channel_create_datagram( 0, 0, &chops ); if( !ctx->sock.channel ) BREAK_WITH_ERROR( "[UDP] request_net_udp_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE ); scheduler_insert_waitable( ctx->sock.notify, ctx, (WaitableNotifyRoutine)udp_channel_notify ); packet_add_tlv_uint( response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->sock.channel) ); dprintf( "[UDP] request_net_udp_channel_open. UDP socket on channel %d (The local specified was %s:%d ) (The peer specified was %s:%d)", channel_get_id( ctx->sock.channel ), inet_ntoa( ctx->localhost ), ctx->localport, inet_ntoa( ctx->peerhost ), ctx->peerport ); } while( 0 ); packet_transmit_response( dwResult, remote, response ); do { if( dwResult == ERROR_SUCCESS ) break; if( !ctx ) break; if( ctx->sock.fd ) closesocket( ctx->sock.fd ); if( ctx->sock.channel ) channel_destroy( ctx->sock.channel, packet ); free( ctx ); } while( 0 ); return ERROR_SUCCESS; }
/*! * @brief Allocates a streaming TCP server channel. * @param remote Pointer to the remote instance. * @param packet Pointer to the request packet. * @returns Indication of success or failure. * @retval ERROR_SUCCESS Opening the server channel completed successfully. */ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet) { DWORD dwResult = ERROR_SUCCESS; TcpServerContext * ctx = NULL; Packet * response = NULL; char * lhost = NULL; SOCKADDR_IN saddr = { 0 }; StreamChannelOps chops = { 0 }; USHORT lport = 0; do { response = packet_create_response(packet); if (!response) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY); } ctx = (TcpServerContext *)malloc(sizeof(TcpServerContext)); if (!ctx) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY); } memset(ctx, 0, sizeof(TcpServerContext)); ctx->remote = remote; lport = (USHORT)(packet_get_tlv_value_uint(packet, TLV_TYPE_LOCAL_PORT) & 0xFFFF); if (!lport) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. lport == NULL", ERROR_INVALID_HANDLE); } lhost = packet_get_tlv_value_string(packet, TLV_TYPE_LOCAL_HOST); if (!lhost) { lhost = "0.0.0.0"; } ctx->fd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); if (ctx->fd == INVALID_SOCKET) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSASocket failed"); } saddr.sin_family = AF_INET; saddr.sin_port = htons(lport); saddr.sin_addr.s_addr = inet_addr(lhost); if (bind(ctx->fd, (SOCKADDR *)&saddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { #ifdef _WIN32 dwResult = WSAGetLastError(); if (dwResult != WSAEADDRNOTAVAIL) #else dwResult = errno; if (dwResult != EADDRNOTAVAIL) #endif { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. bind failed"); } dprintf("[TCP-SERVER] Failed to bind to %s, trying 0.0.0.0 ...", lhost); // try again, but this time bind to any/all interfaces. lhost = "0.0.0.0"; saddr.sin_addr.s_addr = inet_addr(lhost); if (bind(ctx->fd, (SOCKADDR *)&saddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. bind failed"); } dwResult = ERROR_SUCCESS; } if (listen(ctx->fd, SOMAXCONN) == SOCKET_ERROR) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. listen failed"); } ctx->notify = WSACreateEvent(); if (ctx->notify == WSA_INVALID_EVENT) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSACreateEvent failed"); } if (WSAEventSelect(ctx->fd, ctx->notify, FD_ACCEPT) == SOCKET_ERROR) { BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSAEventSelect failed"); } memset(&chops, 0, sizeof(StreamChannelOps)); chops.native.context = ctx; chops.native.close = tcp_channel_server_close; ctx->channel = channel_create_stream(0, CHANNEL_FLAG_SYNCHRONOUS, &chops); if (!ctx->channel) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE); } scheduler_insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL); packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->channel)); dprintf("[TCP-SERVER] request_net_tcp_server_channel_open. tcp server %s:%d on channel %d", lhost, lport, channel_get_id(ctx->channel)); } while (0); packet_transmit_response(dwResult, remote, response); do { if (dwResult == ERROR_SUCCESS) { break; } dprintf("[TCP-SERVER] Error encountered %u 0x%x", dwResult, dwResult); if (!ctx) { break; } if (ctx->fd) { dprintf("[TCP-SERVER] Destroying socket"); closesocket(ctx->fd); } if (ctx->channel) { dprintf("[TCP-SERVER] Destroying channel"); channel_destroy(ctx->channel, packet); } free(ctx); } while (0); return dwResult; }