Esempio n. 1
0
/* Output device redirection capability set header */
void
rdpdr_out_capset_header(char* data, int size, uint16 capabilityType, uint16 capabilityLength, uint32 version)
{
	SET_UINT16(data, 0, capabilityType); /* capabilityType */
	SET_UINT16(data, 2, capabilityLength); /* capabilityLength */
	SET_UINT32(data, 4, version); /* version */
}
Esempio n. 2
0
int
cliprdr_send_packet(cliprdrPlugin * plugin, int type, int flag,
	char * data, int length)
{
	char * out_data;
	int size;
	uint32 error;

	LLOGLN(10, ("cliprdr_send_packet: type=%d, flag=%d, length=%d",
		type, flag, length));

	size = 12 + length;
	out_data = (char *) malloc(size);
	memset(out_data, 0, size);
	SET_UINT16(out_data, 0, (uint16)type);
	SET_UINT16(out_data, 2, (uint16)flag);
	SET_UINT32(out_data, 4, (uint32)length);
	if (data != 0)
	{
		memcpy(out_data + 8, data, length);
	}

	error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
		out_data, size, out_data);
	if (error != CHANNEL_RC_OK)
	{
		LLOGLN(0, ("cliprdr_send_packet: "
			"VirtualChannelWrite "
			"failed %d", error));
		return 1;
	}
	return 0;
}
Esempio n. 3
0
/* header is not removed from data in this function */
static int
thread_process_message_wave(rdpsndPlugin * plugin, char * data, int data_size)
{
	int size;
	int wTimeStamp;
	char * out_data;

	plugin->expectingWave = 0;
	memcpy(data, plugin->waveData, 4);
	if (data_size != plugin->waveDataSize)
	{
		LLOGLN(0, ("thread_process_message_wave: "
			"size error"));
	}
	if (plugin->device_plugin)
		plugin->device_plugin->play(plugin->device_plugin, data, data_size, &plugin->delay_ms);
	size = 8;
	out_data = (char *) malloc(size);
	SET_UINT8(out_data, 0, SNDC_WAVECONFIRM);
	SET_UINT8(out_data, 1, 0);
	SET_UINT16(out_data, 2, size - 4);
	LLOGLN(10, ("thread_process_message_wave: "
		"data_size %d delay %d local_time %u",
		data_size, plugin->delay_ms, plugin->local_time_stamp));
	wTimeStamp = plugin->wTimeStamp + plugin->delay_ms;
	SET_UINT16(out_data, 4, wTimeStamp);
	SET_UINT8(out_data, 6, plugin->cBlockNo);
	SET_UINT8(out_data, 7, 0);
	plugin->data_out = out_data;
	plugin->data_out_size = size;
	queue_data_out(plugin);
	return 0;
}
Esempio n. 4
0
static int
process_CAPABILITY_REQUEST_PDU(drdynvcPlugin * plugin, int Sp, int cbChId,
	char * data, int data_size)
{
	int error;
	int size;
	char * out_data;

	LLOGLN(10, ("process_CAPABILITY_REQUEST_PDU:"));
	plugin->version = GET_UINT16(data, 2);
	if (plugin->version == 2)
	{
		plugin->PriorityCharge0 = GET_UINT16(data, 4);
		plugin->PriorityCharge1 = GET_UINT16(data, 6);
		plugin->PriorityCharge2 = GET_UINT16(data, 8);
		plugin->PriorityCharge3 = GET_UINT16(data, 10);
	}
	size = 4;
	out_data = (char *) malloc(size);
	SET_UINT16(out_data, 0, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */
	SET_UINT16(out_data, 2, plugin->version);
	hexdump(out_data, 4);
	error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
	out_data, size, out_data);
	if (error != CHANNEL_RC_OK)
	{
		LLOGLN(0, ("process_CAPABILITY_REQUEST_PDU: "
			"VirtualChannelWrite "
			"failed %d", error));
		return 1;
	}
	return 0;
}
Esempio n. 5
0
static int
set_variable_uint(uint32 val, char * data, uint32 * pos)
{
	int cb;

	if (val <= 0xFF)
	{
		cb = 0;
		SET_UINT8(data, *pos, val);
		*pos += 1;
	}
	else if (val <= 0xFFFF)
	{
		cb = 1;
		SET_UINT16(data, *pos, val);
		*pos += 2;
	}
	else
	{
		cb = 3;
		SET_UINT32(data, *pos, val);
		*pos += 4;
	}
	return cb;
}
Esempio n. 6
0
/* Output device direction general capability set */
int
rdpdr_out_general_capset(char* data, int size)
{
	SET_UINT32(data, 8, 0); /* osType, ignored on receipt */
	SET_UINT32(data, 12, 0); /* osVersion, unused and must be set to zero */
	SET_UINT16(data, 16, 1); /* protocolMajorVersion, must be set to 1 */
	SET_UINT16(data, 18, RDPDR_MINOR_RDP_VERSION_5_2); /* protocolMinorVersion */
	SET_UINT32(data, 20, 0x0000FFFF); /* ioCode1 */
	SET_UINT32(data, 24, 0); /* ioCode2, must be set to zero, reserved for future use */
	SET_UINT32(data, 28, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */
	SET_UINT32(data, 32, ENABLE_ASYNCIO); /* extraFlags1 */
	SET_UINT32(data, 36, 0); /* extraFlags2, must be set to zero, reserved for future use */
	SET_UINT32(data, 40, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */

	rdpdr_out_capset_header(data, size,
		CAP_GENERAL_TYPE, 44, GENERAL_CAPABILITY_VERSION_02);

	return 44;
}
Esempio n. 7
0
/* Decodes the raw packet in buf to create a rr. Assumes buf points to the 
 * start of a rr. 
 * Note: Question rrs dont have rdatalen or rdata. Set is_question when
 * decoding question rrs, else clear is_question
 */
void dns_decode_rr(struct dns_rr *rr, char **buf, int is_question,char *header, char *buf_start, struct dns_message *m)
{
  /* if the first two bits the of the name are set, then the message has been
     compressed and so the next byte is an offset from the start of the message
     pointing to the start of the name */
  if( **buf & 0xC0 ){
    (*buf)++;
    header += *(*buf)++;
    dns_decode_name( rr->name, &header );
  }else{
    /* ordinary decode name */
    dns_decode_name( rr->name, buf );
  }  

  SET_UINT16( rr->type, buf );
  SET_UINT16( rr->class, buf);

  if( is_question != 1 ){
    SET_UINT32( rr->ttl, buf );
    SET_UINT16( rr->rdatalen, buf );
    
    /* BRCM message format wrong. drop it */
    if(((*buf - buf_start) >= MAX_PACKET_SIZE) ||
       (((*buf - buf_start) + rr->rdatalen) >= MAX_PACKET_SIZE) ||
       (rr->rdatalen >= MAX_PACKET_SIZE/2))
    {
      m->header.ancount = 0;
      return;
    }
    memcpy( rr->data, *buf, rr->rdatalen );
    *buf += rr->rdatalen;
    /*
    for(i = 0; i < rr->rdatalen; i+=4 )
      SET_UINT32( (uint32)rr->data[i], buf );
    */
  }

  if( rr->type == PTR ){ /* reverse lookup */
    dns_decode_reverse_name( rr->name );
  }
}
Esempio n. 8
0
char *
irp_output_device_io_completion(IRP* irp, int * data_size)
{
	char * data;

	*data_size = 20 + irp->outputBufferLength;
	data = malloc(*data_size);
	memset(data, 0, *data_size);

	SET_UINT16(data, 0, RDPDR_CTYP_CORE); /* component */
	SET_UINT16(data, 2, PAKID_CORE_DEVICE_IOCOMPLETION); /* packetID */
	SET_UINT32(data, 4, irp->dev->id); /* deviceID */
	SET_UINT32(data, 8, irp->completionID); /* completionID */
	SET_UINT32(data, 12, irp->ioStatus); /* ioStatus */
	SET_UINT32(data, 16, irp->outputResult);
	if (irp->outputBufferLength > 0)
	{
		memcpy(data + 20, irp->outputBuffer, irp->outputBufferLength);
	}
	return data;
}
Esempio n. 9
0
/* A raw packet pointed to by buf is decoded in the assumed to be alloced 
 * dns_message structure.
 * RETURNS: 0
 */
int dns_decode_message(struct dns_message *m, char **buf)
{
  int i;
  char *header_start = *buf;
  char *buf_start = *buf;

  //BRCM: just decode id and header
  SET_UINT16( m->header.id, buf );  
  SET_UINT16( m->header.flags.flags, buf );
  
  SET_UINT16( m->header.qdcount, buf );
  SET_UINT16( m->header.ancount, buf );
  SET_UINT16( m->header.nscount, buf );
  SET_UINT16( m->header.arcount, buf );

  #if 0 //BRCM
  if( m->header.ancount > 1 ){
    printf("Lotsa answers\n");
  }
  #endif

  /* decode all the question rrs */
  for( i = 0; i < m->header.qdcount && i < NUM_RRS; i++){
    dns_decode_rr( &m->question[i], buf, 1, header_start, buf_start, m);
  }  
  /* decode all the answer rrs */
  for( i = 0; i < m->header.ancount && i < NUM_RRS; i++){
    dns_decode_rr( &m->answer[i], buf, 0, header_start, buf_start, m);
  }

  return 0;
}
Esempio n. 10
0
/* called by worker thread
   server is getting a feel of the round trip time */
static int
thread_process_message_training(rdpsndPlugin * plugin, char * data, int data_size)
{
	int wTimeStamp;
	int wPackSize;
	int size;
	char * out_data;
	uint32 error;

	wTimeStamp = GET_UINT16(data, 0);
	wPackSize = GET_UINT16(data, 2);
	if (wPackSize != 0)
	{
		if ((wPackSize - 4) != data_size)
		{
			LLOGLN(0, ("thread_process_message_training: size error "
				"wPackSize %d data_size %d",
				wPackSize, data_size));
			return 1;
		}
	}
	size = 8;
	out_data = (char *) malloc(size);
	SET_UINT8(out_data, 0, SNDC_TRAINING);
	SET_UINT8(out_data, 1, 0);
	SET_UINT16(out_data, 2, size - 4);
	SET_UINT16(out_data, 4, wTimeStamp);
	SET_UINT16(out_data, 6, wPackSize);
	error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
		out_data, size, out_data);
	if (error != CHANNEL_RC_OK)
	{
		LLOGLN(0, ("thread_process_message_training: VirtualChannelWrite "
			"failed %d", error));
		return 1;
	}
	return 0;
}
Esempio n. 11
0
ENTRY_POINT MSCompStatus xpress_deflate(mscomp_stream* stream, MSCompFlush flush)
{
	// There will be one conceptual difference between the streaming and non-streaming versions.
	// The streaming version has to deal with the fact that the two partnered half-bytes might be
	// very far apart. To not take up too much memory, after 16kb (or more - up to 128kb?) of not
	// finding a partner for a half-byte the partner will be assumed to be 0x0 (forcing a length
	// of 10 the next time a length 10+ match is found). This adds at most 2 bytes to the output
	// for data that is already not compressing well (each time it occurs).
#ifdef _XDEBUG
	mscomp_xpress_compress_state *state = (mscomp_xpress_compress_state*) stream->state;

	CHECK_STREAM_PLUS(stream, true, MSCOMP_XPRESS, state == NULL || state->finished);

	const size_t out_avail = stream->out_avail;
	const_bytes in  = stream->in;  const const_bytes in_end  = in +stream->in_avail;
	      bytes out = stream->out; const       bytes out_end = out+stream->out_avail;
	// TODO: const_bytes filled_to = in;

	uint32_t flags = state->flags, *out_flags = (uint32_t*)state->out_flags;
	byte flag_count = state->flag_count;
	byte* half_byte = state->half_byte;

	// TODO:
	//if (finish && stream->in_avail == 0 && state->in_avail == 0)
	//{
	//	if (UNLIKELY(out_len < 4)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
	//	SET_UINT32(out, 0xFFFFFFFF);
	//	*_out_len = 4;
	//	return MSCOMP_OK;
	//}
	//if (!d.Initialized()) { return MSCOMP_MEM_ERROR; }

	if (out_flags == NULL)
	{
		*out_flags = out;
	}

	out += 4;		// skip four for flags
	*out++ = *in++;	// copy the first byte
	flag_count = 1;

	while (in < in_end-1 && out < out_end)
	{
		uint32_t len, off;
		if (filled_to <= in) { filled_to = d.Fill(filled_to); }
		len = d.Find(in, &off);

		if (in + len >= in_end)
		{
		}

		flags <<= 1;
		if (len < 3) { *out++ = *in++; } // Copy byte
		else // Match found
		{
			flags |= 1;
			in += len;
			len -= 3;
			SET_UINT16(out, ((off-1) << 3) | MIN(len, 7));
			out += 2;
			if (len >= 0x7)
			{
				len -= 0x7;
				if (half_byte)
				{
					*half_byte |= MIN(len, 0xF) << 4;
					half_byte = NULL;
				}
				else
				{
					if (out >= out_end) { TODO; }
					*(half_byte=out++) = (byte)(MIN(len, 0xF));
				}
				if (len >= 0xF)
				{
					len -= 0xF;
					if (out >= out_end) { state->out[state->out_avail++] = (byte)MIN(len, 0xFF); }
					else { *out++ = (byte)MIN(len, 0xFF); }
					if (len >= 0xFF)
					{
						len += 0xF+0x7;
						if (len <= 0xFFFF)
						{
							if (out + 2 > out_end)
							{
								ptrdiff_t rem = out_end - out;
								ALWAYS(0 <= rem && rem < 2);
								if (rem == 1) { byte buf[2]; SET_UINT16(buf, len); *out++ = buf[0]; state->out[0] = buf[1]; ++state->out_avail; }
								else /*if (rem == 0)*/ { SET_UINT16(state->out+state->out_avail, len); state->out_avail += 2; }
							}
							else { SET_UINT16(out, len); out += 2; }
						}
						else
						{
							if (out + 6 > out_end)
							{
								// TODO: this really could be improved...
								ptrdiff_t rem = out_end - out;
								ALWAYS(0 <= rem && rem < 6);
								byte buf[6];
								SET_UINT16(buf, 0);
								SET_UINT32(buf+2, len);
								memcpy(out, buf, rem);
								memcpy(state->out+state->out_avail, buf+rem, 6-rem);
								state->out_avail += 6-rem;
								out = out_end;
							}
							else { SET_UINT16(out, 0); SET_UINT32(out+2, len); out += 6; }
						}
					}
				}
			}
		}
		if (++flag_count == 32)
		{
			SET_UINT32(out_flags, flags);
			flag_count = 0;
			if (out + 4 > out_end) { TODO; }
			out_flags = (uint32_t*)out;
			out += 4;
		}
	}
	while (in < in_end && out < out_end)
	{
		*out++ = *in++;
		flags <<= 1;
		if (++flag_count == 32)
		{
			SET_UINT32(out_flags, flags);
			flag_count = 0;
			if (out + 4 > out_end) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
			out_flags = (uint32_t*)out;
			out += 4;
		}
	}
	// Finish shifting over flags and set all unused bytes to 1
	// Note: the shifting math does not effect flags at all when flag_count == 0, resulting in a copy of the previous flags so the proper value must be set manually
	// RTL produces improper output in this case as well, so the decompressor still must tolerate bad flags at the very end
	if (UNLIKELY(in != in_end)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
	flags = flag_count ? (flags << (32 - flag_count)) | ((1 << (32 - flag_count)) - 1) : 0xFFFFFFFF;
	SET_UINT32(out_flags, flags);
	*_out_len = out - out_start;
	return MSCOMP_OK;

#else
	return MSCOMP_ARG_ERROR;
#endif
}
Esempio n. 12
0
ENTRY_POINT MSCompStatus xpress_compress(const_bytes in, size_t in_len, bytes out, size_t* _out_len)
{
	const size_t out_len = *_out_len;
	const const_bytes                  in_end  = in +in_len,  in_end2  = in_end  - 2;
	const const_bytes out_start = out, out_end = out+out_len, out_end1 = out_end - 1;
	const_bytes filled_to = in;

	uint32_t flags = 0, *out_flags = (uint32_t*)out;
	byte flag_count;
	byte* half_byte = NULL;

	Dictionary d(in, in_end);

	if (in_len == 0)
	{
		if (UNLIKELY(out_len < 4)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
		SET_UINT32(out, 0xFFFFFFFF);
		*_out_len = 4;
		return MSCOMP_OK;
	}
	if (out_len < MIN_DATA) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }

	out += 4;		// skip four for flags
	*out++ = *in++;	// copy the first byte
	flag_count = 1;

	while (in < in_end2 && out < out_end1)
	{
		uint32_t len, off;
		if (filled_to <= in) { filled_to = d.Fill(filled_to); }
		flags <<= 1;
		if ((len = d.Find(in, &off)) < 3) { *out++ = *in++; } // Copy byte
		else // Match found
		{
			in += len;
			len -= 3;
			SET_UINT16(out, ((off-1) << 3) | MIN(len, 7));
			out += 2;
			if (len >= 0x7)
			{
				len -= 0x7;
				if (half_byte)
				{
					*half_byte |= MIN(len, 0xF) << 4;
					half_byte = NULL;
				}
				else
				{
					if (out >= out_end) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
					*(half_byte=out++) = (byte)(MIN(len, 0xF));
				}
				if (len >= 0xF)
				{
					len -= 0xF;
					if (UNLIKELY(out >= out_end)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
					*out++ = (byte)MIN(len, 0xFF);
					if (len >= 0xFF)
					{
						len += 0xF+0x7;
						if (len <= 0xFFFF)
						{
							if (UNLIKELY(out + 2 > out_end)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
							SET_UINT16(out, len);
							out += 2;
						}
						else
						{
							if (UNLIKELY(out + 6 > out_end)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
							SET_UINT16(out, 0);
							SET_UINT32(out+2, len);
							out += 6;
						}
					}
				}
			}
			flags |= 1;
		}
		if (++flag_count == 32)
		{
			SET_UINT32(out_flags, flags);
			flag_count = 0;
			if (UNLIKELY(out + 4 > out_end)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
			out_flags = (uint32_t*)out;
			out += 4;
		}
	}
	while (in < in_end && out < out_end)
	{
		*out++ = *in++;
		flags <<= 1;
		if (++flag_count == 32)
		{
			SET_UINT32(out_flags, flags);
			flag_count = 0;
			if (out + 4 > out_end) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
			out_flags = (uint32_t*)out;
			out += 4;
		}
	}
	// Finish shifting over flags and set all unused bytes to 1
	// Note: the shifting math does not effect flags at all when flag_count == 0, resulting in a copy of the previous flags so the proper value must be set manually
	// RTL produces improper output in this case as well, so the decompressor still must tolerate bad flags at the very end
	if (UNLIKELY(in != in_end)) { PRINT_ERROR("Xpress Compression Error: Insufficient buffer"); return MSCOMP_BUF_ERROR; }
	flags = flag_count ? (flags << (32 - flag_count)) | ((1 << (32 - flag_count)) - 1) : 0xFFFFFFFF;
	SET_UINT32(out_flags, flags);
	*_out_len = out - out_start;
	return MSCOMP_OK;
}
Esempio n. 13
0
/* called by worker thread
   receives a list of server supported formats and returns a list
   of client supported formats */
static int
thread_process_message_formats(rdpsndPlugin * plugin, char * data, int data_size)
{
	int index;
	int format_count;
	int out_format_count;
	int out_format_size;
	int size;
	int flags;
	int version;
	char * ldata;
	char * out_data;
	char * out_formats;
	char * lout_formats;
	uint32 error;

	/* skip:
		dwFlags (4 bytes),
		dwVolume (4 bytes),
		dwPitch (4 bytes),
		wDGramPort (2 bytes) */
	format_count = GET_UINT16(data, 14); /* wNumberOfFormats */
	if ((format_count < 1) || (format_count > 1000))
	{
		LLOGLN(0, ("thread_process_message_formats: bad format_count %d",
			format_count));
		return 1;
	}
	plugin->cBlockNo = GET_UINT8(data, 16); /* cLastBlockConfirmed */
	version = GET_UINT16(data, 17); /* wVersion */
	if (version < 2)
	{
		LLOGLN(0, ("thread_process_message_formats: warning, old server"));
	}
	LLOGLN(0, ("thread_process_message_formats: version %d", version));
	/* skip:
		bPad (1 byte) */
	/* setup output buffer */
	size = 32 + data_size;
	out_data = (char *) malloc(size);
	out_formats = out_data + 24;
	lout_formats = out_formats;
	/* remainder is sndFormats (variable) */
	ldata = data + 20;
	out_format_count = 0;
	for (index = 0; index < format_count; index++)
	{
		size = 18 + GET_UINT16(ldata, 16);
		if (plugin->device_plugin && plugin->device_plugin->format_supported(plugin->device_plugin, ldata, size))
		{
			memcpy(lout_formats, ldata, size);
			lout_formats += size;
			out_format_count++;
		}
		ldata += size;
	}
	out_format_size = (int) (lout_formats - out_formats);
	if ((out_format_size > 0) && (out_format_count > 0))
	{
		plugin->supported_formats = (char *) malloc(out_format_size);
		memcpy(plugin->supported_formats, out_formats, out_format_size);
		plugin->supported_formats_size = out_format_size;
	}
	else
	{
		LLOGLN(0, ("thread_process_message_formats: error, "
			"no formats supported"));
	}
	size = 24 + out_format_size;
	SET_UINT8(out_data, 0, SNDC_FORMATS); /* Header (4 bytes) */
	SET_UINT8(out_data, 1, 0);
	SET_UINT16(out_data, 2, size - 4);
	flags = TSSNDCAPS_ALIVE | TSSNDCAPS_VOLUME;
	SET_UINT32(out_data, 4, flags); /* dwFlags */
	SET_UINT32(out_data, 8, 0xffffffff); /* dwVolume */
	SET_UINT32(out_data, 12, 0); /* dwPitch */
	SET_UINT16(out_data, 16, 0); /* wDGramPort */
	SET_UINT16(out_data, 18, out_format_count); /* wNumberOfFormats */
	SET_UINT8(out_data, 20, 0); /* cLastBlockConfirmed */
	SET_UINT16(out_data, 21, 2); /* wVersion */
	SET_UINT8(out_data, 23, 0); /* bPad */
	error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
		out_data, size, out_data);
	if (error != CHANNEL_RC_OK)
	{
		LLOGLN(0, ("thread_process_message_formats: "
			"VirtualChannelWrite "
			"failed %d", error));
		return 1;
	}
	if (version >= 6)
	{
		size = 8;
		out_data = (char *) malloc(size);
		SET_UINT8(out_data, 0, SNDC_QUALITYMODE); /* Header (4 bytes) */
		SET_UINT8(out_data, 1, 0);
		SET_UINT16(out_data, 2, size - 4);
		SET_UINT16(out_data, 4, 2); /* HIGH_QUALITY */
		SET_UINT16(out_data, 6, 0); /* Reserved (2 bytes) */
		error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
			out_data, size, out_data);
		if (error != CHANNEL_RC_OK)
		{
			LLOGLN(0, ("thread_process_message_formats: "
				"VirtualChannelWrite "
				"failed %d", error));
			return 1;
		}
	}
	return 0;
}