Пример #1
0
bool G2Packet::SkipCompound(quint32& nLength, quint32 nRemaining)
{
	quint32 nStart	= m_nPosition;
	quint32 nEnd	= m_nPosition + nLength;

	while ( m_nPosition < nEnd )
	{
		char nInput = ReadByte();
		if ( nInput == 0 ) break;

		char nLenLen	= ( nInput & 0xC0 ) >> 6;
		char nTypeLen	= ( nInput & 0x38 ) >> 3;
		char nFlags	= ( nInput & 0x07 );
		Q_UNUSED(nFlags);

		if ( m_nPosition + nTypeLen + nLenLen + 1 > nEnd ) throw packet_error();

		quint32 nPacket = 0;

		Read( &nPacket, nLenLen );

		if ( m_nPosition + nTypeLen + 1 + nPacket > nEnd ) throw packet_error();

		m_nPosition += nPacket + nTypeLen + 1;
	}

	nEnd = m_nPosition - nStart;
	if ( nEnd > nLength ) throw packet_error();
	nLength -= nEnd;

	return nRemaining ? nLength >= nRemaining : true;
}
Пример #2
0
bool G2Packet::ReadPacket(char* pszType, quint32& nLength, bool* pbCompound)
{
	if ( GetRemaining() == 0 ) return false;

	char nInput = ReadByte();
	if ( nInput == 0 ) return false;

	char nLenLen	= ( nInput & 0xC0 ) >> 6;
	char nTypeLen	= ( nInput & 0x38 ) >> 3;
	char nFlags		= ( nInput & 0x07 );

	if ( GetRemaining() < nTypeLen + nLenLen + 1 ) throw packet_error();

	nLength = 0;
	Read( &nLength, nLenLen );

	if ( GetRemaining() < (int)nLength + nTypeLen + 1 ) throw packet_error();

	Read( pszType, nTypeLen + 1 );
	pszType[ nTypeLen + 1 ] = 0;

	if ( pbCompound )
	{
		*pbCompound = ( nFlags & G2_FLAG_COMPOUND ) == G2_FLAG_COMPOUND;
	}
	else
	{
		if ( nFlags & G2_FLAG_COMPOUND ) SkipCompound( nLength );
	}

	return true;
}
Пример #3
0
G2Packet* G2Packet::ReadBuffer(QByteArray* pBuffer)
{
	if ( pBuffer == 0 )
		return 0;

	if ( pBuffer->size() < 2 )
		return 0;

	char nInput = *pBuffer[0];

	if ( nInput == 0 )
	{
		pBuffer->remove(0, 1);
		return 0;
	}

	char nLenLen	= ( nInput & 0xC0 ) >> 6;
	char nTypeLen	= ( nInput & 0x38 ) >> 3;
	char nFlags		= ( nInput & 0x07 );

	if ( (quint32)pBuffer->size() < (quint32)nLenLen + nTypeLen + 2u )
		return 0;

	quint32 nLength = 0;

	if ( nFlags & G2_FLAG_BIG_ENDIAN )
	{
		throw packet_error();
	}
	else
	{
		char* pLenIn	= pBuffer->data() + 1;
		char* pLenOut	= (char*)&nLength;
		for ( char nLenCnt = nLenLen ; nLenCnt-- ; ) *pLenOut++ = *pLenIn++;
	}

	if ( (quint32)pBuffer->size() < (quint32)nLength + nLenLen + nTypeLen + 2 )
		return 0;

	G2Packet* pPacket = G2Packet::New( pBuffer->data() );
	pBuffer->remove(0, nLength + nLenLen + nTypeLen + 2 );

	return pPacket;
}
Пример #4
0
/*
  trigger a run of the send queue
*/
_PUBLIC_ void packet_queue_run(struct packet_context *pc)
{
	while (pc->send_queue) {
		struct send_element *el = pc->send_queue;
		NTSTATUS status;
		size_t nwritten;
		DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent,
						 el->blob.length - el->nsent);

		status = socket_send(pc->sock, &blob, &nwritten);

		if (NT_STATUS_IS_ERR(status)) {
			packet_error(pc, status);
			return;
		}
		if (!NT_STATUS_IS_OK(status)) {
			return;
		}
		el->nsent += nwritten;
		if (el->nsent == el->blob.length) {
			DLIST_REMOVE(pc->send_queue, el);
			if (el->send_callback) {
				pc->busy = true;
				el->send_callback(el->send_callback_private);
				pc->busy = false;
				if (pc->destructor_called) {
					talloc_free(pc);
					return;
				}
			}
			talloc_free(el);
		}
	}

	/* we're out of requests to send, so don't wait for write
	   events any more */
	TEVENT_FD_NOT_WRITEABLE(pc->fde);
}
Пример #5
0
G2Packet* G2Packet::New(char* pSource)
{
	G2Packet* pPacket = New();

	char nInput		= *pSource++;

	char nLenLen	= ( nInput & 0xC0 ) >> 6;
	char nTypeLen	= ( nInput & 0x38 ) >> 3;
	char nFlags	= ( nInput & 0x07 );

	pPacket->m_bCompound	= ( nFlags & G2_FLAG_COMPOUND ) ? true : false;
	bool	bBigEndian	= ( nFlags & G2_FLAG_BIG_ENDIAN ) ? true : false;

	quint32 nLength = 0;

	if ( bBigEndian )
	{
		throw packet_error();
	}
	else
	{
		char* pLenOut = (char*)&nLength;
		while ( nLenLen-- ) *pLenOut++ = *pSource++;
	}

	nTypeLen++;
	char* pszType = pPacket->m_sType;
	for ( ; nTypeLen-- ;  )
	{
		*pszType++ = *pSource++;
	}
	*pszType++ = 0;

	pPacket->Write( pSource, nLength );

	return pPacket;
}
Пример #6
0
/*
  call this when the socket becomes readable to kick off the whole
  stream parsing process
*/
_PUBLIC_ void packet_recv(struct packet_context *pc)
{
	size_t npending;
	NTSTATUS status;
	size_t nread = 0;
	DATA_BLOB blob;
	bool recv_retry = false;

	if (pc->processing) {
		TEVENT_FD_NOT_READABLE(pc->fde);
		pc->processing++;
		return;
	}

	if (pc->recv_disable) {
		pc->recv_need_enable = true;
		TEVENT_FD_NOT_READABLE(pc->fde);
		return;
	}

	if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) {
		goto next_partial;
	}

	if (pc->packet_size != 0) {
		/* we've already worked out how long this next packet is, so skip the
		   socket_pending() call */
		npending = pc->packet_size - pc->num_read;
	} else if (pc->initial_read != 0) {
		npending = pc->initial_read - pc->num_read;
	} else {
		if (pc->sock) {
			status = socket_pending(pc->sock, &npending);
		} else {
			status = NT_STATUS_CONNECTION_DISCONNECTED;
		}
		if (!NT_STATUS_IS_OK(status)) {
			packet_error(pc, status);
			return;
		}
	}

	if (npending == 0) {
		packet_eof(pc);
		return;
	}

again:

	if (npending + pc->num_read < npending) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	if (npending + pc->num_read < pc->num_read) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	/* possibly expand the partial packet buffer */
	if (npending + pc->num_read > pc->partial.length) {
		if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
	}

	if (pc->partial.length < pc->num_read + npending) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}
	if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	status = socket_recv(pc->sock, pc->partial.data + pc->num_read, 
			     npending, &nread);

	if (NT_STATUS_IS_ERR(status)) {
		packet_error(pc, status);
		return;
	}
	if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
		nread = 0;
		status = NT_STATUS_OK;
	}
	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	if (nread == 0 && !recv_retry) {
		packet_eof(pc);
		return;
	}

	pc->num_read += nread;

	if (pc->unreliable_select && nread != 0) {
		recv_retry = true;
		status = socket_pending(pc->sock, &npending);
		if (!NT_STATUS_IS_OK(status)) {
			packet_error(pc, status);
			return;
		}
		if (npending != 0) {
			goto again;
		}
	}

next_partial:
	if (pc->partial.length != pc->num_read) {
		if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
	}

	/* see if its a full request */
	blob = pc->partial;
	blob.length = pc->num_read;
	status = pc->full_request(pc->private_data, blob, &pc->packet_size);
	if (NT_STATUS_IS_ERR(status)) {
		packet_error(pc, status);
		return;
	}
	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	if (pc->packet_size > pc->num_read) {
		/* the caller made an error */
		DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n",
			 (long)pc->packet_size, (long)pc->num_read));
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	/* it is a full request - give it to the caller */
	blob = pc->partial;
	blob.length = pc->num_read;

	if (pc->packet_size < pc->num_read) {
		pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size, 
					       pc->num_read - pc->packet_size);
		if (pc->partial.data == NULL) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
		/* Trunate the blob sent to the caller to only the packet length */
		if (!data_blob_realloc(pc, &blob, pc->packet_size)) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
	} else {
		pc->partial = data_blob(NULL, 0);
	}
	pc->num_read -= pc->packet_size;
	pc->packet_size = 0;
	
	if (pc->serialise) {
		pc->processing = 1;
	}

	pc->busy = true;

	status = pc->callback(pc->private_data, blob);

	pc->busy = false;

	if (pc->destructor_called) {
		talloc_free(pc);
		return;
	}

	if (pc->processing) {
		if (pc->processing > 1) {
			TEVENT_FD_READABLE(pc->fde);
		}
		pc->processing = 0;
	}

	if (!NT_STATUS_IS_OK(status)) {
		packet_error(pc, status);
		return;
	}

	/* Have we consumed the whole buffer yet? */
	if (pc->partial.length == 0) {
		return;
	}

	/* we got multiple packets in one tcp read */
	if (pc->ev == NULL) {
		goto next_partial;
	}

	blob = pc->partial;
	blob.length = pc->num_read;

	status = pc->full_request(pc->private_data, blob, &pc->packet_size);
	if (NT_STATUS_IS_ERR(status)) {
		packet_error(pc, status);
		return;
	}

	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	tevent_add_timer(pc->ev, pc, timeval_zero(), packet_next_event, pc);
}
Пример #7
0
/*
  tell the caller we have EOF
*/
static void packet_eof(struct packet_context *pc)
{
	packet_error(pc, NT_STATUS_END_OF_FILE);
}