Merge pull request #2403 from awakecoding/master

Transport, Gateway, Sockets
This commit is contained in:
Marc-André Moreau 2015-02-18 13:56:25 -05:00
commit 3f371b22ad
31 changed files with 2452 additions and 2098 deletions

View File

@ -173,6 +173,8 @@ int tfreerdp_run(freerdp* instance)
FD_ZERO(&rfds_set);
FD_ZERO(&wfds_set);
fprintf(stderr, "rcount: %d\n", rcount);
for (i = 0; i < rcount; i++)
{
fds = (int)(long)(rfds[i]);
@ -237,7 +239,11 @@ void* tf_client_thread_proc(freerdp* instance)
channels = instance->context->channels;
freerdp_connect(instance);
if (!freerdp_connect(instance))
{
WLog_ERR(TAG, "connection failure");
return NULL;
}
while (1)
{

View File

@ -30,7 +30,6 @@ int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* re
{
int count;
int index;
int status = 1;
xfGfxSurface* surface;
UINT16* pSurfaceIds = NULL;
xfContext* xfc = (xfContext*) context->custom;

View File

@ -248,7 +248,7 @@ FREERDP_API BOOL freerdp_reconnect(freerdp* instance);
FREERDP_API BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount);
FREERDP_API BOOL freerdp_check_fds(freerdp* instance);
FREERDP_API DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events);
FREERDP_API UINT32 freerdp_get_event_handles(rdpContext* context, HANDLE* events);
FREERDP_API BOOL freerdp_check_event_handles(rdpContext* context);
FREERDP_API wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id);

View File

@ -263,12 +263,12 @@ BOOL rdp_client_connect(rdpRdp* rdp)
return FALSE;
}
rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO);
if (!nego_connect(rdp->nego))
{
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(rdp->context, FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED);
}
WLog_ERR(TAG, "Error: protocol security negotiation or connection failure");
return FALSE;
@ -281,25 +281,16 @@ BOOL rdp_client_connect(rdpRdp* rdp)
settings->AutoLogonEnabled = TRUE;
}
rdp_set_blocking_mode(rdp, FALSE);
/* everything beyond this point is event-driven and non blocking */
rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO);
rdp->finalize_sc_pdus = 0;
rdp->transport->ReceiveCallback = rdp_recv_callback;
rdp->transport->ReceiveExtra = rdp;
transport_set_blocking_mode(rdp->transport, FALSE);
if (!mcs_send_connect_initial(rdp->mcs))
if (rdp->state != CONNECTION_STATE_NLA)
{
if (!connectErrorCode)
{
connectErrorCode = MCSCONNECTINITIALERROR;
}
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(rdp->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
}
WLog_ERR(TAG, "Error: unable to send MCS Connect Initial");
return FALSE;
if (!mcs_client_begin(rdp->mcs))
return FALSE;
}
while (rdp->state != CONNECTION_STATE_ACTIVE)
@ -307,9 +298,7 @@ BOOL rdp_client_connect(rdpRdp* rdp)
if (rdp_check_fds(rdp) < 0)
{
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(rdp->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
}
return FALSE;
}
@ -648,38 +637,6 @@ end2:
return ret;
}
BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s)
{
if (!mcs_recv_connect_response(rdp->mcs, s))
{
WLog_ERR(TAG, "rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed");
return FALSE;
}
if (!mcs_send_erect_domain_request(rdp->mcs))
return FALSE;
if (!mcs_send_attach_user_request(rdp->mcs))
return FALSE;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
return TRUE;
}
BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s)
{
if (!mcs_recv_attach_user_confirm(rdp->mcs, s))
return FALSE;
if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->userId))
return FALSE;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN);
return TRUE;
}
BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s)
{
UINT32 i;
@ -925,6 +882,10 @@ int rdp_client_transition_to_state(rdpRdp* rdp, int state)
rdp->state = CONNECTION_STATE_NEGO;
break;
case CONNECTION_STATE_NLA:
rdp->state = CONNECTION_STATE_NLA;
break;
case CONNECTION_STATE_MCS_CONNECT:
rdp->state = CONNECTION_STATE_MCS_CONNECT;
break;

View File

@ -31,28 +31,27 @@
enum CONNECTION_STATE
{
CONNECTION_STATE_INITIAL = 0,
CONNECTION_STATE_NEGO = 1,
CONNECTION_STATE_MCS_CONNECT = 2,
CONNECTION_STATE_MCS_ERECT_DOMAIN = 3,
CONNECTION_STATE_MCS_ATTACH_USER = 4,
CONNECTION_STATE_MCS_CHANNEL_JOIN = 5,
CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT = 6,
CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE = 7,
CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT = 8,
CONNECTION_STATE_LICENSING = 9,
CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING = 10,
CONNECTION_STATE_CAPABILITIES_EXCHANGE = 11,
CONNECTION_STATE_FINALIZATION = 12,
CONNECTION_STATE_ACTIVE = 13
CONNECTION_STATE_INITIAL,
CONNECTION_STATE_NEGO,
CONNECTION_STATE_NLA,
CONNECTION_STATE_MCS_CONNECT,
CONNECTION_STATE_MCS_ERECT_DOMAIN,
CONNECTION_STATE_MCS_ATTACH_USER,
CONNECTION_STATE_MCS_CHANNEL_JOIN,
CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT,
CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE,
CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT,
CONNECTION_STATE_LICENSING,
CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING,
CONNECTION_STATE_CAPABILITIES_EXCHANGE,
CONNECTION_STATE_FINALIZATION,
CONNECTION_STATE_ACTIVE
};
BOOL rdp_client_connect(rdpRdp* rdp);
BOOL rdp_client_disconnect(rdpRdp* rdp);
BOOL rdp_client_reconnect(rdpRdp* rdp);
BOOL rdp_client_redirect(rdpRdp* rdp);
BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s);
int rdp_client_connect_license(rdpRdp* rdp, wStream* s);

View File

@ -84,17 +84,10 @@ BOOL freerdp_connect(freerdp* instance)
if (!status)
{
if (!connectErrorCode)
{
connectErrorCode = PREECONNECTERROR;
}
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");
WLog_ERR(TAG, "freerdp_pre_connect failed");
goto freerdp_connect_finally;
}
@ -103,7 +96,7 @@ BOOL freerdp_connect(freerdp* instance)
/* --authonly tests the connection without a UI */
if (instance->settings->AuthenticationOnly)
{
WLog_ERR(TAG, "Authentication only, exit status %d", !status);
WLog_ERR(TAG, "Authentication only, exit status %d", !status);
goto freerdp_connect_finally;
}
@ -122,17 +115,10 @@ BOOL freerdp_connect(freerdp* instance)
if (!status)
{
WLog_ERR(TAG, "freerdp_post_connect failed");
if (!connectErrorCode)
{
connectErrorCode = POSTCONNECTERROR;
}
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;
}
@ -183,10 +169,7 @@ BOOL freerdp_connect(freerdp* instance)
}
if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
{
connectErrorCode = INSUFFICIENTPRIVILEGESERROR;
freerdp_set_last_error(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
}
SetEvent(rdp->transport->connectedEvent);
freerdp_connect_finally:
@ -199,11 +182,8 @@ freerdp_connect_finally:
BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
{
rdpRdp* rdp;
rdp = instance->context->rdp;
rdpRdp* rdp = instance->context->rdp;
transport_get_fds(rdp->transport, rfds, rcount);
return TRUE;
}
@ -240,9 +220,9 @@ BOOL freerdp_check_fds(freerdp* instance)
return TRUE;
}
DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events)
UINT32 freerdp_get_event_handles(rdpContext* context, HANDLE* events)
{
DWORD nCount = 0;
UINT32 nCount = 0;
nCount += transport_get_event_handles(context->rdp->transport, events);
@ -534,9 +514,64 @@ UINT32 freerdp_get_last_error(rdpContext* context)
void freerdp_set_last_error(rdpContext* context, UINT32 lastError)
{
if (lastError)
WLog_ERR(TAG, "freerdp_set_last_error 0x%04X", lastError);
WLog_ERR(TAG, "freerdp_set_last_error 0x%04X", lastError);
context->LastError = lastError;
switch (lastError)
{
case FREERDP_ERROR_PRE_CONNECT_FAILED:
connectErrorCode = PREECONNECTERROR;
break;
case FREERDP_ERROR_CONNECT_UNDEFINED:
connectErrorCode = UNDEFINEDCONNECTERROR;
break;
case FREERDP_ERROR_POST_CONNECT_FAILED:
connectErrorCode = POSTCONNECTERROR;
break;
case FREERDP_ERROR_DNS_ERROR:
connectErrorCode = DNSERROR;
break;
case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
connectErrorCode = DNSNAMENOTFOUND;
break;
case FREERDP_ERROR_CONNECT_FAILED:
connectErrorCode = CONNECTERROR;
break;
case FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR:
connectErrorCode = MCSCONNECTINITIALERROR;
break;
case FREERDP_ERROR_TLS_CONNECT_FAILED:
connectErrorCode = TLSCONNECTERROR;
break;
case FREERDP_ERROR_AUTHENTICATION_FAILED:
connectErrorCode = AUTHENTICATIONERROR;
break;
case FREERDP_ERROR_INSUFFICIENT_PRIVILEGES:
connectErrorCode = INSUFFICIENTPRIVILEGESERROR;
break;
case FREERDP_ERROR_CONNECT_CANCELLED:
connectErrorCode = CANCELEDBYUSER;
break;
case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
connectErrorCode = CONNECTERROR;
break;
case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
connectErrorCode = CONNECTERROR;
break;
}
}
/** Allocator function for the rdp_freerdp structure.

View File

@ -132,7 +132,6 @@ int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, RpcChannel* channel)
if (!proceed)
{
connectErrorCode = CANCELEDBYUSER;
freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
return 0;
}

View File

@ -506,6 +506,18 @@ void rpc_in_channel_free(RpcInChannel* inChannel)
rpc_in_channel_rpch_uninit(inChannel);
if (inChannel->tls)
{
tls_free(inChannel->tls);
inChannel->tls = NULL;
}
if (inChannel->bio)
{
BIO_free(inChannel->bio);
inChannel->bio = NULL;
}
free(inChannel);
}
@ -645,6 +657,18 @@ void rpc_out_channel_free(RpcOutChannel* outChannel)
rpc_out_channel_rpch_uninit(outChannel);
if (outChannel->tls)
{
tls_free(outChannel->tls);
outChannel->tls = NULL;
}
if (outChannel->bio)
{
BIO_free(outChannel->bio);
outChannel->bio = NULL;
}
free(outChannel);
}
@ -735,21 +759,39 @@ void rpc_virtual_connection_free(RpcVirtualConnection* connection)
int rpc_channel_tls_connect(RpcChannel* channel, int timeout)
{
rdpTcp* tcp;
int sockfd;
rdpTls* tls;
int tlsStatus;
BIO* socketBio;
BIO* bufferedBio;
rdpRpc* rpc = channel->rpc;
rdpContext* context = rpc->context;
rdpSettings* settings = context->settings;
tcp = channel->tcp = freerdp_tcp_new(settings);
sockfd = freerdp_tcp_connect(settings, settings->GatewayHostname, settings->GatewayPort, timeout);
if (!freerdp_tcp_connect(tcp, settings->GatewayHostname, settings->GatewayPort, timeout))
if (sockfd < 1)
return -1;
if (!freerdp_tcp_set_blocking_mode(tcp, FALSE))
socketBio = BIO_new(BIO_s_simple_socket());
if (!socketBio)
return FALSE;
BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
bufferedBio = BIO_new(BIO_s_buffered_socket());
if (!bufferedBio)
return FALSE;
bufferedBio = BIO_push(bufferedBio, socketBio);
if (!BIO_set_nonblock(bufferedBio, TRUE))
return -1;
channel->bio = bufferedBio;
tls = channel->tls = tls_new(settings);
if (!tls)
@ -759,7 +801,7 @@ int rpc_channel_tls_connect(RpcChannel* channel, int timeout)
tls->port = settings->GatewayPort;
tls->isGatewayTransport = TRUE;
tlsStatus = tls_connect(tls, tcp->bufferedBio);
tlsStatus = tls_connect(tls, bufferedBio);
if (tlsStatus < 1)
{

View File

@ -586,7 +586,7 @@ typedef struct rpc_client_call RpcClientCall;
#define RPC_CHANNEL_COMMON() \
rdpRpc* rpc; \
rdpTcp* tcp; \
BIO* bio; \
rdpTls* tls; \
rdpNtlm* ntlm; \
HttpContext* http; \

View File

@ -143,7 +143,6 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
if (!proceed)
{
connectErrorCode = CANCELEDBYUSER;
freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
return 0;
}

View File

@ -280,15 +280,12 @@ int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_CONTEXT_NEGOTIATED);
if (!TsProxyCreateTunnel(tsg, NULL, NULL, NULL, NULL))
if (tsg_proxy_begin(tsg) < 0)
{
WLog_ERR(TAG, "TsProxyCreateTunnel failure");
tsg->state = TSG_STATE_FINAL;
WLog_ERR(TAG, "tsg_proxy_begin failure");
return -1;
}
tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
status = 1;
}
else
@ -298,10 +295,7 @@ int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
}
else if (rpc->State >= RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
{
if (tsg->state != TSG_STATE_PIPE_CREATED)
{
status = tsg_recv_pdu(tsg, pdu);
}
status = tsg_recv_pdu(tsg, pdu);
}
return status;
@ -531,13 +525,8 @@ int rpc_client_out_channel_recv(rdpRpc* rpc)
if (response->StatusCode == HTTP_STATUS_DENIED)
{
if (!connectErrorCode)
connectErrorCode = AUTHENTICATIONERROR;
if (!freerdp_get_last_error(rpc->context))
{
freerdp_set_last_error(rpc->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
}
}
return -1;

File diff suppressed because it is too large Load Diff

View File

@ -53,20 +53,6 @@ enum _TSG_STATE
};
typedef enum _TSG_STATE TSG_STATE;
struct rdp_tsg
{
BIO* bio;
rdpRpc* rpc;
UINT16 Port;
LPWSTR Hostname;
LPWSTR MachineName;
TSG_STATE state;
rdpSettings* settings;
rdpTransport* transport;
CONTEXT_HANDLE TunnelContext;
CONTEXT_HANDLE ChannelContext;
};
typedef WCHAR* RESOURCENAME;
#define TsProxyCreateTunnelOpnum 1
@ -299,8 +285,31 @@ typedef struct _TSG_PACKET
TSG_PACKET_TYPE_UNION tsgPacket;
} TSG_PACKET, *PTSG_PACKET;
BOOL TsProxyCreateTunnel(rdpTsg* tsg, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse,
PTUNNEL_CONTEXT_HANDLE_SERIALIZE* tunnelContext, UINT32* tunnelId);
struct rdp_tsg
{
BIO* bio;
rdpRpc* rpc;
UINT16 Port;
LPWSTR Hostname;
LPWSTR MachineName;
TSG_STATE state;
UINT32 TunnelId;
UINT32 ChannelId;
BOOL reauthSequence;
rdpSettings* settings;
rdpTransport* transport;
UINT64 ReauthTunnelContext;
CONTEXT_HANDLE TunnelContext;
CONTEXT_HANDLE ChannelContext;
CONTEXT_HANDLE NewTunnelContext;
CONTEXT_HANDLE NewChannelContext;
TSG_PACKET_REAUTH packetReauth;
TSG_PACKET_CAPABILITIES tsgCaps;
TSG_PACKET_VERSIONCAPS packetVersionCaps;
};
int tsg_proxy_begin(rdpTsg* tsg);
int tsg_proxy_reauth(rdpTsg* tsg);
DWORD TsProxySendToServer(handle_t IDL_handle, BYTE pRpcMessage[], UINT32 count, UINT32* lengths);
@ -313,7 +322,9 @@ int tsg_write(rdpTsg* tsg, BYTE* data, UINT32 length);
int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length);
int tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu);
int tsg_check(rdpTsg* tsg);
int tsg_check_event_handles(rdpTsg* tsg);
UINT32 tsg_get_event_handles(rdpTsg* tsg, HANDLE* events);
rdpTsg* tsg_new(rdpTransport* transport);
void tsg_free(rdpTsg* tsg);

View File

@ -39,8 +39,6 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
#else
#define close(_fd) closesocket(_fd)
#endif
#include "listener.h"
@ -144,26 +142,20 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a
ioctlsocket(sockfd, FIONBIO, &arg);
#endif
status = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
status = _bind((SOCKET) sockfd, ai->ai_addr, ai->ai_addrlen);
if (status != 0)
{
#ifdef _WIN32
WLog_ERR(TAG, "bind() failed with error: %d", (int) WSAGetLastError());
WSACleanup();
#else
WLog_ERR(TAG, "bind");
close(sockfd);
#endif
closesocket((SOCKET) sockfd);
continue;
}
status = listen(sockfd, 10);
status = _listen((SOCKET) sockfd, 10);
if (status != 0)
{
WLog_ERR(TAG, "listen");
close(sockfd);
closesocket((SOCKET) sockfd);
continue;
}
@ -203,28 +195,28 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char*
strncpy(addr.sun_path, path, sizeof(addr.sun_path));
unlink(path);
status = bind(sockfd, (struct sockaddr*) &addr, sizeof(addr));
status = _bind(sockfd, (struct sockaddr*) &addr, sizeof(addr));
if (status != 0)
{
WLog_ERR(TAG, "bind");
close(sockfd);
closesocket((SOCKET) sockfd);
return FALSE;
}
status = listen(sockfd, 10);
status = _listen(sockfd, 10);
if (status != 0)
{
WLog_ERR(TAG, "listen");
close(sockfd);
closesocket((SOCKET) sockfd);
return FALSE;
}
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd);
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
return TRUE;
#else
return TRUE;
@ -239,7 +231,7 @@ static void freerdp_listener_close(freerdp_listener* instance)
for (i = 0; i < listener->num_sockfds; i++)
{
close(listener->sockfds[i]);
closesocket((SOCKET) listener->sockfds[i]);
CloseHandle(listener->events[i]);
}

View File

@ -30,6 +30,7 @@
#include "tpdu.h"
#include "tpkt.h"
#include "client.h"
#include "connection.h"
#define TAG FREERDP_TAG("core")
@ -1049,6 +1050,23 @@ BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs)
return (status < 0) ? FALSE : TRUE;
}
BOOL mcs_client_begin(rdpMcs* mcs)
{
rdpContext* context = mcs->transport->context;
if (!mcs_send_connect_initial(mcs))
{
if (!freerdp_get_last_error(context))
freerdp_set_last_error(context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
WLog_ERR(TAG, "Error: unable to send MCS Connect Initial");
return FALSE;
}
rdp_client_transition_to_state(context->rdp, CONNECTION_STATE_MCS_CONNECT);
return TRUE;
}
/**
* Instantiate new MCS module.
* @param transport transport

View File

@ -186,6 +186,8 @@ BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs);
BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU, UINT16* length);
void mcs_write_domain_mcspdu_header(wStream* s, enum DomainMCSPDU domainMCSPDU, UINT16 length, BYTE options);
BOOL mcs_client_begin(rdpMcs* mcs);
rdpMcs* mcs_new(rdpTransport* transport);
void mcs_free(rdpMcs* mcs);

View File

@ -1033,8 +1033,6 @@ void nego_init(rdpNego* nego)
{
nego->state = NEGO_STATE_INITIAL;
nego->RequestedProtocols = PROTOCOL_RDP;
nego->transport->ReceiveCallback = nego_recv;
nego->transport->ReceiveExtra = (void*) nego;
nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH;
nego->sendNegoData = FALSE;
nego->flags = 0;
@ -1049,11 +1047,12 @@ void nego_init(rdpNego* nego)
rdpNego* nego_new(rdpTransport* transport)
{
rdpNego* nego = (rdpNego*) calloc(1, sizeof(rdpNego));
if (!nego)
return NULL;
nego->transport = transport;
nego_init(nego);
return nego;

File diff suppressed because it is too large Load Diff

View File

@ -17,10 +17,10 @@
* limitations under the License.
*/
#ifndef FREERDP_CORE_CREDSSP_H
#define FREERDP_CORE_CREDSSP_H
#ifndef FREERDP_CORE_NLA_H
#define FREERDP_CORE_NLA_H
typedef struct rdp_credssp rdpCredssp;
typedef struct rdp_nla rdpNla;
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
@ -35,32 +35,60 @@ typedef struct rdp_credssp rdpCredssp;
#include "transport.h"
struct rdp_credssp
enum _NLA_STATE
{
NLA_STATE_INITIAL,
NLA_STATE_NEGO_TOKEN,
NLA_STATE_PUB_KEY_AUTH,
NLA_STATE_AUTH_INFO,
NLA_STATE_FINAL
};
typedef enum _NLA_STATE NLA_STATE;
struct rdp_nla
{
BOOL server;
int send_seq_num;
int recv_seq_num;
NLA_STATE state;
int sendSeqNum;
int recvSeqNum;
freerdp* instance;
CtxtHandle context;
LPTSTR SspiModule;
rdpSettings* settings;
rdpTransport* transport;
UINT32 cbMaxToken;
ULONG fContextReq;
ULONG pfContextAttr;
BOOL haveContext;
BOOL haveInputBuffer;
BOOL havePubKeyAuth;
SECURITY_STATUS status;
CredHandle credentials;
TimeStamp expiration;
PSecPkgInfo pPackageInfo;
SecBuffer inputBuffer;
SecBuffer outputBuffer;
SecBufferDesc inputBufferDesc;
SecBufferDesc outputBufferDesc;
SecBuffer negoToken;
SecBuffer pubKeyAuth;
SecBuffer authInfo;
SecBuffer PublicKey;
SecBuffer ts_credentials;
CryptoRc4 rc4_seal_state;
SecBuffer tsCredentials;
CryptoRc4 rc4SealState;
LPTSTR ServicePrincipalName;
SEC_WINNT_AUTH_IDENTITY identity;
PSecurityFunctionTable table;
SecPkgContext_Sizes ContextSizes;
};
int credssp_authenticate(rdpCredssp* credssp);
LPTSTR credssp_make_spn(const char* ServiceClass, const char* hostname);
int nla_authenticate(rdpNla* nla);
LPTSTR nla_make_spn(const char* ServiceClass, const char* hostname);
rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings);
void credssp_free(rdpCredssp* credssp);
int nla_client_begin(rdpNla* nla);
int nla_recv_pdu(rdpNla* nla, wStream* s);
#endif /* FREERDP_CORE_CREDSSP_H */
rdpNla* nla_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings);
void nla_free(rdpNla* nla);
#endif /* FREERDP_CORE_NLA_H */

View File

@ -229,7 +229,9 @@ static BOOL freerdp_peer_initialize(freerdp_peer* client)
static BOOL freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount)
{
rfds[*rcount] = (void*)(long)(client->context->rdp->transport->TcpIn->sockfd);
rdpTransport* transport = client->context->rdp->transport;
rfds[*rcount] = (void*)(long)(BIO_get_fd(transport->frontBio, NULL));
(*rcount)++;
return TRUE;
@ -237,7 +239,12 @@ static BOOL freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount)
static HANDLE freerdp_peer_get_event_handle(freerdp_peer* client)
{
return client->context->rdp->transport->TcpIn->event;
HANDLE hEvent = NULL;
rdpTransport* transport = client->context->rdp->transport;
BIO_get_event(transport->frontBio, &hEvent);
return hEvent;
}
static BOOL freerdp_peer_check_fds(freerdp_peer* peer)
@ -453,10 +460,10 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra)
if (rdp->nego->SelectedProtocol & PROTOCOL_NLA)
{
sspi_CopyAuthIdentity(&client->identity, &(rdp->nego->transport->credssp->identity));
sspi_CopyAuthIdentity(&client->identity, &(rdp->nego->transport->nla->identity));
IFCALLRET(client->Logon, client->authenticated, client, &client->identity, TRUE);
credssp_free(rdp->nego->transport->credssp);
rdp->nego->transport->credssp = NULL;
nla_free(rdp->nego->transport->nla);
rdp->nego->transport->nla = NULL;
}
else
{
@ -590,7 +597,8 @@ static BOOL freerdp_peer_close(freerdp_peer* client)
static void freerdp_peer_disconnect(freerdp_peer* client)
{
transport_disconnect(client->context->rdp->transport);
rdpTransport* transport = client->context->rdp->transport;
transport_disconnect(transport);
}
static int freerdp_peer_send_channel_data(freerdp_peer* client, UINT16 channelId, BYTE* data, int size)
@ -600,14 +608,14 @@ static int freerdp_peer_send_channel_data(freerdp_peer* client, UINT16 channelId
static BOOL freerdp_peer_is_write_blocked(freerdp_peer* peer)
{
return tranport_is_write_blocked(peer->context->rdp->transport);
rdpTransport* transport = peer->context->rdp->transport;
return transport_is_write_blocked(transport);
}
static int freerdp_peer_drain_output_buffer(freerdp_peer* peer)
{
rdpTransport* transport = peer->context->rdp->transport;
return tranport_drain_output_buffer(transport);
return transport_drain_output_buffer(transport);
}
void freerdp_peer_context_new(freerdp_peer* client)

View File

@ -361,7 +361,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId)
rdp_set_error_info(rdp, ERRINFO_RPC_INITIATED_DISCONNECT);
}
WLog_ERR(TAG, "DisconnectProviderUltimatum: reason: %d", reason);
WLog_ERR(TAG, "DisconnectProviderUltimatum: reason: %d", reason);
rdp->disconnect = TRUE;
EventArgsInit(&e, "freerdp");
@ -748,7 +748,7 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
if (Stream_GetRemainingLength(s) < (size_t) SrcSize)
{
WLog_ERR(TAG, "bulk_decompress: not enough bytes for compressedLength %d", compressedLength);
WLog_ERR(TAG, "bulk_decompress: not enough bytes for compressedLength %d", compressedLength);
return -1;
}
@ -763,7 +763,7 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
}
else
{
WLog_ERR(TAG, "bulk_decompress() failed");
WLog_ERR(TAG, "bulk_decompress() failed");
return -1;
}
@ -970,13 +970,13 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags)
if (!security_fips_decrypt(Stream_Pointer(s), length, rdp))
{
WLog_ERR(TAG, "FATAL: cannot decrypt");
WLog_ERR(TAG, "FATAL: cannot decrypt");
return FALSE; /* TODO */
}
if (!security_fips_check_signature(Stream_Pointer(s), length - pad, sig, rdp))
{
WLog_ERR(TAG, "FATAL: invalid packet signature");
WLog_ERR(TAG, "FATAL: invalid packet signature");
return FALSE; /* TODO */
}
@ -1000,7 +1000,7 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags)
if (memcmp(wmac, cmac, sizeof(wmac)) != 0)
{
WLog_ERR(TAG, "WARNING: invalid packet signature");
WLog_ERR(TAG, "WARNING: invalid packet signature");
/*
* Because Standard RDP Security is totally broken,
* and cannot protect against MITM, don't treat signature
@ -1032,7 +1032,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
if (!rdp_read_header(rdp, s, &length, &channelId))
{
WLog_ERR(TAG, "Incorrect RDP header.");
WLog_ERR(TAG, "Incorrect RDP header.");
return -1;
}
@ -1053,7 +1053,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
{
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
WLog_ERR(TAG, "rdp_decrypt failed");
WLog_ERR(TAG, "rdp_decrypt failed");
return -1;
}
}
@ -1088,7 +1088,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
case PDU_TYPE_DATA:
if (rdp_recv_data_pdu(rdp, s) < 0)
{
WLog_ERR(TAG, "rdp_recv_data_pdu failed");
WLog_ERR(TAG, "rdp_recv_data_pdu failed");
return -1;
}
break;
@ -1108,7 +1108,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
break;
default:
WLog_ERR(TAG, "incorrect PDU type: 0x%04X", pduType);
WLog_ERR(TAG, "incorrect PDU type: 0x%04X", pduType);
break;
}
@ -1140,7 +1140,7 @@ static int rdp_recv_fastpath_pdu(rdpRdp* rdp, wStream* s)
if ((length == 0) || (length > Stream_GetRemainingLength(s)))
{
WLog_ERR(TAG, "incorrect FastPath PDU header length %d", length);
WLog_ERR(TAG, "incorrect FastPath PDU header length %d", length);
return -1;
}
@ -1168,7 +1168,7 @@ static int rdp_recv_pdu(rdpRdp* rdp, wStream* s)
return rdp_recv_fastpath_pdu(rdp, s);
}
static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
{
int status = 0;
rdpRdp* rdp = (rdpRdp*) extra;
@ -1179,8 +1179,7 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
* enters the active state, an auto-detect PDU can be received
* on the MCS message channel.
*/
if ((rdp->state > CONNECTION_STATE_MCS_CHANNEL_JOIN) &&
(rdp->state < CONNECTION_STATE_ACTIVE))
if ((rdp->state > CONNECTION_STATE_MCS_CHANNEL_JOIN) && (rdp->state < CONNECTION_STATE_ACTIVE))
{
if (rdp_client_connect_auto_detect(rdp, s))
return 0;
@ -1188,14 +1187,59 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
switch (rdp->state)
{
case CONNECTION_STATE_NEGO:
if (!rdp_client_connect_mcs_connect_response(rdp, s))
status = -1;
case CONNECTION_STATE_NLA:
if (nla_recv_pdu(rdp->nla, s) < 1)
return -1;
if (rdp->nla->state == NLA_STATE_AUTH_INFO)
{
transport_set_nla_mode(rdp->transport, FALSE);
nla_free(rdp->nla);
rdp->nla = NULL;
if (!mcs_client_begin(rdp->mcs))
return -1;
}
break;
case CONNECTION_STATE_MCS_CONNECT:
if (!mcs_recv_connect_response(rdp->mcs, s))
{
WLog_ERR(TAG, "mcs_recv_connect_response failure");
return -1;
}
if (!mcs_send_erect_domain_request(rdp->mcs))
{
WLog_ERR(TAG, "mcs_send_erect_domain_request failure");
return -1;
}
if (!mcs_send_attach_user_request(rdp->mcs))
{
WLog_ERR(TAG, "mcs_send_attach_user_request failure");
return -1;
}
rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
break;
case CONNECTION_STATE_MCS_ATTACH_USER:
if (!rdp_client_connect_mcs_attach_user_confirm(rdp, s))
status = -1;
if (!mcs_recv_attach_user_confirm(rdp->mcs, s))
{
WLog_ERR(TAG, "mcs_recv_attach_user_confirm failure");
return -1;
}
if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->userId))
{
WLog_ERR(TAG, "mcs_send_channel_join_request failure");
return -1;
}
rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN);
break;
case CONNECTION_STATE_MCS_CHANNEL_JOIN:
@ -1226,7 +1270,7 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
break;
default:
WLog_ERR(TAG, "Invalid state %d", rdp->state);
WLog_ERR(TAG, "Invalid state %d", rdp->state);
status = -1;
break;
}
@ -1256,18 +1300,6 @@ BOOL rdp_send_error_info(rdpRdp* rdp)
return status;
}
/**
* Set non-blocking mode information.
* @param rdp RDP module
* @param blocking blocking mode
*/
void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking)
{
rdp->transport->ReceiveCallback = rdp_recv_callback;
rdp->transport->ReceiveExtra = rdp;
transport_set_blocking_mode(rdp->transport, blocking);
}
int rdp_check_fds(rdpRdp* rdp)
{
int status;
@ -1277,7 +1309,7 @@ int rdp_check_fds(rdpRdp* rdp)
{
rdpTsg* tsg = transport->tsg;
status = tsg_check(tsg);
status = tsg_check_event_handles(tsg);
if (status < 0)
return -1;
@ -1513,6 +1545,7 @@ void rdp_free(rdpRdp* rdp)
fastpath_free(rdp->fastpath);
nego_free(rdp->nego);
mcs_free(rdp->mcs);
nla_free(rdp->nla);
redirection_free(rdp->redirection);
autodetect_free(rdp->autodetect);
heartbeat_free(rdp->heartbeat);

View File

@ -25,6 +25,7 @@
#include "config.h"
#endif
#include "nla.h"
#include "mcs.h"
#include "tpkt.h"
#include "bulk.h"
@ -132,6 +133,7 @@ struct rdp_rdp
int state;
freerdp* instance;
rdpContext* context;
rdpNla* nla;
rdpMcs* mcs;
rdpNego* nego;
rdpBulk* bulk;
@ -213,7 +215,8 @@ int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s);
void rdp_read_flow_control_pdu(wStream* s, UINT16* type);
void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking);
int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra);
int rdp_check_fds(rdpRdp* rdp);
rdpRdp* rdp_new(rdpContext* context);

View File

@ -22,9 +22,6 @@
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
@ -93,7 +90,6 @@
struct _WINPR_BIO_SIMPLE_SOCKET
{
BOOL win32;
SOCKET socket;
HANDLE hEvent;
};
@ -107,8 +103,9 @@ static void transport_bio_simple_check_reset_event(BIO* bio)
u_long nbytes = 0;
WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*) bio->ptr;
if (!ptr->win32)
return;
#ifndef _WIN32
return;
#endif
_ioctlsocket(ptr->socket, FIONREAD, &nbytes);
@ -252,6 +249,78 @@ static long transport_bio_simple_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
#endif
return 1;
}
else if (cmd == BIO_C_WAIT_READ)
{
int timeout = (int) arg1;
int sockfd = (int) ptr->socket;
#ifdef HAVE_POLL_H
struct pollfd pollset;
pollset.fd = sockfd;
pollset.events = POLLIN;
pollset.revents = 0;
do
{
status = poll(&pollset, 1, timeout);
}
while ((status < 0) && (errno == EINTR));
#else
fd_set rset;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
if (timeout)
{
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
}
do
{
status = select(sockfd + 1, &rset, NULL, NULL, timeout ? &tv : NULL);
}
while ((status < 0) && (errno == EINTR));
#endif
}
else if (cmd == BIO_C_WAIT_WRITE)
{
int timeout = (int) arg1;
int sockfd = (int) ptr->socket;
#ifdef HAVE_POLL_H
struct pollfd pollset;
pollset.fd = sockfd;
pollset.events = POLLOUT;
pollset.revents = 0;
do
{
status = poll(&pollset, 1, timeout);
}
while ((status < 0) && (errno == EINTR));
#else
fd_set rset;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
if (timeout)
{
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
}
do
{
status = select(sockfd + 1, NULL, &rset, NULL, timeout ? &tv : NULL);
}
while ((status < 0) && (errno == EINTR));
#endif
}
switch (cmd)
{
@ -308,8 +377,7 @@ static int transport_bio_simple_init(BIO* bio, SOCKET socket, int shutdown)
bio->flags = BIO_FLAGS_SHOULD_RETRY;
bio->init = 1;
if (ptr->win32)
{
#ifdef _WIN32
ptr->hEvent = WSACreateEvent(); /* creates a manual reset event */
if (!ptr->hEvent)
@ -317,14 +385,12 @@ static int transport_bio_simple_init(BIO* bio, SOCKET socket, int shutdown)
/* WSAEventSelect automatically sets the socket in non-blocking mode */
WSAEventSelect(ptr->socket, ptr->hEvent, FD_READ | FD_CLOSE);
}
else
{
#else
ptr->hEvent = CreateFileDescriptorEvent(NULL, FALSE, FALSE, (int) ptr->socket);
if (!ptr->hEvent)
return 0;
}
#endif
return 1;
}
@ -370,10 +436,6 @@ static int transport_bio_simple_new(BIO* bio)
bio->ptr = ptr;
#ifdef _WIN32
ptr->win32 = TRUE;
#endif
return 1;
}
@ -414,6 +476,16 @@ BIO_METHOD* BIO_s_simple_socket(void)
/* Buffered Socket BIO */
struct _WINPR_BIO_BUFFERED_SOCKET
{
BIO* socketBio;
BIO* bufferedBio;
BOOL readBlocked;
BOOL writeBlocked;
RingBuffer xmitBuffer;
};
typedef struct _WINPR_BIO_BUFFERED_SOCKET WINPR_BIO_BUFFERED_SOCKET;
long transport_bio_buffered_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
{
return 1;
@ -421,26 +493,28 @@ long transport_bio_buffered_callback(BIO* bio, int mode, const char* argp, int a
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
{
int status, ret;
rdpTcp* tcp = (rdpTcp*) bio->ptr;
int nchunks, committedBytes, i;
int i, ret;
int status;
int nchunks;
int committedBytes;
DataChunk chunks[2];
WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) bio->ptr;
ret = num;
tcp->writeBlocked = FALSE;
ptr->writeBlocked = FALSE;
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
/* we directly append extra bytes in the xmit buffer, this could be prevented
* but for now it makes the code more simple.
*/
if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE*) buf, num))
if (buf && num && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*) buf, num))
{
WLog_ERR(TAG, "an error occured when writing(toWrite=%d)", num);
WLog_ERR(TAG, "an error occured when writing (num: %d)", num);
return -1;
}
committedBytes = 0;
nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer));
nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer));
for (i = 0; i < nchunks; i++)
{
@ -460,7 +534,7 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
if (BIO_should_write(bio->next_bio))
{
BIO_set_flags(bio, BIO_FLAGS_WRITE);
tcp->writeBlocked = TRUE;
ptr->writeBlocked = TRUE;
goto out; /* EWOULDBLOCK */
}
}
@ -472,16 +546,17 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
}
out:
ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes);
ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes);
return ret;
}
static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
{
int status;
rdpTcp* tcp = (rdpTcp*) bio->ptr;
WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) bio->ptr;
tcp->readBlocked = FALSE;
ptr->readBlocked = FALSE;
BIO_clear_flags(bio, BIO_FLAGS_READ);
status = BIO_read(bio->next_bio, buf, size);
@ -499,7 +574,7 @@ static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
if (BIO_should_read(bio->next_bio))
{
BIO_set_flags(bio, BIO_FLAGS_READ);
tcp->readBlocked = TRUE;
ptr->readBlocked = TRUE;
goto out;
}
}
@ -520,37 +595,78 @@ static int transport_bio_buffered_gets(BIO* bio, char* str, int size)
static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
rdpTcp* tcp = (rdpTcp*) bio->ptr;
int status = -1;
WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) bio->ptr;
switch (cmd)
{
case BIO_CTRL_FLUSH:
return 1;
if (!ringbuffer_used(&ptr->xmitBuffer))
status = 1;
else
status = (transport_bio_buffered_write(bio, NULL, 0) >= 0) ? 1 : -1;
break;
case BIO_CTRL_WPENDING:
return ringbuffer_used(&tcp->xmitBuffer);
status = ringbuffer_used(&ptr->xmitBuffer);
break;
case BIO_CTRL_PENDING:
return 0;
status = 0;
break;
case BIO_C_READ_BLOCKED:
status = (int) ptr->readBlocked;
break;
case BIO_C_WRITE_BLOCKED:
status = (int) ptr->writeBlocked;
break;
default:
return BIO_ctrl(bio->next_bio, cmd, arg1, arg2);
status = BIO_ctrl(bio->next_bio, cmd, arg1, arg2);
break;
}
return 0;
return status;
}
static int transport_bio_buffered_new(BIO* bio)
{
WINPR_BIO_BUFFERED_SOCKET* ptr;
bio->init = 1;
bio->num = 0;
bio->ptr = NULL;
bio->flags = BIO_FLAGS_SHOULD_RETRY;
ptr = (WINPR_BIO_BUFFERED_SOCKET*) calloc(1, sizeof(WINPR_BIO_BUFFERED_SOCKET));
if (!ptr)
return -1;
bio->ptr = (void*) ptr;
if (!ringbuffer_init(&ptr->xmitBuffer, 0x10000))
return -1;
return 1;
}
static int transport_bio_buffered_free(BIO* bio)
{
WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) bio->ptr;
if (ptr->socketBio)
{
BIO_free(ptr->socketBio);
ptr->socketBio = NULL;
}
ringbuffer_destroy(&ptr->xmitBuffer);
free(ptr);
return 1;
}
@ -573,43 +689,27 @@ BIO_METHOD* BIO_s_buffered_socket(void)
return &transport_bio_buffered_socket_methods;
}
BOOL transport_bio_buffered_drain(BIO *bio)
{
int status;
rdpTcp* tcp = (rdpTcp*) bio->ptr;
if (!ringbuffer_used(&tcp->xmitBuffer))
return 1;
status = transport_bio_buffered_write(bio, NULL, 0);
return status >= 0;
}
void freerdp_tcp_get_ip_address(rdpTcp* tcp)
char* freerdp_tcp_get_ip_address(int sockfd)
{
BYTE* ip;
socklen_t length;
char ipAddress[32];
struct sockaddr_in sockaddr;
length = sizeof(sockaddr);
ZeroMemory(&sockaddr, length);
if (getsockname(tcp->sockfd, (struct sockaddr*) &sockaddr, &length) == 0)
if (getsockname(sockfd, (struct sockaddr*) &sockaddr, &length) == 0)
{
ip = (BYTE*) (&sockaddr.sin_addr);
sprintf_s(tcp->ip_address, sizeof(tcp->ip_address),
"%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
sprintf_s(ipAddress, sizeof(ipAddress), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
}
else
{
strcpy(tcp->ip_address, "127.0.0.1");
strcpy(ipAddress, "127.0.0.1");
}
tcp->settings->IPv6Enabled = 0;
free(tcp->settings->ClientAddress);
tcp->settings->ClientAddress = _strdup(tcp->ip_address);
return _strdup(ipAddress);
}
int freerdp_uds_connect(const char* path)
@ -913,57 +1013,86 @@ int freerdp_tcp_connect_multi(char** hostnames, int count, int port, int timeout
#endif
BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout)
BOOL freerdp_tcp_set_keep_alive_mode(int sockfd)
{
#ifndef _WIN32
UINT32 optval;
socklen_t optlen;
optval = 1;
optlen = sizeof(optval);
if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*) &optval, optlen) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
}
#ifdef TCP_KEEPIDLE
optval = 5;
optlen = sizeof(optval);
if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &optval, optlen) < 0)
{
WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
}
#endif
#ifdef TCP_KEEPCNT
optval = 3;
optlen = sizeof(optval);
if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*) &optval, optlen) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
}
#endif
#ifdef TCP_KEEPINTVL
optval = 2;
optlen = sizeof(optval);
if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*) &optval, optlen) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
}
#endif
#endif
#if defined(__MACOSX__) || defined(__IOS__)
optval = 1;
optlen = sizeof(optval);
if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*) &optval, optlen) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
}
#endif
return TRUE;
}
int freerdp_tcp_connect(rdpSettings* settings, const char* hostname, int port, int timeout)
{
int status;
UINT32 option_value;
socklen_t option_len;
rdpSettings* settings = tcp->settings;
int sockfd;
UINT32 optval;
socklen_t optlen;
BOOL ipcSocket = FALSE;
if (!hostname)
return FALSE;
return -1;
if (hostname[0] == '/')
tcp->ipcSocket = TRUE;
ipcSocket = TRUE;
if (tcp->ipcSocket)
if (ipcSocket)
{
tcp->sockfd = freerdp_uds_connect(hostname);
sockfd = freerdp_uds_connect(hostname);
if (tcp->sockfd < 0)
return FALSE;
tcp->socketBio = BIO_new(BIO_s_simple_socket());
if (!tcp->socketBio)
return FALSE;
BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
if (sockfd < 0)
return -1;
}
else
{
#ifdef NO_IPV6
tcp->socketBio = BIO_new(BIO_s_connect());
if (!tcp->socketBio)
return FALSE;
if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0)
return FALSE;
BIO_set_nbio(tcp->socketBio, 1);
status = BIO_do_connect(tcp->socketBio);
if ((status <= 0) && !BIO_should_retry(tcp->socketBio))
return FALSE;
tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL);
if (tcp->sockfd < 0)
return FALSE;
#else /* NO_IPV6 */
tcp->sockfd = -1;
sockfd = -1;
if (!settings->GatewayEnabled)
{
@ -972,7 +1101,7 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou
if (settings->TargetNetAddressCount > 0)
{
#ifndef _WIN32
tcp->sockfd = freerdp_tcp_connect_multi(settings->TargetNetAddresses,
sockfd = freerdp_tcp_connect_multi(settings->TargetNetAddresses,
settings->TargetNetAddressCount, port, timeout);
#else
hostname = settings->TargetNetAddresses[0];
@ -981,7 +1110,7 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou
}
}
if (tcp->sockfd <= 0)
if (sockfd <= 0)
{
char port_str[16];
struct addrinfo hints;
@ -996,12 +1125,14 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou
status = getaddrinfo(hostname, port_str, &hints, &result);
if (status) {
if (status)
{
WLog_ERR(TAG, "getaddrinfo: %s", gai_strerror(status));
return FALSE;
return -1;
}
addr = result;
if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0))
{
while ((addr = addr->ai_next))
@ -1009,311 +1140,65 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou
if (addr->ai_family == AF_INET)
break;
}
if (!addr)
addr = result;
}
tcp->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (tcp->sockfd < 0) {
if (sockfd < 0)
{
freeaddrinfo(result);
return FALSE;
return -1;
}
if (!freerdp_tcp_connect_timeout(tcp->sockfd, addr->ai_addr, addr->ai_addrlen, timeout))
if (!freerdp_tcp_connect_timeout(sockfd, addr->ai_addr, addr->ai_addrlen, timeout))
{
fprintf(stderr, "failed to connect to %s\n", hostname);
freeaddrinfo(result);
return FALSE;
return -1;
}
freeaddrinfo(result);
}
tcp->socketBio = BIO_new_socket(tcp->sockfd, BIO_NOCLOSE);
#endif /* NO_IPV6 */
(void) BIO_set_close(tcp->socketBio, BIO_NOCLOSE);
BIO_free(tcp->socketBio);
tcp->socketBio = BIO_new(BIO_s_simple_socket());
if (!tcp->socketBio)
return FALSE;
BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
}
BIO_get_event(tcp->socketBio, &tcp->event);
settings->IPv6Enabled = FALSE;
freerdp_tcp_get_ip_address(tcp);
free(settings->ClientAddress);
settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd);
option_value = 1;
option_len = sizeof(option_value);
optval = 1;
optlen = sizeof(optval);
if (!tcp->ipcSocket)
if (!ipcSocket)
{
if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0)
WLog_ERR(TAG, "unable to set TCP_NODELAY");
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &optval, optlen) < 0)
WLog_ERR(TAG, "unable to set TCP_NODELAY");
}
/* receive buffer must be a least 32 K */
if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0)
if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &optval, &optlen) == 0)
{
if (option_value < (1024 * 32))
if (optval < (1024 * 32))
{
option_value = 1024 * 32;
option_len = sizeof(option_value);
optval = 1024 * 32;
optlen = sizeof(optval);
if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0)
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &optval, optlen) < 0)
{
WLog_ERR(TAG, "unable to set receive buffer len");
return FALSE;
WLog_ERR(TAG, "unable to set receive buffer len");
return -1;
}
}
}
if (!tcp->ipcSocket)
if (!ipcSocket)
{
if (!freerdp_tcp_set_keep_alive_mode(tcp))
return FALSE;
}
tcp->bufferedBio = BIO_new(BIO_s_buffered_socket());
if (!tcp->bufferedBio)
return FALSE;
tcp->bufferedBio->ptr = tcp;
tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio);
return TRUE;
}
BOOL freerdp_tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking)
{
return BIO_set_nonblock(tcp->socketBio, blocking ? 0 : 1) ? TRUE : FALSE;
}
BOOL freerdp_tcp_set_keep_alive_mode(rdpTcp* tcp)
{
#ifndef _WIN32
UINT32 option_value;
socklen_t option_len;
option_value = 1;
option_len = sizeof(option_value);
if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*) &option_value, option_len) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
}
#ifdef TCP_KEEPIDLE
option_value = 5;
option_len = sizeof(option_value);
if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &option_value, option_len) < 0)
{
WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
}
#endif
#ifdef TCP_KEEPCNT
option_value = 3;
option_len = sizeof(option_value);
if (setsockopt(tcp->sockfd, SOL_TCP, TCP_KEEPCNT, (void*) &option_value, option_len) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
}
#endif
#ifdef TCP_KEEPINTVL
option_value = 2;
option_len = sizeof(option_value);
if (setsockopt(tcp->sockfd, SOL_TCP, TCP_KEEPINTVL, (void*) &option_value, option_len) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
}
#endif
#endif
#if defined(__MACOSX__) || defined(__IOS__)
option_value = 1;
option_len = sizeof(option_value);
if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*) &option_value, option_len) < 0)
{
WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
}
#endif
return TRUE;
}
int freerdp_tcp_attach(rdpTcp* tcp, int sockfd)
{
tcp->sockfd = sockfd;
ringbuffer_commit_read_bytes(&tcp->xmitBuffer, ringbuffer_used(&tcp->xmitBuffer));
if (tcp->socketBio)
{
if (BIO_set_fd(tcp->socketBio, sockfd, BIO_CLOSE) < 0)
if (!freerdp_tcp_set_keep_alive_mode(sockfd))
return -1;
}
else
{
tcp->socketBio = BIO_new(BIO_s_simple_socket());
if (!tcp->socketBio)
return -1;
BIO_set_fd(tcp->socketBio, sockfd, BIO_CLOSE);
}
if (!tcp->bufferedBio)
{
tcp->bufferedBio = BIO_new(BIO_s_buffered_socket());
if (!tcp->bufferedBio)
return FALSE;
tcp->bufferedBio->ptr = tcp;
tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio);
}
BIO_get_event(tcp->socketBio, &tcp->event);
return 1;
}
HANDLE freerdp_tcp_get_event_handle(rdpTcp* tcp)
{
if (!tcp)
return NULL;
return tcp->event;
}
int freerdp_tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds)
{
int status;
#ifdef HAVE_POLL_H
struct pollfd pollset;
pollset.fd = tcp->sockfd;
pollset.events = POLLIN;
pollset.revents = 0;
do
{
status = poll(&pollset, 1, dwMilliSeconds);
}
while ((status < 0) && (errno == EINTR));
#else
struct timeval tv;
fd_set rset;
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
if (dwMilliSeconds)
{
tv.tv_sec = dwMilliSeconds / 1000;
tv.tv_usec = (dwMilliSeconds % 1000) * 1000;
}
do
{
status = select(tcp->sockfd + 1, &rset, NULL, NULL, dwMilliSeconds ? &tv : NULL);
}
while ((status < 0) && (errno == EINTR));
#endif
return status;
}
int freerdp_tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds)
{
int status;
#ifdef HAVE_POLL_H
struct pollfd pollset;
pollset.fd = tcp->sockfd;
pollset.events = POLLOUT;
pollset.revents = 0;
do
{
status = poll(&pollset, 1, dwMilliSeconds);
}
while ((status < 0) && (errno == EINTR));
#else
struct timeval tv;
fd_set rset;
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
if (dwMilliSeconds)
{
tv.tv_sec = dwMilliSeconds / 1000;
tv.tv_usec = (dwMilliSeconds % 1000) * 1000;
}
do
{
status = select(tcp->sockfd + 1, NULL, &rset, NULL, dwMilliSeconds ? &tv : NULL);
}
while ((status < 0) && (errno == EINTR));
#endif
return status;
}
rdpTcp* freerdp_tcp_new(rdpSettings* settings)
{
rdpTcp* tcp;
tcp = (rdpTcp*) calloc(1, sizeof(rdpTcp));
if (!tcp)
return NULL;
if (!ringbuffer_init(&tcp->xmitBuffer, 0x10000))
goto out_free;
tcp->sockfd = -1;
tcp->settings = settings;
return tcp;
out_free:
free(tcp);
return NULL;
}
void freerdp_tcp_free(rdpTcp* tcp)
{
if (!tcp)
return;
ringbuffer_destroy(&tcp->xmitBuffer);
if (tcp->socketBio)
{
BIO_free(tcp->socketBio);
tcp->socketBio = NULL;
}
if (tcp->bufferedBio)
{
BIO_free(tcp->bufferedBio);
tcp->bufferedBio = NULL;
}
free(tcp);
return sockfd;
}

View File

@ -31,12 +31,9 @@
#include <winpr/stream.h>
#include <winpr/winsock.h>
#include <freerdp/utils/ringbuffer.h>
#include <openssl/bio.h>
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
#include <freerdp/utils/ringbuffer.h>
#define BIO_TYPE_TSG 65
#define BIO_TYPE_SIMPLE 66
@ -46,40 +43,23 @@
#define BIO_C_GET_SOCKET 1102
#define BIO_C_GET_EVENT 1103
#define BIO_C_SET_NONBLOCK 1104
#define BIO_C_READ_BLOCKED 1105
#define BIO_C_WRITE_BLOCKED 1106
#define BIO_C_WAIT_READ 1107
#define BIO_C_WAIT_WRITE 1108
#define BIO_set_socket(b, s, c) BIO_ctrl(b, BIO_C_SET_SOCKET, c, s);
#define BIO_get_socket(b, c) BIO_ctrl(b, BIO_C_GET_SOCKET, 0, (char*) c)
#define BIO_get_event(b, c) BIO_ctrl(b, BIO_C_GET_EVENT, 0, (char*) c)
#define BIO_set_nonblock(b, c) BIO_ctrl(b, BIO_C_SET_NONBLOCK, c, NULL)
#define BIO_read_blocked(b) BIO_ctrl(b, BIO_C_READ_BLOCKED, 0, NULL)
#define BIO_write_blocked(b) BIO_ctrl(b, BIO_C_WRITE_BLOCKED, 0, NULL)
#define BIO_wait_read(b, c) BIO_ctrl(b, BIO_C_WAIT_READ, c, NULL)
#define BIO_wait_write(b, c) BIO_ctrl(b, BIO_C_WAIT_WRITE, c, NULL)
typedef struct rdp_tcp rdpTcp;
BIO_METHOD* BIO_s_simple_socket(void);
BIO_METHOD* BIO_s_buffered_socket(void);
struct rdp_tcp
{
int sockfd;
BOOL ipcSocket;
char ip_address[32];
BYTE mac_address[6];
rdpSettings* settings;
BIO* socketBio;
BIO* bufferedBio;
RingBuffer xmitBuffer;
BOOL writeBlocked;
BOOL readBlocked;
HANDLE event;
};
BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout);
int freerdp_tcp_read(rdpTcp* tcp, BYTE* data, int length);
int freerdp_tcp_write(rdpTcp* tcp, BYTE* data, int length);
int freerdp_tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds);
int freerdp_tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds);
BOOL freerdp_tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking);
BOOL freerdp_tcp_set_keep_alive_mode(rdpTcp* tcp);
int freerdp_tcp_attach(rdpTcp* tcp, int sockfd);
HANDLE freerdp_tcp_get_event_handle(rdpTcp* tcp);
rdpTcp* freerdp_tcp_new(rdpSettings* settings);
void freerdp_tcp_free(rdpTcp* tcp);
int freerdp_tcp_connect(rdpSettings* settings, const char* hostname, int port, int timeout);
#endif /* __TCP_H */

View File

@ -67,67 +67,28 @@ wStream* transport_send_stream_init(rdpTransport* transport, int size)
return s;
}
void transport_attach(rdpTransport* transport, int sockfd)
BOOL transport_attach(rdpTransport* transport, int sockfd)
{
freerdp_tcp_attach(transport->TcpIn, sockfd);
transport->SplitInputOutput = FALSE;
transport->frontBio = transport->TcpIn->bufferedBio;
}
BIO* socketBio;
BIO* bufferedBio;
void transport_stop(rdpTransport* transport)
{
if (transport->async)
{
if (transport->stopEvent)
{
SetEvent(transport->stopEvent);
WaitForSingleObject(transport->thread, INFINITE);
CloseHandle(transport->thread);
CloseHandle(transport->stopEvent);
transport->thread = NULL;
transport->stopEvent = NULL;
}
}
}
socketBio = BIO_new(BIO_s_simple_socket());
BOOL transport_disconnect(rdpTransport* transport)
{
BOOL status = TRUE;
if (!transport)
if (!socketBio)
return FALSE;
transport_stop(transport);
BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
if (transport->tsg)
{
if (transport->TsgTls)
{
tls_free(transport->TsgTls);
transport->TsgTls = NULL;
}
bufferedBio = BIO_new(BIO_s_buffered_socket());
tsg_free(transport->tsg);
transport->tsg = NULL;
}
else
{
if (transport->TlsIn)
tls_free(transport->TlsIn);
if (!bufferedBio)
return FALSE;
if (transport->TcpIn)
freerdp_tcp_free(transport->TcpIn);
}
bufferedBio = BIO_push(bufferedBio, socketBio);
transport->TlsIn = NULL;
transport->TlsOut = NULL;
transport->frontBio = bufferedBio;
transport->TcpIn = NULL;
transport->TcpOut = NULL;
transport->layer = TRANSPORT_LAYER_TCP;
return status;
return TRUE;
}
BOOL transport_connect_rdp(rdpTransport* transport)
@ -138,45 +99,37 @@ BOOL transport_connect_rdp(rdpTransport* transport)
BOOL transport_connect_tls(rdpTransport* transport)
{
int tls_status;
BIO* targetBio = NULL;
rdpTls* targetTls = NULL;
int tlsStatus;
rdpTls* tls = NULL;
rdpContext* context = transport->context;
rdpSettings* settings = transport->settings;
if (transport->GatewayEnabled)
{
transport->TsgTls = tls_new(transport->settings);
tls = transport->tls = tls_new(settings);
transport->layer = TRANSPORT_LAYER_TSG_TLS;
targetTls = transport->TsgTls;
targetBio = transport->frontBio;
}
else
{
transport->TlsIn = tls_new(settings);
targetTls = transport->TlsIn;
targetBio = transport->TcpIn->bufferedBio;
tls = transport->tls = tls_new(settings);
transport->layer = TRANSPORT_LAYER_TLS;
}
transport->tls = targetTls;
transport->tls = tls;
targetTls->hostname = settings->ServerHostname;
targetTls->port = settings->ServerPort;
tls->hostname = settings->ServerHostname;
tls->port = settings->ServerPort;
if (targetTls->port == 0)
targetTls->port = 3389;
if (tls->port == 0)
tls->port = 3389;
targetTls->isGatewayTransport = FALSE;
tls_status = tls_connect(targetTls, targetBio);
tls->isGatewayTransport = FALSE;
tlsStatus = tls_connect(tls, transport->frontBio);
if (tls_status < 1)
if (tlsStatus < 1)
{
if (tls_status < 0)
if (tlsStatus < 0)
{
if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR;
if (!freerdp_get_last_error(context))
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
}
@ -189,7 +142,7 @@ BOOL transport_connect_tls(rdpTransport* transport)
return FALSE;
}
transport->frontBio = targetTls->bio;
transport->frontBio = tls->bio;
if (!transport->frontBio)
{
@ -202,84 +155,51 @@ BOOL transport_connect_tls(rdpTransport* transport)
BOOL transport_connect_nla(rdpTransport* transport)
{
freerdp* instance;
rdpSettings* settings;
rdpCredssp* credSsp;
settings = transport->settings;
instance = (freerdp*) settings->instance;
rdpContext* context = transport->context;
rdpSettings* settings = context->settings;
freerdp* instance = context->instance;
rdpRdp* rdp = context->rdp;
if (!transport_connect_tls(transport))
return FALSE;
/* Network Level Authentication */
if (!settings->Authentication)
return TRUE;
if (!transport->credssp)
{
transport->credssp = credssp_new(instance, transport, settings);
rdp->nla = nla_new(instance, transport, settings);
if (!transport->credssp)
if (!rdp->nla)
return FALSE;
transport_set_nla_mode(transport, TRUE);
if (settings->AuthenticationServiceClass)
{
rdp->nla->ServicePrincipalName =
nla_make_spn(settings->AuthenticationServiceClass, settings->ServerHostname);
if (!rdp->nla->ServicePrincipalName)
return FALSE;
transport_set_nla_mode(transport, TRUE);
if (settings->AuthenticationServiceClass)
{
transport->credssp->ServicePrincipalName =
credssp_make_spn(settings->AuthenticationServiceClass, settings->ServerHostname);
if (!transport->credssp->ServicePrincipalName)
return FALSE;
}
}
credSsp = transport->credssp;
if (credssp_authenticate(credSsp) < 0)
if (nla_client_begin(rdp->nla) < 0)
{
if (!connectErrorCode)
connectErrorCode = AUTHENTICATIONERROR;
if (!freerdp_get_last_error(context))
freerdp_set_last_error(context, FREERDP_ERROR_AUTHENTICATION_FAILED);
if (!freerdp_get_last_error(instance->context))
{
freerdp_set_last_error(instance->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
}
WLog_ERR(TAG, "Authentication failure, check credentials."
"If credentials are valid, the NTLMSSP implementation may be to blame.");
transport_set_nla_mode(transport, FALSE);
credssp_free(credSsp);
transport->credssp = NULL;
return FALSE;
}
transport_set_nla_mode(transport, FALSE);
credssp_free(credSsp);
transport->credssp = NULL;
return TRUE;
}
BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout)
{
rdpTsg* tsg;
tsg = tsg_new(transport);
if (!tsg)
return FALSE;
transport->tsg = tsg;
if (!tsg_connect(tsg, hostname, port, timeout))
return FALSE;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_NLA);
return TRUE;
}
BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout)
{
int sockfd;
BOOL status = FALSE;
rdpSettings* settings = transport->settings;
@ -287,18 +207,29 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
if (transport->GatewayEnabled)
{
if (!transport_tsg_connect(transport, hostname, port, timeout))
transport->tsg = tsg_new(transport);
if (!transport->tsg)
return FALSE;
if (!tsg_connect(transport->tsg, hostname, port, timeout))
return FALSE;
transport->frontBio = transport->tsg->bio;
transport->layer = TRANSPORT_LAYER_TSG;
status = TRUE;
}
else
{
transport->TcpIn = freerdp_tcp_new(settings);
sockfd = freerdp_tcp_connect(settings, hostname, port, timeout);
status = freerdp_tcp_connect(transport->TcpIn, hostname, port, timeout);
transport->SplitInputOutput = FALSE;
transport->frontBio = transport->TcpIn->bufferedBio;
if (sockfd < 1)
return FALSE;
transport_attach(transport, sockfd);
status = TRUE;
}
if (status)
@ -324,15 +255,16 @@ BOOL transport_accept_tls(rdpTransport* transport)
{
rdpSettings* settings = transport->settings;
if (!transport->TlsIn)
transport->TlsIn = tls_new(transport->settings);
if (!transport->tls)
transport->tls = tls_new(transport->settings);
transport->layer = TRANSPORT_LAYER_TLS;
if (!tls_accept(transport->TlsIn, transport->TcpIn->bufferedBio, settings->CertificateFile, settings->PrivateKeyFile))
if (!tls_accept(transport->tls, transport->frontBio, settings->CertificateFile, settings->PrivateKeyFile))
return FALSE;
transport->frontBio = transport->TlsIn->bio;
transport->frontBio = transport->tls->bio;
return TRUE;
}
@ -341,77 +273,42 @@ BOOL transport_accept_nla(rdpTransport* transport)
rdpSettings* settings = transport->settings;
freerdp* instance = (freerdp*) settings->instance;
if (!transport->TlsIn)
transport->TlsIn = tls_new(transport->settings);
if (!transport->tls)
transport->tls = tls_new(transport->settings);
transport->layer = TRANSPORT_LAYER_TLS;
if (!tls_accept(transport->TlsIn, transport->TcpIn->bufferedBio, settings->CertificateFile, settings->PrivateKeyFile))
if (!tls_accept(transport->tls, transport->frontBio, settings->CertificateFile, settings->PrivateKeyFile))
return FALSE;
transport->frontBio = transport->TlsIn->bio;
transport->frontBio = transport->tls->bio;
/* Network Level Authentication */
if (!settings->Authentication)
return TRUE;
if (!transport->credssp)
if (!transport->nla)
{
transport->credssp = credssp_new(instance, transport, settings);
transport->nla = nla_new(instance, transport, settings);
transport_set_nla_mode(transport, TRUE);
}
if (credssp_authenticate(transport->credssp) < 0)
if (nla_authenticate(transport->nla) < 0)
{
WLog_ERR(TAG, "client authentication failure");
transport_set_nla_mode(transport, FALSE);
credssp_free(transport->credssp);
transport->credssp = NULL;
tls_set_alert_code(transport->TlsIn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DESCRIPTION_ACCESS_DENIED);
nla_free(transport->nla);
transport->nla = NULL;
tls_set_alert_code(transport->tls, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DESCRIPTION_ACCESS_DENIED);
return FALSE;
}
/* don't free credssp module yet, we need to copy the credentials from it first */
/* don't free nla module yet, we need to copy the credentials from it first */
transport_set_nla_mode(transport, FALSE);
return TRUE;
}
static int transport_wait_for_read(rdpTransport* transport)
{
rdpTcp* tcpIn = transport->TcpIn;
if (tcpIn->readBlocked)
{
return freerdp_tcp_wait_read(tcpIn, 10);
}
else if (tcpIn->writeBlocked)
{
return freerdp_tcp_wait_write(tcpIn, 10);
}
USleep(1000);
return 0;
}
static int transport_wait_for_write(rdpTransport* transport)
{
rdpTcp* tcpOut;
tcpOut = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn;
if (tcpOut->writeBlocked)
{
return freerdp_tcp_wait_write(tcpOut, 10);
}
else if (tcpOut->readBlocked)
{
return freerdp_tcp_wait_read(tcpOut, 10);
}
USleep(1000);
return 0;
}
int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
{
int read = 0;
@ -440,9 +337,8 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
if (!transport->blocking)
return read;
/* blocking means that we can't continue until we have read the number of
* requested bytes */
if (transport_wait_for_read(transport) < 0)
/* blocking means that we can't continue until we have read the number of requested bytes */
if (BIO_wait_read(transport->frontBio, 100) < 0)
{
WLog_ERR(TAG, "error when selecting for read");
return -1;
@ -505,6 +401,7 @@ int transport_read_pdu(rdpTransport* transport, wStream* s)
int position;
int pduLength;
BYTE* header;
position = 0;
pduLength = 0;
@ -518,7 +415,7 @@ int transport_read_pdu(rdpTransport* transport, wStream* s)
/* Make sure there is enough space for the longest header within the stream */
Stream_EnsureCapacity(s, 4);
/* Make sure at least two bytes are read for futher processing */
/* Make sure at least two bytes are read for further processing */
if (position < 2 && (status = transport_read_layer_bytes(transport, s, 2 - position)) != 1)
{
/* No data available at the moment */
@ -618,17 +515,6 @@ int transport_read_pdu(rdpTransport* transport, wStream* s)
if (status != 1)
return status;
#ifdef WITH_DEBUG_TRANSPORT
/* dump when whole PDU is read */
if (Stream_GetPosition(s) >= pduLength)
{
WLog_DBG(TAG, "Local < Remote");
winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), pduLength);
}
#endif
if (Stream_GetPosition(s) >= pduLength)
WLog_Packet(WLog_Get(TAG), WLOG_TRACE, Stream_Buffer(s), pduLength, WLOG_PACKET_INBOUND);
@ -637,24 +523,15 @@ int transport_read_pdu(rdpTransport* transport, wStream* s)
return Stream_Length(s);
}
BOOL transport_bio_buffered_drain(BIO* bio);
int transport_write(rdpTransport* transport, wStream* s)
{
int length;
int status = -1;
EnterCriticalSection(&(transport->WriteLock));
length = Stream_GetPosition(s);
Stream_SetPosition(s, 0);
#ifdef WITH_DEBUG_TRANSPORT
if (length > 0)
{
WLog_DBG(TAG, "Local > Remote");
winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length);
}
#endif
if (length > 0)
{
@ -678,7 +555,7 @@ int transport_write(rdpTransport* transport, wStream* s)
if (!transport->blocking)
return status;
if (transport_wait_for_write(transport) < 0)
if (BIO_wait_write(transport->frontBio, 100) < 0)
{
WLog_ERR(TAG, "error when selecting for write");
return -1;
@ -689,20 +566,17 @@ int transport_write(rdpTransport* transport, wStream* s)
if (transport->blocking || transport->settings->WaitForOutputBufferFlush)
{
/* blocking transport, we must ensure the write buffer is really empty */
rdpTcp* out = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn;
while (out->writeBlocked)
while (BIO_write_blocked(transport->frontBio))
{
if (transport_wait_for_write(transport) < 0)
if (BIO_wait_write(transport->frontBio, 100) < 0)
{
WLog_ERR(TAG, "error when selecting for write");
return -1;
}
if (!transport_bio_buffered_drain(out->bufferedBio))
if (BIO_flush(transport->frontBio) < 1)
{
WLog_ERR(TAG, "error when draining outputBuffer");
WLog_ERR(TAG, "error when flushing outputBuffer");
return -1;
}
}
@ -725,92 +599,54 @@ int transport_write(rdpTransport* transport, wStream* s)
return status;
}
void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount)
UINT32 transport_get_event_handles(rdpTransport* transport, HANDLE* events)
{
void* pfd;
UINT32 nCount = 0;
#ifdef _WIN32
rfds[*rcount] = transport->TcpIn->event;
(*rcount)++;
#else
rfds[*rcount] = (void*)(long)(transport->TcpIn->sockfd);
(*rcount)++;
#endif
pfd = GetEventWaitObject(transport->ReceiveEvent);
if (pfd)
{
rfds[*rcount] = pfd;
(*rcount)++;
}
if (transport->GatewayEvent)
{
pfd = GetEventWaitObject(transport->GatewayEvent);
if (pfd)
{
rfds[*rcount] = pfd;
(*rcount)++;
}
}
}
DWORD transport_get_event_handles(rdpTransport* transport, HANDLE* events)
{
DWORD nCount = 0;
if (events)
events[nCount] = freerdp_tcp_get_event_handle(transport->TcpIn);
nCount++;
if (transport->ReceiveEvent)
if (!transport->GatewayEnabled)
{
if (events)
events[nCount] = transport->ReceiveEvent;
BIO_get_event(transport->frontBio, &events[nCount]);
nCount++;
}
if (transport->GatewayEvent)
else
{
if (events)
events[nCount] = transport->GatewayEvent;
nCount++;
nCount += tsg_get_event_handles(transport->tsg, events);
}
return nCount;
}
BOOL tranport_is_write_blocked(rdpTransport* transport)
void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount)
{
if (transport->TcpIn->writeBlocked)
return TRUE;
UINT32 index;
UINT32 nCount;
HANDLE events[64];
return transport->SplitInputOutput &&
transport->TcpOut &&
transport->TcpOut->writeBlocked;
nCount = transport_get_event_handles(transport, events);
for (index = 0; index < nCount; index++)
{
rfds[*rcount] = GetEventWaitObject(events[index]);
(*rcount)++;
}
}
int tranport_drain_output_buffer(rdpTransport* transport)
BOOL transport_is_write_blocked(rdpTransport* transport)
{
return BIO_write_blocked(transport->frontBio);
}
int transport_drain_output_buffer(rdpTransport* transport)
{
BOOL status = FALSE;
/* First try to send some accumulated bytes in the send buffer */
if (transport->TcpIn->writeBlocked)
if (BIO_write_blocked(transport->frontBio))
{
if (!transport_bio_buffered_drain(transport->TcpIn->bufferedBio))
if (BIO_flush(transport->frontBio) < 1)
return -1;
status |= transport->TcpIn->writeBlocked;
}
if (transport->SplitInputOutput && transport->TcpOut && transport->TcpOut->writeBlocked)
{
if (!transport_bio_buffered_drain(transport->TcpOut->bufferedBio))
return -1;
status |= transport->TcpOut->writeBlocked;
status |= BIO_write_blocked(transport->frontBio);
}
return status;
@ -825,8 +661,6 @@ int transport_check_fds(rdpTransport* transport)
if (!transport)
return -1;
ResetEvent(transport->ReceiveEvent);
/**
* Loop through and read all available PDUs. Since multiple
* PDUs can exist, it's important to deliver them all before
@ -876,16 +710,12 @@ int transport_check_fds(rdpTransport* transport)
BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking)
{
BOOL status = TRUE;
transport->blocking = blocking;
if (!transport->SplitInputOutput)
{
status &= freerdp_tcp_set_blocking_mode(transport->TcpIn, blocking);
}
if (!BIO_set_nonblock(transport->frontBio, blocking ? FALSE : TRUE))
return FALSE;
return status;
return TRUE;
}
void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled)
@ -898,6 +728,58 @@ void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode)
transport->NlaMode = NlaMode;
}
void transport_stop(rdpTransport* transport)
{
if (transport->async)
{
if (transport->stopEvent)
{
SetEvent(transport->stopEvent);
WaitForSingleObject(transport->thread, INFINITE);
CloseHandle(transport->thread);
CloseHandle(transport->stopEvent);
transport->thread = NULL;
transport->stopEvent = NULL;
}
}
}
BOOL transport_disconnect(rdpTransport* transport)
{
BOOL status = TRUE;
if (!transport)
return FALSE;
transport_stop(transport);
if (transport->tsg)
{
if (transport->tls)
{
tls_free(transport->tls);
transport->tls = NULL;
}
tsg_free(transport->tsg);
transport->tsg = NULL;
}
else
{
if (transport->tls)
{
tls_free(transport->tls);
transport->tls = NULL;
}
}
transport->frontBio = NULL;
transport->layer = TRANSPORT_LAYER_TCP;
return status;
}
static void* transport_client_thread(void* arg)
{
DWORD status;
@ -968,12 +850,10 @@ rdpTransport* transport_new(rdpContext* context)
transport->context = context;
transport->settings = context->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;
goto out_free_transport;
/* receive buffer for non-blocking read. */
transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0);
@ -981,15 +861,10 @@ rdpTransport* transport_new(rdpContext* context)
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;
goto out_free_receivebuffer;
transport->blocking = TRUE;
transport->GatewayEnabled = FALSE;
@ -1006,14 +881,11 @@ 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:
freerdp_tcp_free(transport->TcpIn);
out_free_transport:
free(transport);
return NULL;
}
@ -1029,7 +901,6 @@ void transport_free(rdpTransport* transport)
Stream_Release(transport->ReceiveBuffer);
StreamPool_Free(transport->ReceivePool);
CloseHandle(transport->ReceiveEvent);
CloseHandle(transport->connectedEvent);
DeleteCriticalSection(&(transport->ReadLock));
DeleteCriticalSection(&(transport->WriteLock));

View File

@ -58,28 +58,19 @@ struct rdp_transport
BIO* frontBio;
rdpTsg* tsg;
rdpTls* tls;
rdpTcp* TcpIn;
rdpTcp* TcpOut;
rdpTls* TlsIn;
rdpTls* TlsOut;
rdpTls* TsgTls;
rdpContext* context;
rdpCredssp* credssp;
rdpNla* nla;
rdpSettings* settings;
UINT32 SleepInterval;
void* ReceiveExtra;
wStream* ReceiveBuffer;
TransportRecv ReceiveCallback;
HANDLE ReceiveEvent;
HANDLE GatewayEvent;
BOOL blocking;
BOOL SplitInputOutput;
wStreamPool* ReceivePool;
HANDLE connectedEvent;
HANDLE stopEvent;
HANDLE thread;
BOOL async;
BOOL NlaMode;
BOOL blocking;
BOOL GatewayEnabled;
CRITICAL_SECTION ReadLock;
CRITICAL_SECTION WriteLock;
@ -87,7 +78,7 @@ struct rdp_transport
wStream* transport_send_stream_init(rdpTransport* transport, int size);
BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout);
void transport_attach(rdpTransport* transport, int sockfd);
BOOL transport_attach(rdpTransport* transport, int sockfd);
BOOL transport_disconnect(rdpTransport* transport);
BOOL transport_connect_rdp(rdpTransport* transport);
BOOL transport_connect_tls(rdpTransport* transport);
@ -102,13 +93,13 @@ int transport_write(rdpTransport* transport, wStream* s);
void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount);
int transport_check_fds(rdpTransport* transport);
DWORD transport_get_event_handles(rdpTransport* transport, HANDLE* events);
UINT32 transport_get_event_handles(rdpTransport* transport, HANDLE* events);
BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking);
void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled);
void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode);
BOOL tranport_is_write_blocked(rdpTransport* transport);
int tranport_drain_output_buffer(rdpTransport* transport);
BOOL transport_is_write_blocked(rdpTransport* transport);
int transport_drain_output_buffer(rdpTransport* transport);
wStream* transport_receive_pool_take(rdpTransport* transport);
int transport_receive_pool_return(rdpTransport* transport, wStream* pdu);

View File

@ -879,162 +879,34 @@ BIO *findBufferedBio(BIO *front)
int tls_write_all(rdpTls* tls, const BYTE* data, int length)
{
int i;
int status;
int nchunks;
int committedBytes;
rdpTcp *tcp;
#ifdef HAVE_POLL_H
struct pollfd pollfds;
#else
fd_set rset, wset;
fd_set *rsetPtr, *wsetPtr;
struct timeval tv;
#endif
int offset = 0;
BIO* bio = tls->bio;
DataChunk chunks[2];
BIO* bufferedBio = findBufferedBio(bio);
if (!bufferedBio)
while (offset < length)
{
WLog_ERR(TAG, "error unable to retrieve the bufferedBio in the BIO chain");
return -1;
}
tcp = (rdpTcp*) bufferedBio->ptr;
do
{
status = BIO_write(bio, data, length);
status = BIO_write(bio, &data[offset], length - offset);
if (status > 0)
break;
if (!BIO_should_retry(bio))
return -1;
#ifdef HAVE_POLL_H
pollfds.fd = tcp->sockfd;
pollfds.revents = 0;
pollfds.events = 0;
if (tcp->writeBlocked)
{
pollfds.events |= POLLOUT;
}
else if (tcp->readBlocked)
{
pollfds.events |= POLLIN;
offset += status;
}
else
{
WLog_ERR(TAG, "weird we're blocked but the underlying is not read or write blocked !");
USleep(10);
continue;
}
if (!BIO_should_retry(bio))
return -1;
do
{
status = poll(&pollfds, 1, 100);
}
while ((status < 0) && (errno == EINTR));
#else
/* we try to handle SSL want_read and want_write nicely */
rsetPtr = wsetPtr = NULL;
if (BIO_write_blocked(bio))
status = BIO_wait_write(bio, 100);
else if (BIO_read_blocked(bio))
status = BIO_wait_read(bio, 100);
else
USleep(100);
if (tcp->writeBlocked)
{
wsetPtr = &wset;
FD_ZERO(&wset);
FD_SET(tcp->sockfd, &wset);
if (status < 0)
return -1;
}
else if (tcp->readBlocked)
{
rsetPtr = &rset;
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
}
else
{
WLog_ERR(TAG, "weird we're blocked but the underlying is not read or write blocked !");
USleep(10);
continue;
}
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
status = _select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
#endif
if (status < 0)
return -1;
}
while (TRUE);
/* make sure the output buffer is empty */
do
{
committedBytes = 0;
if (ringbuffer_used(&tcp->xmitBuffer) < 1)
break;
nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer));
if (nchunks < 1)
break;
for (i = 0; i < nchunks; i++)
{
while (chunks[i].size)
{
status = BIO_write(tcp->socketBio, chunks[i].data, chunks[i].size);
if (status > 0)
{
chunks[i].size -= status;
chunks[i].data += status;
committedBytes += status;
continue;
}
if (!BIO_should_retry(tcp->socketBio))
goto out_fail;
#ifdef HAVE_POLL_H
pollfds.fd = tcp->sockfd;
pollfds.events = POLLIN;
pollfds.revents = 0;
do
{
status = poll(&pollfds, 1, 100);
}
while ((status < 0) && (errno == EINTR));
#else
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
status = _select(tcp->sockfd + 1, &rset, NULL, NULL, &tv);
#endif
if (status < 0)
goto out_fail;
}
}
ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes);
continue;
out_fail:
ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes);
return -1;
}
while (TRUE);
return length;
}

View File

@ -56,6 +56,12 @@
#define _getprotobynumber getprotobynumber
#define _getprotobyname getprotobyname
#define _IFF_UP IFF_UP
#define _IFF_BROADCAST IFF_BROADCAST
#define _IFF_LOOPBACK IFF_LOOPBACK
#define _IFF_POINTTOPOINT IFF_POINTTOPOINT
#define _IFF_MULTICAST IFF_MULTICAST
#if (_WIN32_WINNT < 0x0600)
PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize);
@ -155,6 +161,123 @@ typedef struct WSAData
#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xFF)) | (((WORD)((BYTE)((DWORD_PTR)(b) & 0xFF))) << 8)))
#endif
typedef struct in6_addr IN6_ADDR;
typedef struct in6_addr* PIN6_ADDR;
typedef struct in6_addr* LPIN6_ADDR;
struct sockaddr_in6_old
{
SHORT sin6_family;
USHORT sin6_port;
ULONG sin6_flowinfo;
IN6_ADDR sin6_addr;
};
typedef union sockaddr_gen
{
struct sockaddr Address;
struct sockaddr_in AddressIn;
struct sockaddr_in6_old AddressIn6;
} sockaddr_gen;
#define _IFF_UP 0x00000001
#define _IFF_BROADCAST 0x00000002
#define _IFF_LOOPBACK 0x00000004
#define _IFF_POINTTOPOINT 0x00000008
#define _IFF_MULTICAST 0x00000010
struct _INTERFACE_INFO
{
ULONG iiFlags;
sockaddr_gen iiAddress;
sockaddr_gen iiBroadcastAddress;
sockaddr_gen iiNetmask;
};
typedef struct _INTERFACE_INFO INTERFACE_INFO;
typedef INTERFACE_INFO* LPINTERFACE_INFO;
#define MAX_PROTOCOL_CHAIN 7
#define WSAPROTOCOL_LEN 255
typedef struct _WSAPROTOCOLCHAIN
{
int ChainLen;
DWORD ChainEntries[MAX_PROTOCOL_CHAIN];
}
WSAPROTOCOLCHAIN, *LPWSAPROTOCOLCHAIN;
typedef struct _WSAPROTOCOL_INFOA
{
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlags4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
CHAR szProtocol[WSAPROTOCOL_LEN+1];
}
WSAPROTOCOL_INFOA, *LPWSAPROTOCOL_INFOA;
typedef struct _WSAPROTOCOL_INFOW
{
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlags4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
WCHAR szProtocol[WSAPROTOCOL_LEN+1];
}
WSAPROTOCOL_INFOW, *LPWSAPROTOCOL_INFOW;
typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwError,
DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);
typedef UINT32 GROUP;
#define SG_UNCONSTRAINED_GROUP 0x01
#define SG_CONSTRAINED_GROUP 0x02
#define SIO_GET_INTERFACE_LIST _IOR('t', 127, ULONG)
#define SIO_GET_INTERFACE_LIST_EX _IOR('t', 126, ULONG)
#define SIO_SET_MULTICAST_FILTER _IOW('t', 125, ULONG)
#define SIO_GET_MULTICAST_FILTER _IOW('t', 124 | IOC_IN, ULONG)
#define SIOCSIPMSFILTER SIO_SET_MULTICAST_FILTER
#define SIOCGIPMSFILTER SIO_GET_MULTICAST_FILTER
#ifdef UNICODE
#define WSAPROTOCOL_INFO WSAPROTOCOL_INFOW
#define LPWSAPROTOCOL_INFO LPWSAPROTOCOL_INFOW
#else
#define WSAPROTOCOL_INFO WSAPROTOCOL_INFOA
#define LPWSAPROTOCOL_INFO LPWSAPROTOCOL_INFOA
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -175,6 +298,14 @@ WINPR_API int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, LONG lNetworkEvent
WINPR_API DWORD WSAWaitForMultipleEvents(DWORD cEvents,
const HANDLE* lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable);
WINPR_API SOCKET WSASocketA(int af, int type, int protocol, LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags);
WINPR_API SOCKET WSASocketW(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags);
WINPR_API int WSAIoctl(SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer,
DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
WINPR_API SOCKET _accept(SOCKET s, struct sockaddr* addr, int* addrlen);
WINPR_API int _bind(SOCKET s, const struct sockaddr* addr, int namelen);
WINPR_API int closesocket(SOCKET s);
@ -210,6 +341,12 @@ WINPR_API struct protoent* _getprotobyname(const char* name);
}
#endif
#ifdef UNICODE
#define WSASocket WSASocketW
#else
#define WSASocket WSASocketA
#endif
#endif /* _WIN32 */
#endif /* WINPR_WINSOCK_H */

View File

@ -19,6 +19,7 @@
*/
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/interlocked.h>

View File

@ -7,7 +7,7 @@
static void *test_thread(void *arg)
{
long timeout = random();
long timeout = rand();
timeout %= 1000;
timeout += 100;
Sleep(timeout);

View File

@ -650,6 +650,151 @@ DWORD WSAWaitForMultipleEvents(DWORD cEvents, const HANDLE* lphEvents, BOOL fWai
return WaitForMultipleObjectsEx(cEvents, lphEvents, fWaitAll, dwTimeout, fAlertable);
}
SOCKET WSASocketA(int af, int type, int protocol, LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags)
{
SOCKET s;
s = _socket(af, type, protocol);
return s;
}
SOCKET WSASocketW(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags)
{
return WSASocketA(af, type, protocol, (LPWSAPROTOCOL_INFOA) lpProtocolInfo, g, dwFlags);
}
int WSAIoctl(SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer,
DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
int fd;
int index;
ULONG nFlags;
size_t offset;
size_t ifreq_len;
struct ifreq* ifreq;
struct ifconf ifconf;
char address[128];
char broadcast[128];
char netmask[128];
char buffer[4096];
int numInterfaces;
int maxNumInterfaces;
INTERFACE_INFO* pInterface;
INTERFACE_INFO* pInterfaces;
struct sockaddr_in* pAddress;
struct sockaddr_in* pBroadcast;
struct sockaddr_in* pNetmask;
if ((dwIoControlCode != SIO_GET_INTERFACE_LIST) ||
(!lpvOutBuffer || !cbOutBuffer || !lpcbBytesReturned))
{
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
fd = (int) s;
pInterfaces = (INTERFACE_INFO*) lpvOutBuffer;
maxNumInterfaces = cbOutBuffer / sizeof(INTERFACE_INFO);
ifconf.ifc_len = sizeof(buffer);
ifconf.ifc_buf = buffer;
if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0)
{
WSASetLastError(WSAENETDOWN);
return SOCKET_ERROR;
}
index = 0;
offset = 0;
numInterfaces = 0;
ifreq = ifconf.ifc_req;
while ((offset < ifconf.ifc_len) && (numInterfaces < maxNumInterfaces))
{
pInterface = &pInterfaces[index];
pAddress = (struct sockaddr_in*) &pInterface->iiAddress;
pBroadcast = (struct sockaddr_in*) &pInterface->iiBroadcastAddress;
pNetmask = (struct sockaddr_in*) &pInterface->iiNetmask;
if (ioctl(fd, SIOCGIFFLAGS, ifreq) != 0)
goto next_ifreq;
nFlags = 0;
if (ifreq->ifr_flags & IFF_UP)
nFlags |= _IFF_UP;
if (ifreq->ifr_flags & IFF_BROADCAST)
nFlags |= _IFF_BROADCAST;
if (ifreq->ifr_flags & IFF_LOOPBACK)
nFlags |= _IFF_LOOPBACK;
if (ifreq->ifr_flags & IFF_POINTOPOINT)
nFlags |= _IFF_POINTTOPOINT;
if (ifreq->ifr_flags & IFF_MULTICAST)
nFlags |= _IFF_MULTICAST;
pInterface->iiFlags = nFlags;
if (ioctl(fd, SIOCGIFADDR, ifreq) != 0)
goto next_ifreq;
if ((ifreq->ifr_addr.sa_family != AF_INET) && (ifreq->ifr_addr.sa_family != AF_INET6))
goto next_ifreq;
getnameinfo(&ifreq->ifr_addr, sizeof(ifreq->ifr_addr),
address, sizeof(address), 0, 0, NI_NUMERICHOST);
inet_pton(ifreq->ifr_addr.sa_family, address, (void*) &pAddress->sin_addr);
if (ioctl(fd, SIOCGIFBRDADDR, ifreq) != 0)
goto next_ifreq;
if ((ifreq->ifr_addr.sa_family != AF_INET) && (ifreq->ifr_addr.sa_family != AF_INET6))
goto next_ifreq;
getnameinfo(&ifreq->ifr_addr, sizeof(ifreq->ifr_addr),
broadcast, sizeof(broadcast), 0, 0, NI_NUMERICHOST);
inet_pton(ifreq->ifr_addr.sa_family, broadcast, (void*) &pBroadcast->sin_addr);
if (ioctl(fd, SIOCGIFNETMASK, ifreq) != 0)
goto next_ifreq;
if ((ifreq->ifr_addr.sa_family != AF_INET) && (ifreq->ifr_addr.sa_family != AF_INET6))
goto next_ifreq;
getnameinfo(&ifreq->ifr_addr, sizeof(ifreq->ifr_addr),
netmask, sizeof(netmask), 0, 0, NI_NUMERICHOST);
inet_pton(ifreq->ifr_addr.sa_family, netmask, (void*) &pNetmask->sin_addr);
numInterfaces++;
next_ifreq:
#ifndef __linux__
ifreq_len = IFNAMSIZ + ifreq->ifr_addr.sa_len;
#else
ifreq_len = sizeof(*ifreq);
#endif
ifreq = (struct ifreq*) &((BYTE*) ifreq)[ifreq_len];
offset += ifreq_len;
index++;
}
*lpcbBytesReturned = (DWORD) (numInterfaces * sizeof(INTERFACE_INFO));
return 0;
}
SOCKET _accept(SOCKET s, struct sockaddr* addr, int* addrlen)
{
int status;