/* * Shuts the socket down for either reading or writing based on the how * parameter supplied by the remote side */ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); SocketContext *ctx = NULL; Channel *channel = NULL; DWORD result = ERROR_SUCCESS; DWORD how; // Find the associated channel channel = channel_find_by_id(packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)); how = packet_get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW); // If the channel and channel context are valid... if ((channel) && ((ctx = channel_get_native_io_context(channel)))) { if (shutdown(ctx->fd, how) == SOCKET_ERROR) result = WSAGetLastError(); } packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * core_channel_tell * ----------------- * * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to check tell on */ DWORD remote_request_core_channel_tell(Remote *remote, Packet *packet) { Channel *channel = NULL; Packet *response = packet_create_response(packet); DWORD result = ERROR_SUCCESS; LONG offset = 0; do { // Lookup the channel by its identifier if (!(channel = channel_find_by_id( packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) { result = ERROR_NOT_FOUND; break; } lock_acquire( channel->lock ); // Make sure this class is compatible if (channel_get_class(channel) != CHANNEL_CLASS_POOL) { result = ERROR_NOT_SUPPORTED; break; } // Call the function if it's set if (channel->ops.pool.tell) result = channel->ops.pool.tell(channel, packet, channel->ops.pool.native.context, &offset); else result = ERROR_NOT_SUPPORTED; } while (0); if( channel ) lock_release( channel->lock ); // Add the offset packet_add_tlv_uint(response, TLV_TYPE_SEEK_POS, offset); // Transmit the response packet_transmit_response(result, remote, response); return result; }
/* * Shuts the socket down for either reading or writing based on the how * parameter supplied by the remote side */ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; Packet * response = NULL; SocketContext * ctx = NULL; Channel * channel = NULL; DWORD cid = 0; DWORD how = 0; do { dprintf( "[TCP] entering request_net_socket_tcp_shutdown" ); response = packet_create_response( packet ); if( !response ) BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. response == NULL", ERROR_NOT_ENOUGH_MEMORY ); cid = packet_get_tlv_value_uint( packet, TLV_TYPE_CHANNEL_ID ); how = packet_get_tlv_value_uint( packet, TLV_TYPE_SHUTDOWN_HOW ); channel = channel_find_by_id( cid ); if( !response ) BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. channel == NULL", ERROR_INVALID_HANDLE ); dprintf( "[TCP] request_net_socket_tcp_shutdown. channel=0x%08X, cid=%d", channel, cid ); ctx = channel_get_native_io_context( channel ); if( !ctx ) BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. ctx == NULL", ERROR_INVALID_HANDLE ); if( shutdown( ctx->fd, how ) == SOCKET_ERROR ) BREAK_ON_WSAERROR( "[TCP] request_net_socket_tcp_shutdown. shutdown failed" ); // sf: we dont seem to need to call this here, as the channels tcp_channel_client_local_notify() will // catch the socket closure and call free_socket_context() for us, due the the FD_READ|FD_CLOSE flags // being passed to WSAEventSelect for the notify event in create_tcp_client_channel(). // This avoids a double call (from two different threads) and subsequent access violation in some edge cases. //free_socket_context( ctx ); } while( 0 ); packet_transmit_response( dwResult, remote, response ); dprintf( "[TCP] leaving request_net_socket_tcp_shutdown" ); return ERROR_SUCCESS; }
/* * core_channel_interact * --------------------- * * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to interact with * req: TLV_TYPE_BOOL -- True if interactive, false if not. */ DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); Channel *channel = NULL; DWORD channelId; DWORD result = ERROR_SUCCESS; BOOLEAN interact; // Get the channel identifier channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); interact = packet_get_tlv_value_bool(packet, TLV_TYPE_BOOL); // If the channel is found, set the interactive flag accordingly if ((channel = channel_find_by_id(channelId))) { lock_acquire( channel->lock ); // If the response packet is valid if ((response) && (channel_get_class(channel) != CHANNEL_CLASS_BUFFERED)) { NativeChannelOps *native = (NativeChannelOps *)&channel->ops; // Check to see if this channel has a registered interact handler dprintf( "[DISPATCH] attempting to set interactive: %d context 0x%p", interact, native->context ); if (native->interact) { result = native->interact(channel, packet, native->context, interact); } } // Set the channel's interactive state channel_set_interactive(channel, interact); lock_release( channel->lock ); } // Send the response to the requestor so that the interaction can be // complete packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * core_channel_close * ------------------ * * Closes a previously opened channel. * * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close */ DWORD remote_request_core_channel_close(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD res = ERROR_SUCCESS, channelId; Channel *channel = NULL; dprintf("[CHANNEL] remote_request_core_channel_close."); do { // Get the channel identifier channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); // Try to locate the specified channel if (!(channel = channel_find_by_id(channelId))) { res = ERROR_NOT_FOUND; break; } // Destroy the channel channel_destroy(channel, packet); if (response) { packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); } } while (0); // Transmit the acknowledgement if (response) { packet_add_tlv_uint(response, TLV_TYPE_RESULT, res); res = PACKET_TRANSMIT(remote, response, NULL); } return res; }
/* * core_channel_close (response) * ------------------ * * Removes the local instance of the channel * * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close */ DWORD remote_response_core_channel_close(Remote *remote, Packet *packet) { DWORD res = ERROR_SUCCESS, channelId; Channel *channel = NULL; do { // Get the channel identifier channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); // Try to locate the specified channel if (!(channel = channel_find_by_id(channelId))) { res = ERROR_NOT_FOUND; break; } // Destroy the channel channel_destroy(channel, packet); } while (0); return res; }
/* * core_channel_read * ----------------- * * From from the local buffer and write back to the requester * * Takes TLVs: * * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to read from * req: TLV_TYPE_LENGTH -- The number of bytes to read */ DWORD remote_request_core_channel_read(Remote *remote, Packet *packet) { DWORD res = ERROR_SUCCESS, bytesToRead, bytesRead, channelId; Packet *response = packet_create_response(packet); PUCHAR temporaryBuffer = NULL; Channel *channel = NULL; do { if (!response) { res = ERROR_NOT_ENOUGH_MEMORY; break; } // Get the number of bytes to read bytesToRead = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); // Try to locate the specified channel if (!(channel = channel_find_by_id(channelId))) { res = ERROR_NOT_FOUND; break; } lock_acquire( channel->lock ); // Allocate temporary storage if (!(temporaryBuffer = (PUCHAR)malloc(bytesToRead))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } switch (channel_get_class(channel)) { // If it's buffered, read from the local buffer and either transmit // the buffer in the response or write it back asynchronously // depending on the mode of the channel. case CHANNEL_CLASS_BUFFERED: // Read in from local res = channel_read_from_buffered(channel, temporaryBuffer, bytesToRead, (PULONG)&bytesRead); break; // Handle read I/O for the pool class case CHANNEL_CLASS_POOL: // If the channel has a read handler if (channel->ops.pool.read) res = channel->ops.pool.read(channel, packet, channel->ops.pool.native.context, temporaryBuffer, bytesToRead, &bytesRead); else res = ERROR_NOT_SUPPORTED; break; default: res = ERROR_NOT_SUPPORTED; } // If we've so far been successful and we have a temporary buffer... if ((res == ERROR_SUCCESS) &&(temporaryBuffer) && (bytesRead)) { // If the channel should operate synchronously, add the data to theresponse if (channel_is_flag(channel, CHANNEL_FLAG_SYNCHRONOUS)) { // if the channel data is ment to be compressed, compress it! if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, temporaryBuffer, bytesRead); else packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA, temporaryBuffer, bytesRead); res = ERROR_SUCCESS; } // Otherwise, asynchronously write the buffer to the remote endpoint else { if ((res = channel_write(channel, remote, NULL, 0, temporaryBuffer, bytesRead, NULL)) != ERROR_SUCCESS) break; } } } while (0); if( channel ) lock_release( channel->lock ); if (temporaryBuffer) free(temporaryBuffer); // Transmit the acknowledgement if (response) { packet_add_tlv_uint(response, TLV_TYPE_RESULT, res); packet_add_tlv_uint(response, TLV_TYPE_LENGTH, bytesRead); packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); res = packet_transmit(remote, response, NULL); } return res; }
/* * core_channel_write * ------------------ * * Write data from a channel into the local output buffer for it */ DWORD remote_request_core_channel_write(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD res = ERROR_SUCCESS, channelId, written = 0; Tlv channelData; Channel * channel = NULL; do { channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); // Try to locate the specified channel if (!(channel = channel_find_by_id(channelId))) { res = ERROR_NOT_FOUND; break; } lock_acquire( channel->lock ); // Get the channel data buffer if ((res = packet_get_tlv(packet, TLV_TYPE_CHANNEL_DATA, &channelData)) != ERROR_SUCCESS) break; // Handle the write operation differently based on the class of channel switch (channel_get_class(channel)) { // If it's buffered, write it to the local buffer cache case CHANNEL_CLASS_BUFFERED: res = channel_write_to_buffered(channel, channelData.buffer, channelData.header.length, (PULONG)&written); break; // If it's non-buffered, call the native write operation handler if // one is implemented default: { NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; if (ops->write) res = ops->write(channel, packet, ops->context, channelData.buffer, channelData.header.length, &written); else res = ERROR_NOT_SUPPORTED; } break; } } while (0); if( channel ) lock_release( channel->lock ); // Transmit the acknowledgement if (response) { packet_add_tlv_uint(response, TLV_TYPE_RESULT, res); packet_add_tlv_uint(response, TLV_TYPE_LENGTH, written); packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); res = packet_transmit(remote, response, NULL); } return res; }
/* * Channel completion routine dispatcher */ DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet, LPVOID context, LPCSTR method, DWORD result) { ChannelCompletionRoutine *comp = (ChannelCompletionRoutine *)context; DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); Channel *channel = channel_find_by_id(channelId); DWORD res = ERROR_NOT_FOUND; dprintf( "[CHANNEL] _channel_packet_completion_routine. channel=0x%08X method=%s", channel, method ); // If the channel was not found and it isn't an open request, return failure if (!channel && strcmp(method, "core_channel_open")) return ERROR_NOT_FOUND; if ((!strcmp(method, "core_channel_open")) && (comp->routine.open)) res = comp->routine.open(remote, channel, comp->context, result); else if ((!strcmp(method, "core_channel_read")) && (comp->routine.read)) { ULONG length = 0, realLength = 0; PUCHAR buffer = NULL; // Get the number of bytes written length = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); // Allocate storage for it if ((length) && (buffer = (PUCHAR)malloc(length))) { memset(buffer, 0, length); channel_read_from_buffered(channel, buffer, length, &realLength); } res = comp->routine.read(remote, channel, comp->context, result, buffer, realLength); if (buffer) free(buffer); } else if ((!strcmp(method, "core_channel_write")) && (comp->routine.write)) { Tlv lengthTlv; ULONG length = 0; // Get the number of bytes written to the channel if ((packet_get_tlv(packet, TLV_TYPE_LENGTH, &lengthTlv) == ERROR_SUCCESS) && (lengthTlv.header.length >= sizeof(DWORD))) length = ntohl(*(LPDWORD)lengthTlv.buffer); res = comp->routine.write(remote, channel, comp->context, result, length); } else if ((!strcmp(method, "core_channel_close")) && (comp->routine.close)) res = comp->routine.close(remote, channel, comp->context, result); else if ((!strcmp(method, "core_channel_interact")) && (comp->routine.interact)) res = comp->routine.interact(remote, channel, comp->context, result); // Deallocate the completion context free(comp); return res; }