wStream* transport_send_stream_init(rdpTransport* transport, int size) { wStream* s; if (!(s = StreamPool_Take(transport->ReceivePool, size))) return NULL; if (!Stream_EnsureCapacity(s, size)) { Stream_Release(s); return NULL; } Stream_SetPosition(s, 0); return s; }
rdpTransport* transport_new(rdpContext* context) { rdpTransport* transport; transport = (rdpTransport*) calloc(1, sizeof(rdpTransport)); if (!transport) return NULL; transport->context = context; transport->settings = context->settings; transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE); if (!transport->ReceivePool) goto out_free_transport; /* receive buffer for non-blocking read. */ transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); if (!transport->ReceiveBuffer) goto out_free_receivepool; transport->connectedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!transport->connectedEvent || transport->connectedEvent == INVALID_HANDLE_VALUE) goto out_free_receivebuffer; transport->blocking = TRUE; transport->GatewayEnabled = FALSE; transport->layer = TRANSPORT_LAYER_TCP; if (!InitializeCriticalSectionAndSpinCount(&(transport->ReadLock), 4000)) goto out_free_connectedEvent; if (!InitializeCriticalSectionAndSpinCount(&(transport->WriteLock), 4000)) goto out_free_readlock; return transport; out_free_readlock: DeleteCriticalSection(&(transport->ReadLock)); out_free_connectedEvent: CloseHandle(transport->connectedEvent); out_free_receivebuffer: StreamPool_Return(transport->ReceivePool, transport->ReceiveBuffer); out_free_receivepool: StreamPool_Free(transport->ReceivePool); out_free_transport: free(transport); return NULL; }
rdpTransport* transport_new(rdpSettings* settings) { rdpTransport* transport; transport = (rdpTransport*) malloc(sizeof(rdpTransport)); if (transport != NULL) { ZeroMemory(transport, sizeof(rdpTransport)); transport->TcpIn = tcp_new(settings); transport->settings = settings; /* a small 0.1ms delay when transport is blocking. */ transport->SleepInterval = 100; transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE); /* receive buffer for non-blocking read. */ transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); transport->ReceiveEvent = CreateEvent(NULL, TRUE, FALSE, NULL); transport->connectedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* buffers for blocking read/write */ transport->ReceiveStream = StreamPool_Take(transport->ReceivePool, 0); transport->SendStream = Stream_New(NULL, BUFFER_SIZE); transport->blocking = TRUE; transport->layer = TRANSPORT_LAYER_TCP; } return transport; }
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length) { DVCMAN_CHANNEL* channel; channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { DEBUG_WARN("ChannelId %d not found!", ChannelId); return 1; } if (channel->dvc_data) Stream_Release(channel->dvc_data); channel->dvc_data = StreamPool_Take(channel->dvcman->pool, length); Stream_AddRef(channel->dvc_data); return 0; }
rdpTransport* transport_new(rdpSettings* settings) { rdpTransport* transport; transport = (rdpTransport*) malloc(sizeof(rdpTransport)); if (transport) { ZeroMemory(transport, sizeof(rdpTransport)); WLog_Init(); transport->log = WLog_Get("com.freerdp.core.transport"); transport->TcpIn = tcp_new(settings); transport->settings = settings; /* a small 0.1ms delay when transport is blocking. */ transport->SleepInterval = 100; transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE); /* receive buffer for non-blocking read. */ transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); transport->ReceiveEvent = CreateEvent(NULL, TRUE, FALSE, NULL); transport->connectedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); transport->blocking = TRUE; transport->ReadMutex = CreateMutex(NULL, FALSE, NULL); transport->WriteMutex = CreateMutex(NULL, FALSE, NULL); transport->layer = TRANSPORT_LAYER_TCP; } return transport; }
/** Creates a new connection based on the settings found in the "instance" parameter * It will use the callbacks registered on the structure to process the pre/post connect operations * that the caller requires. * @see struct rdp_freerdp in freerdp.h * * @param instance - pointer to a rdp_freerdp structure that contains base information to establish the connection. * On return, this function will be initialized with the new connection's settings. * * @return TRUE if successful. FALSE otherwise. * */ BOOL freerdp_connect(freerdp* instance) { rdpRdp* rdp; rdpSettings* settings; BOOL status = FALSE; ConnectionResultEventArgs e; /* We always set the return code to 0 before we start the connect sequence*/ connectErrorCode = 0; rdp = instance->context->rdp; settings = instance->settings; IFCALLRET(instance->PreConnect, status, instance); if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) { settings->KeyboardType = 7; settings->KeyboardSubType = 2; settings->KeyboardFunctionKey = 12; } extension_load_and_init_plugins(rdp->extension); extension_pre_connect(rdp->extension); if (!status) { if (!connectErrorCode) { connectErrorCode = PREECONNECTERROR; } fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__); goto freerdp_connect_finally; } status = rdp_client_connect(rdp); /* --authonly tests the connection without a UI */ if (instance->settings->AuthenticationOnly) { fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status); goto freerdp_connect_finally; } if (status) { if (instance->settings->DumpRemoteFx) { instance->update->pcap_rfx = pcap_open(instance->settings->DumpRemoteFxFile, TRUE); if (instance->update->pcap_rfx) instance->update->dump_rfx = TRUE; } extension_post_connect(rdp->extension); IFCALLRET(instance->PostConnect, status, instance); update_post_connect(instance->update); if (!status) { fprintf(stderr, "freerdp_post_connect failed\n"); if (!connectErrorCode) { connectErrorCode = POSTCONNECTERROR; } goto freerdp_connect_finally; } if (instance->settings->PlayRemoteFx) { wStream* s; rdpUpdate* update; pcap_record record; update = instance->update; update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE); if (!update->pcap_rfx) { status = FALSE; goto freerdp_connect_finally; } else { update->play_rfx = TRUE; } while (pcap_has_next_record(update->pcap_rfx)) { pcap_get_next_record_header(update->pcap_rfx, &record); s = StreamPool_Take(rdp->transport->ReceivePool, record.length); record.data = Stream_Buffer(s); pcap_get_next_record_content(update->pcap_rfx, &record); Stream_SetLength(s,record.length); Stream_SetPosition(s, 0); update->BeginPaint(update->context); update_recv_surfcmds(update, Stream_Length(s) , s); update->EndPaint(update->context); Stream_Release(s); StreamPool_Return(rdp->transport->ReceivePool, s); } pcap_close(update->pcap_rfx); update->pcap_rfx = NULL; status = TRUE; goto freerdp_connect_finally; } } if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES) { connectErrorCode = INSUFFICIENTPRIVILEGESERROR; } if (!connectErrorCode) { connectErrorCode = UNDEFINEDCONNECTERROR; } SetEvent(rdp->transport->connectedEvent); freerdp_connect_finally: EventArgsInit(&e, "freerdp"); e.result = status ? 0 : -1; PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e); return status; }
int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) { BYTE type; wStream* cs; UINT16 length; UINT32 shareId; BYTE compressedType; UINT16 compressedLength; if (!rdp_read_share_data_header(s, &length, &type, &shareId, &compressedType, &compressedLength)) return -1; cs = s; if (compressedType & PACKET_COMPRESSED) { UINT32 DstSize = 0; BYTE* pDstData = NULL; UINT32 SrcSize = compressedLength - 18; if (Stream_GetRemainingLength(s) < (size_t) SrcSize) { DEBUG_WARN( "bulk_decompress: not enough bytes for compressedLength %d\n", compressedLength); return -1; } if (bulk_decompress(rdp->bulk, Stream_Pointer(s), SrcSize, &pDstData, &DstSize, compressedType)) { cs = StreamPool_Take(rdp->transport->ReceivePool, DstSize); Stream_SetPosition(cs, 0); Stream_Write(cs, pDstData, DstSize); Stream_SealLength(cs); Stream_SetPosition(cs, 0); } else { DEBUG_WARN( "bulk_decompress() failed\n"); return -1; } Stream_Seek(s, SrcSize); } #ifdef WITH_DEBUG_RDP DEBUG_MSG("recv %s Data PDU (0x%02X), length: %d\n", type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); #endif switch (type) { case DATA_PDU_TYPE_UPDATE: if (!update_recv(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_CONTROL: if (!rdp_recv_server_control_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_POINTER: if (!update_recv_pointer(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_SYNCHRONIZE: if (!rdp_recv_synchronize_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_PLAY_SOUND: if (!update_recv_play_sound(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_SHUTDOWN_DENIED: if (!rdp_recv_server_shutdown_denied_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SAVE_SESSION_INFO: if (!rdp_recv_save_session_info(rdp, cs)) return -1; break; case DATA_PDU_TYPE_FONT_MAP: if (!rdp_recv_font_map_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS: if (!rdp_recv_server_set_keyboard_indicators_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS: if (!rdp_recv_server_set_keyboard_ime_status_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_ERROR_INFO: if (!rdp_recv_set_error_info_data_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_ARC_STATUS: if (!rdp_recv_server_auto_reconnect_status_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_STATUS_INFO: if (!rdp_recv_server_status_info_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_MONITOR_LAYOUT: if (!rdp_recv_monitor_layout_pdu(rdp, cs)) return -1; break; default: break; } if (cs != s) Stream_Release(cs); return 0; }
rdpTransport* transport_new(rdpSettings* settings) { rdpTransport* transport; transport = (rdpTransport *)calloc(1, sizeof(rdpTransport)); if (!transport) return NULL; WLog_Init(); transport->log = WLog_Get("com.freerdp.core.transport"); if (!transport->log) goto out_free; transport->TcpIn = tcp_new(settings); if (!transport->TcpIn) goto out_free; transport->settings = settings; /* a small 0.1ms delay when transport is blocking. */ transport->SleepInterval = 100; transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE); if (!transport->ReceivePool) goto out_free_tcpin; /* receive buffer for non-blocking read. */ transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); if (!transport->ReceiveBuffer) goto out_free_receivepool; transport->ReceiveEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!transport->ReceiveEvent || transport->ReceiveEvent == INVALID_HANDLE_VALUE) goto out_free_receivebuffer; transport->connectedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!transport->connectedEvent || transport->connectedEvent == INVALID_HANDLE_VALUE) goto out_free_receiveEvent; transport->blocking = TRUE; transport->GatewayEnabled = FALSE; transport->layer = TRANSPORT_LAYER_TCP; if (!InitializeCriticalSectionAndSpinCount(&(transport->ReadLock), 4000)) goto out_free_connectedEvent; if (!InitializeCriticalSectionAndSpinCount(&(transport->WriteLock), 4000)) goto out_free_readlock; return transport; out_free_readlock: DeleteCriticalSection(&(transport->ReadLock)); out_free_connectedEvent: CloseHandle(transport->connectedEvent); out_free_receiveEvent: CloseHandle(transport->ReceiveEvent); out_free_receivebuffer: StreamPool_Return(transport->ReceivePool, transport->ReceiveBuffer); out_free_receivepool: StreamPool_Free(transport->ReceivePool); out_free_tcpin: tcp_free(transport->TcpIn); out_free: free(transport); return NULL; }
int transport_check_fds(rdpTransport* transport) { int status; int recv_status; wStream* received; if (!transport) return -1; #ifdef _WIN32 WSAResetEvent(transport->TcpIn->wsa_event); #endif ResetEvent(transport->ReceiveEvent); /** * Loop through and read all available PDUs. Since multiple * PDUs can exist, it's important to deliver them all before * returning. Otherwise we run the risk of having a thread * wait for a socket to get signaled that data is available * (which may never happen). */ for (;;) { /** * Note: transport_read_pdu tries to read one PDU from * the transport layer. * The ReceiveBuffer might have a position > 0 in case of a non blocking * transport. If transport_read_pdu returns 0 the pdu couldn't be read at * this point. * Note that transport->ReceiveBuffer is replaced after each iteration * of this loop with a fresh stream instance from a pool. */ if ((status = transport_read_pdu(transport, transport->ReceiveBuffer)) <= 0) { return status; } received = transport->ReceiveBuffer; transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); /** * status: * -1: error * 0: success * 1: redirection */ recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); if (recv_status == 1) { return 1; /* session redirection */ } Stream_Release(received); if (recv_status < 0) return -1; } return 0; }
int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) { BYTE type; UINT32 roff; UINT32 rlen; wStream* cs; BYTE* buffer; UINT16 length; UINT32 share_id; BYTE compressed_type; UINT16 compressed_len; if (!rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len)) return -1; cs = s; if (compressed_type & PACKET_COMPRESSED) { if (Stream_GetRemainingLength(s) < compressed_len - 18) { fprintf(stderr, "decompress_rdp: not enough bytes for compressed_len=%d\n", compressed_len); return -1; } if (decompress_rdp(rdp->mppc_dec, Stream_Pointer(s), compressed_len - 18, compressed_type, &roff, &rlen)) { buffer = rdp->mppc_dec->history_buf + roff; cs = StreamPool_Take(rdp->transport->ReceivePool, rlen); Stream_SetPosition(cs, 0); Stream_Write(cs, buffer, rlen); Stream_SealLength(cs); Stream_SetPosition(cs, 0); } else { fprintf(stderr, "decompress_rdp() failed\n"); return -1; } Stream_Seek(s, compressed_len - 18); } #ifdef WITH_DEBUG_RDP /* if (type != DATA_PDU_TYPE_UPDATE) */ DEBUG_RDP("recv %s Data PDU (0x%02X), length:%d", type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); #endif switch (type) { case DATA_PDU_TYPE_UPDATE: if (!update_recv(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_CONTROL: if (!rdp_recv_server_control_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_POINTER: if (!update_recv_pointer(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_INPUT: break; case DATA_PDU_TYPE_SYNCHRONIZE: if (!rdp_recv_synchronize_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_REFRESH_RECT: break; case DATA_PDU_TYPE_PLAY_SOUND: if (!update_recv_play_sound(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_SUPPRESS_OUTPUT: break; case DATA_PDU_TYPE_SHUTDOWN_REQUEST: break; case DATA_PDU_TYPE_SHUTDOWN_DENIED: break; case DATA_PDU_TYPE_SAVE_SESSION_INFO: if (!rdp_recv_save_session_info(rdp, cs)) return -1; break; case DATA_PDU_TYPE_FONT_LIST: break; case DATA_PDU_TYPE_FONT_MAP: if (!rdp_recv_font_map_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS: break; case DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST: break; case DATA_PDU_TYPE_BITMAP_CACHE_ERROR: break; case DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS: break; case DATA_PDU_TYPE_OFFSCREEN_CACHE_ERROR: break; case DATA_PDU_TYPE_SET_ERROR_INFO: if (!rdp_recv_set_error_info_data_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_DRAW_NINEGRID_ERROR: break; case DATA_PDU_TYPE_DRAW_GDIPLUS_ERROR: break; case DATA_PDU_TYPE_ARC_STATUS: break; case DATA_PDU_TYPE_STATUS_INFO: break; case DATA_PDU_TYPE_MONITOR_LAYOUT: break; default: break; } if (cs != s) Stream_Release(cs); return 0; }
/** Creates a new connection based on the settings found in the "instance" parameter * It will use the callbacks registered on the structure to process the pre/post connect operations * that the caller requires. * @see struct rdp_freerdp in freerdp.h * * @param instance - pointer to a rdp_freerdp structure that contains base information to establish the connection. * On return, this function will be initialized with the new connection's settings. * * @return TRUE if successful. FALSE otherwise. * */ BOOL freerdp_connect(freerdp* instance) { rdpRdp* rdp; BOOL status = TRUE; rdpSettings* settings; ConnectionResultEventArgs e; /* We always set the return code to 0 before we start the connect sequence*/ connectErrorCode = 0; freerdp_set_last_error(instance->context, FREERDP_ERROR_SUCCESS); rdp = instance->context->rdp; settings = instance->settings; instance->context->codecs = codecs_new(instance->context); IFCALLRET(instance->PreConnect, status, instance); if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) { settings->KeyboardType = 7; settings->KeyboardSubType = 2; settings->KeyboardFunctionKey = 12; } if (!status) { if (!freerdp_get_last_error(rdp->context)) freerdp_set_last_error(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED); WLog_ERR(TAG, "freerdp_pre_connect failed"); goto freerdp_connect_finally; } status = rdp_client_connect(rdp); /* --authonly tests the connection without a UI */ if (instance->settings->AuthenticationOnly) { WLog_ERR(TAG, "Authentication only, exit status %d", !status); goto freerdp_connect_finally; } if (status) { if (instance->settings->DumpRemoteFx) { instance->update->pcap_rfx = pcap_open(instance->settings->DumpRemoteFxFile, TRUE); if (instance->update->pcap_rfx) instance->update->dump_rfx = TRUE; } IFCALLRET(instance->PostConnect, status, instance); if (!status || !update_post_connect(instance->update)) { WLog_ERR(TAG, "freerdp_post_connect failed"); if (!freerdp_get_last_error(rdp->context)) freerdp_set_last_error(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED); goto freerdp_connect_finally; } if (instance->settings->PlayRemoteFx) { wStream* s; rdpUpdate* update; pcap_record record; update = instance->update; update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE); if (!update->pcap_rfx) { status = FALSE; goto freerdp_connect_finally; } else { update->play_rfx = TRUE; } while (pcap_has_next_record(update->pcap_rfx)) { pcap_get_next_record_header(update->pcap_rfx, &record); if (!(s = StreamPool_Take(rdp->transport->ReceivePool, record.length))) break; record.data = Stream_Buffer(s); pcap_get_next_record_content(update->pcap_rfx, &record); Stream_SetLength(s,record.length); Stream_SetPosition(s, 0); update->BeginPaint(update->context); update_recv_surfcmds(update, Stream_Length(s) , s); update->EndPaint(update->context); Stream_Release(s); } pcap_close(update->pcap_rfx); update->pcap_rfx = NULL; status = TRUE; goto freerdp_connect_finally; } } if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES) freerdp_set_last_error(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES); SetEvent(rdp->transport->connectedEvent); freerdp_connect_finally: EventArgsInit(&e, "freerdp"); e.result = status ? 0 : -1; PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e); return status; }
int transport_check_fds(rdpTransport* transport) { int status; int recv_status; wStream* received; DWORD now = GetTickCount(); DWORD dueDate = 0; if (!transport) return -1; dueDate = now + transport->settings->MaxTimeInCheckLoop; if (transport->haveMoreBytesToRead) { transport->haveMoreBytesToRead = FALSE; ResetEvent(transport->rereadEvent); } while (now < dueDate) { if (freerdp_shall_disconnect(transport->context->instance)) { return -1; } /** * Note: transport_read_pdu tries to read one PDU from * the transport layer. * The ReceiveBuffer might have a position > 0 in case of a non blocking * transport. If transport_read_pdu returns 0 the pdu couldn't be read at * this point. * Note that transport->ReceiveBuffer is replaced after each iteration * of this loop with a fresh stream instance from a pool. */ if ((status = transport_read_pdu(transport, transport->ReceiveBuffer)) <= 0) { if (status < 0) WLog_Print(transport->log, WLOG_DEBUG, "transport_check_fds: transport_read_pdu() - %i", status); return status; } received = transport->ReceiveBuffer; if (!(transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0))) return -1; /** * status: * -1: error * 0: success * 1: redirection */ recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); Stream_Release(received); /* session redirection or activation */ if (recv_status == 1 || recv_status == 2) { return recv_status; } if (recv_status < 0) { WLog_Print(transport->log, WLOG_ERROR, "transport_check_fds: transport->ReceiveCallback() - %i", recv_status); return -1; } now = GetTickCount(); } if (now >= dueDate) { SetEvent(transport->rereadEvent); transport->haveMoreBytesToRead = TRUE; } return 0; }
int transport_check_fds(rdpTransport* transport) { int pos; int status; UINT16 length; int recv_status; wStream* received; if (!transport) return -1; #ifdef _WIN32 WSAResetEvent(transport->TcpIn->wsa_event); #endif ResetEvent(transport->ReceiveEvent); status = transport_read_nonblocking(transport); if (status < 0) return status; while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0) { Stream_SetPosition(transport->ReceiveBuffer, 0); if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */ { /* Ensure the TPKT header is available. */ if (pos <= 4) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } length = tpkt_read_header(transport->ReceiveBuffer); } else if (nla_verify_header(transport->ReceiveBuffer)) { /* TSRequest */ /* Ensure the TSRequest header is available. */ if (pos <= 4) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } /* TSRequest header can be 2, 3 or 4 bytes long */ length = nla_header_length(transport->ReceiveBuffer); if (pos < length) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } length = nla_read_header(transport->ReceiveBuffer); } else /* Fast Path */ { /* Ensure the Fast Path header is available. */ if (pos <= 2) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } /* Fastpath header can be two or three bytes long. */ length = fastpath_header_length(transport->ReceiveBuffer); if (pos < length) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } length = fastpath_read_header(NULL, transport->ReceiveBuffer); } if (length == 0) { fprintf(stderr, "transport_check_fds: protocol error, not a TPKT or Fast Path header.\n"); winpr_HexDump(Stream_Buffer(transport->ReceiveBuffer), pos); return -1; } if (pos < length) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; /* Packet is not yet completely received. */ } received = transport->ReceiveBuffer; transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); Stream_SetPosition(received, length); Stream_SealLength(received); Stream_SetPosition(received, 0); /** * status: * -1: error * 0: success * 1: redirection */ recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); if (recv_status == 1) { /** * Last call to ReceiveCallback resulted in a session redirection, * which means the current rdpTransport* transport pointer has been freed. * Return 0 for success, the rest of this function is meant for non-redirected cases. */ return 0; } Stream_Release(received); if (recv_status < 0) status = -1; if (status < 0) return status; } return 0; }
int transport_check_fds(rdpTransport** ptransport) { int pos; int status; UINT16 length; int recv_status; wStream* received; rdpTransport* transport = *ptransport; #ifdef _WIN32 WSAResetEvent(transport->TcpIn->wsa_event); #endif ResetEvent(transport->ReceiveEvent); status = transport_read_nonblocking(transport); if (status < 0) return status; while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0) { Stream_SetPosition(transport->ReceiveBuffer, 0); if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */ { /* Ensure the TPKT header is available. */ if (pos <= 4) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } length = tpkt_read_header(transport->ReceiveBuffer); } else if (nla_verify_header(transport->ReceiveBuffer)) { /* TSRequest */ /* Ensure the TSRequest header is available. */ if (pos <= 4) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } /* TSRequest header can be 2, 3 or 4 bytes long */ length = nla_header_length(transport->ReceiveBuffer); if (pos < length) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } length = nla_read_header(transport->ReceiveBuffer); } else /* Fast Path */ { /* Ensure the Fast Path header is available. */ if (pos <= 2) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } /* Fastpath header can be two or three bytes long. */ length = fastpath_header_length(transport->ReceiveBuffer); if (pos < length) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; } length = fastpath_read_header(NULL, transport->ReceiveBuffer); } if (length == 0) { fprintf(stderr, "transport_check_fds: protocol error, not a TPKT or Fast Path header.\n"); winpr_HexDump(Stream_Buffer(transport->ReceiveBuffer), pos); return -1; } if (pos < length) { Stream_SetPosition(transport->ReceiveBuffer, pos); return 0; /* Packet is not yet completely received. */ } received = transport->ReceiveBuffer; transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); Stream_SetPosition(received, length); Stream_SealLength(received); Stream_SetPosition(received, 0); recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); if (transport == *ptransport) /* transport might now have been freed by rdp_client_redirect and a new rdp->transport created */ /* so only release if still valid */ Stream_Release(received); if (recv_status < 0) status = -1; if (status < 0) return status; /* transport might now have been freed by rdp_client_redirect and a new rdp->transport created */ transport = *ptransport; } return 0; }