/* * Destroy a previously allocated channel */ VOID channel_destroy(Channel *channel, Packet *request) { dprintf( "[CHANNEL] channel_destroy. channel=0x%08X", channel ); // Call the close handler as we're being destroyed. if ((channel_get_class(channel) == CHANNEL_CLASS_BUFFERED) && (channel->ops.buffered.dio)) { channel->ops.buffered.dio(channel, &channel->ops.buffered, channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_CLOSE, NULL, 0, NULL); if (channel->ops.buffered.buffer) free(channel->ops.buffered.buffer); } else { NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; if (ops->close) ops->close(channel, request, ops->context); } // Remove the channel from the list of channels channel_remove_list_entry(channel); lock_destroy( channel->lock ); // Destroy the channel context free(channel); }
VOID channel_destroy(Channel *channel, Packet *request) { dprintf( "[CHANNEL] channel_destroy. channel=0x%08X", channel ); if ((channel_get_class(channel) == CHANNEL_CLASS_BUFFERED) && (channel->ops.buffered.dio)) { channel->ops.buffered.dio(channel, &channel->ops.buffered, channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_CLOSE, NULL, 0, NULL); if (channel->ops.buffered.buffer) free(channel->ops.buffered.buffer); } else { NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; if (ops->close) ops->close(channel, request, ops->context); } channel_remove_list_entry(channel); lock_destroy( channel->lock ); dprintf( "[CHANNEL] Free up the channel context 0x%p", channel ); free(channel); }
/* * 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; }
/* * 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_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; }