/* * 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; }
/* * 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; }