diff --git a/libfreerdp-core/listener.c b/libfreerdp-core/listener.c index a39d96fec..42641f0da 100644 --- a/libfreerdp-core/listener.c +++ b/libfreerdp-core/listener.c @@ -40,7 +40,7 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bind_address, uint16 port) { - rdpListener* listener = (rdpListener*)instance->listener; + rdpListener* listener = (rdpListener*) instance->listener; int status; int sockfd; char servname[10]; @@ -56,14 +56,20 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + if (bind_address == NULL) hints.ai_flags = AI_PASSIVE; snprintf(servname, sizeof(servname), "%d", port); status = getaddrinfo(bind_address, servname, &hints, &res); + if (status != 0) { +#ifdef _WIN32 + _tprintf(_T("getaddrinfo error: %s\n"), gai_strerror(status)); +#else perror("getaddrinfo"); +#endif return false; } @@ -73,6 +79,7 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin continue; sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sockfd == -1) { perror("socket"); @@ -92,14 +99,21 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin #endif status = bind(sockfd, ai->ai_addr, ai->ai_addrlen); + if (status != 0) { +#ifdef _WIN32 + _tprintf(L"bind() failed with error: %u\n", WSAGetLastError()); + WSACleanup(); +#else perror("bind"); close(sockfd); +#endif continue; } status = listen(sockfd, 10); + if (status != 0) { perror("listen"); @@ -110,9 +124,9 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin listener->sockfds[listener->num_sockfds++] = sockfd; if (ai->ai_family == AF_INET) - sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr); + sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr); else - sin_addr = &(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr); + sin_addr = &(((struct sockaddr_in6*) ai->ai_addr)->sin6_addr); printf("Listening on %s port %s.\n", inet_ntop(ai->ai_family, sin_addr, buf, sizeof(buf)), servname); } @@ -125,12 +139,13 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin static boolean freerdp_listener_open_local(freerdp_listener* instance, const char* path) { #ifndef _WIN32 - rdpListener* listener = (rdpListener*)instance->listener; int status; int sockfd; struct sockaddr_un addr; + rdpListener* listener = (rdpListener*) instance->listener; sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd == -1) { perror("socket"); @@ -142,7 +157,9 @@ static boolean freerdp_listener_open_local(freerdp_listener* instance, const cha addr.sun_family = AF_UNIX; 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) { perror("bind"); @@ -151,6 +168,7 @@ static boolean freerdp_listener_open_local(freerdp_listener* instance, const cha } status = listen(sockfd, 10); + if (status != 0) { perror("listen"); @@ -164,7 +182,7 @@ static boolean freerdp_listener_open_local(freerdp_listener* instance, const cha return true; #else - return false; + return true; #endif } @@ -183,8 +201,8 @@ static void freerdp_listener_close(freerdp_listener* instance) static boolean freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount) { - rdpListener* listener = (rdpListener*)instance->listener; int i; + rdpListener* listener = (rdpListener*) instance->listener; if (listener->num_sockfds < 1) return false; diff --git a/libfreerdp-crypto/tls.c b/libfreerdp-crypto/tls.c index 26855e0b3..0df0f9a64 100644 --- a/libfreerdp-crypto/tls.c +++ b/libfreerdp-crypto/tls.c @@ -53,7 +53,6 @@ static void tls_free_certificate(CryptoCert cert) xfree(cert); } - boolean tls_connect(rdpTls* tls) { CryptoCert cert; diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index b208f64dd..cf7f3e743 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -32,4 +32,6 @@ if(NOT WIN32) # Build Server Channels library add_subdirectory(channels) +else() + add_subdirectory(Windows) endif() diff --git a/server/Windows/CMakeLists.txt b/server/Windows/CMakeLists.txt new file mode 100644 index 000000000..1de211f5d --- /dev/null +++ b/server/Windows/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP Windows Server cmake build script +# +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_executable(wfreerdp-server + wfreerdp.c) + +target_link_libraries(wfreerdp-server freerdp-core) +target_link_libraries(wfreerdp-server freerdp-utils) +target_link_libraries(wfreerdp-server freerdp-codec) +target_link_libraries(wfreerdp-server freerdp-channels) diff --git a/server/Windows/server.crt b/server/Windows/server.crt new file mode 100644 index 000000000..7ce931c26 --- /dev/null +++ b/server/Windows/server.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICyzCCAbOgAwIBAgIJANbqtAWwlQZuMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV +BAMTB0ZyZWVSRFAwHhcNMDkxMDI5MDA0MTQ5WhcNMDkxMTI4MDA0MTQ5WjASMRAw +DgYDVQQDEwdGcmVlUkRQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +q7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1TptzXTcmfDrDslTGwcEY +hTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2SXvTiaV26VPPxddGb +o6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJLd2SU4ItWHj8zjz1f +eGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsjgvz4yP7I3TL8+GsN +MjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdymrulJSIhoOVfKkwi +ptTe43FgwxVRIygJP9HjHQIDAQABoyQwIjATBgNVHSUEDDAKBggrBgEFBQcDATAL +BgNVHQ8EBAMCBDAwDQYJKoZIhvcNAQEFBQADggEBAIOdEDhOX2kbl02znltd9hCr +nV4kRPKm979RKwBNkrEuwYSlcsjAHg5MZ5itH3wFOUo2s5pjt7/vMOAg+6rOBbIa +nqr22/gKBtOmuaJLG1yjxDC2vfez7f3B26pKgxa/krM8oxiFdT9n8QbdxdkN7/D9 +3RLU/aCfgrMzXxRus7eq3kR00jnSs6ggnAfE1E9gric3vFgr1wCzdcriRXmXDfUb +hRq+4VG+ZWk16TwCofV5GVU39XWCv5HNO2swAdjkNXgI5e3tQbV3wWLZLqqYzBco +iWulAXtoCGmE81+u1Ms7hLLzpXitLZSGPu1r+sDdkKPLCmOvkAaljDQ4nBz7fIA= +-----END CERTIFICATE----- diff --git a/server/Windows/server.key b/server/Windows/server.key new file mode 100644 index 000000000..5c2f2c803 --- /dev/null +++ b/server/Windows/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAq7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1Tptz +XTcmfDrDslTGwcEYhTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2S +XvTiaV26VPPxddGbo6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJL +d2SU4ItWHj8zjz1feGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsj +gvz4yP7I3TL8+GsNMjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdy +mrulJSIhoOVfKkwiptTe43FgwxVRIygJP9HjHQIDAQABAoIBAAVv5K54xtc1JtBR +1lfdPbSqDlnjx8aOnVIPg5TnqMp3sR8jBt0NsPc/+RA9ZOmfjoIxFAEJaZ9zSDJC +5BqmnxC5R1mfCQkSd2haQ+4pdFvWyrv4Bblh8YU6hXrJGn0LfO0KlIcywtAvKpsi +LtTyZkWmaW2HeF/+pO32jYygw38R1wd8Tl6GwjOXwTF6lFACJXOT4YAzcfp3FKSB +AiKBIGuMzozoSND7KPFNRrhGhNumJpdS5A8Fb8D2c/ZMv6Cq5IbwOgTfKun+Bz+s +mFbnzeb1uWRqQbsVXOBBW/zHfuG3SU5qeZsaAyuu4DTy+LE1oAHF9uhBSHuT5C6i +vCJ8A8ECgYEA1iaOmiEJYBrs25iAc4SjCKqhY0mwR3wtu3I06vmgUoML5fhPMv36 +SvYQIqDyNw3p7TE6mZtw9+G+kK3PqhuJhogwSwg0a6o51RdKnhXH3/68oNWtKCLC +1AmR8q/Gd3FwAR3b49CuOIZ9uOiJrc/ejzKdFEJTDR1/TX1frWfZznECgYEAzUiz +XxFf7YrGel7JgmfRD2eZRYngOoteFlg5Tee42UjeAY2Pt2aiDLk+2TqQEdI9+Xg7 +LcFdBqcSNd8bh33xSzgNthIkX+lTDzx0SmKGfyxfFBJcY8nzsLvvnNt3YeuMeaJQ +CPszwoZ0jcD46jTCjbrKhaLyEWmUkDp1O71NTW0CgYAXKF49Xpsz8FVyvcAOPeaf +dkwzf3F3mX8ciRId4taqdY9g1AREgGCDoK5IAF2RBIkqZCtxFvUVaS0BWjpdq9Ko +YKvQQVfh2KueVoF0LOjLWTGutsydzXyCD3Lf6pAstHCnPkJcFWHxrOGFkGfrCtKH +a7K+0RlIDsuIZqllCBjukQKBgA31+MTpYJW+D1t5IMkumEgs6n6RLt+sZLyuSU9k +B+03CGogn3qAj1rAKmcJlYywuKhDpfqpoNL3/8QMJUokpYlRCZWtTC39pzltCheY +9b6mXNz3lrLupBUL4vLO9iKBq28GO90wgEelbz3ItuTuq6CJ6IYIG+BVRtY8M4bZ +i+1NAoGANXZjYnJYDnh8Je9SDxDSc5byzK7ddkQoId64RCIfNHqNKH63P81vjgnH +YBIPtagY75ZVVNxujCF7m8Rety+d8tEFwfQKDin2EVI7PD2rOJra385/izp7HuBR +vqxvLzG9Xv3cNOU2l7PttVw4Pa2i5E37atKi3V3Zp2kMW+KaKPQ= +-----END RSA PRIVATE KEY----- diff --git a/server/Windows/wfreerdp.c b/server/Windows/wfreerdp.c new file mode 100644 index 000000000..abf403046 --- /dev/null +++ b/server/Windows/wfreerdp.c @@ -0,0 +1,360 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Windows Server + * + * Copyright 2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +HANDLE g_done_event; +int g_thread_count = 0; + +struct test_peer_context +{ + rdpContext _p; + + STREAM* s; + uint32 frame_id; + boolean activated; + RFX_CONTEXT* rfx_context; + NSC_CONTEXT* nsc_context; + freerdp_thread* debug_channel_thread; +}; +typedef struct test_peer_context testPeerContext; + +void test_peer_context_new(freerdp_peer* client, testPeerContext* context) +{ + context->rfx_context = rfx_context_new(); + context->rfx_context->mode = RLGR3; + context->rfx_context->width = client->settings->width; + context->rfx_context->height = client->settings->height; + rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_R8G8B8); + + context->nsc_context = nsc_context_new(); + nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_R8G8B8); + + context->s = stream_new(65536); +} + +void test_peer_context_free(freerdp_peer* client, testPeerContext* context) +{ + if (context) + { + if (context->debug_channel_thread) + { + freerdp_thread_stop(context->debug_channel_thread); + freerdp_thread_free(context->debug_channel_thread); + } + stream_free(context->s); + + rfx_context_free(context->rfx_context); + nsc_context_free(context->nsc_context); + + xfree(context); + } +} + +static void test_peer_init(freerdp_peer* client) +{ + client->context_size = sizeof(testPeerContext); + client->ContextNew = (psPeerContextNew) test_peer_context_new; + client->ContextFree = (psPeerContextFree) test_peer_context_free; + freerdp_peer_context_new(client); +} + +static STREAM* test_peer_stream_init(testPeerContext* context) +{ + stream_clear(context->s); + stream_set_pos(context->s, 0); + return context->s; +} + +static void test_peer_begin_frame(freerdp_peer* client) +{ + rdpUpdate* update = client->update; + SURFACE_FRAME_MARKER* fm = &update->surface_frame_marker; + testPeerContext* context = (testPeerContext*) client->context; + + fm->frameAction = SURFACECMD_FRAMEACTION_BEGIN; + fm->frameId = context->frame_id; + update->SurfaceFrameMarker(update->context, fm); +} + +static void test_peer_end_frame(freerdp_peer* client) +{ + rdpUpdate* update = client->update; + SURFACE_FRAME_MARKER* fm = &update->surface_frame_marker; + testPeerContext* context = (testPeerContext*) client->context; + + fm->frameAction = SURFACECMD_FRAMEACTION_END; + fm->frameId = context->frame_id; + update->SurfaceFrameMarker(update->context, fm); + + context->frame_id++; +} + +boolean tf_peer_post_connect(freerdp_peer* client) +{ + int i; + testPeerContext* context = (testPeerContext*) client->context; + + /** + * This callback is called when the entire connection sequence is done, i.e. we've received the + * Font List PDU from the client and sent out the Font Map PDU. + * The server may start sending graphics output and receiving keyboard/mouse input after this + * callback returns. + */ + + printf("Client %s is activated (osMajorType %d osMinorType %d)", client->local ? "(local)" : client->hostname, + client->settings->os_major_type, client->settings->os_minor_type); + + if (client->settings->autologon) + { + printf(" and wants to login automatically as %s\\%s", + client->settings->domain ? client->settings->domain : "", + client->settings->username); + + /* A real server may perform OS login here if NLA is not executed previously. */ + } + printf("\n"); + + printf("Client requested desktop: %dx%dx%d\n", + client->settings->width, client->settings->height, client->settings->color_depth); + + /* A real server should tag the peer as activated here and start sending updates in main loop. */ + + /* Iterate all channel names requested by the client and activate those supported by the server */ + + for (i = 0; i < client->settings->num_channels; i++) + { + if (client->settings->channels[i].joined) + { + + } + } + + /* Return false here would stop the execution of the peer mainloop. */ + return true; +} + +boolean tf_peer_activate(freerdp_peer* client) +{ + testPeerContext* context = (testPeerContext*) client->context; + + rfx_context_reset(context->rfx_context); + context->activated = true; + + return true; +} + +void tf_peer_synchronize_event(rdpInput* input, uint32 flags) +{ + printf("Client sent a synchronize event (flags:0x%X)\n", flags); +} + +void tf_peer_keyboard_event(rdpInput* input, uint16 flags, uint16 code) +{ + freerdp_peer* client = input->context->peer; + rdpUpdate* update = client->update; + testPeerContext* context = (testPeerContext*) input->context; + + printf("Client sent a keyboard event (flags:0x%X code:0x%X)\n", flags, code); + + if ((flags & 0x4000) && code == 0x1F) /* 's' key */ + { + if (client->settings->width != 800) + { + client->settings->width = 800; + client->settings->height = 600; + } + else + { + client->settings->width = 640; + client->settings->height = 480; + } + update->DesktopResize(update->context); + context->activated = false; + } + else if ((flags & 0x4000) && code == 0x2D) /* 'x' key */ + { + client->Close(client); + } +} + +void tf_peer_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code) +{ + printf("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code); +} + +void tf_peer_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y) +{ + printf("Client sent a mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y); +} + +void tf_peer_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y) +{ + printf("Client sent an extended mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y); +} + +static DWORD WINAPI test_peer_main_loop(LPVOID lpParam) +{ + int rcount; + void* rfds[32]; + testPeerContext* context; + freerdp_peer* client = (freerdp_peer*) lpParam; + + memset(rfds, 0, sizeof(rfds)); + + test_peer_init(client); + + /* Initialize the real server settings here */ + client->settings->cert_file = xstrdup("server.crt"); + client->settings->privatekey_file = xstrdup("server.key"); + client->settings->nla_security = false; + client->settings->rfx_codec = true; + + client->PostConnect = tf_peer_post_connect; + client->Activate = tf_peer_activate; + + client->input->SynchronizeEvent = tf_peer_synchronize_event; + client->input->KeyboardEvent = tf_peer_keyboard_event; + client->input->UnicodeKeyboardEvent = tf_peer_unicode_keyboard_event; + client->input->MouseEvent = tf_peer_mouse_event; + client->input->ExtendedMouseEvent = tf_peer_extended_mouse_event; + + client->Initialize(client); + context = (testPeerContext*) client->context; + + printf("We've got a client %s\n", client->local ? "(local)" : client->hostname); + + while (1) + { + rcount = 0; + + if (client->GetFileDescriptor(client, rfds, &rcount) != true) + { + printf("Failed to get FreeRDP file descriptor\n"); + break; + } + + if (client->CheckFileDescriptor(client) != true) + break; + } + + printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname); + + client->Disconnect(client); + freerdp_peer_context_free(client); + freerdp_peer_free(client); + + return 0; +} + +static void test_peer_accepted(freerdp_listener* instance, freerdp_peer* client) +{ + /* start peer main loop thread */ + + if (CreateThread(NULL, 0, test_peer_main_loop, client, 0, NULL) != 0) + g_thread_count++; +} + +static void test_server_main_loop(freerdp_listener* instance) +{ + int rcount; + void* rfds[32]; + + memset(rfds, 0, sizeof(rfds)); + + while (1) + { + rcount = 0; + + if (instance->GetFileDescriptor(instance, rfds, &rcount) != true) + { + printf("Failed to get FreeRDP file descriptor\n"); + break; + } + + if (instance->CheckFileDescriptor(instance) != true) + { + printf("Failed to check FreeRDP file descriptor\n"); + break; + } + } + + instance->Close(instance); +} + +#define WFREERDP_SERVER_LOCAL_FILE "wfreerdp-server.0" + +int main(int argc, char* argv[]) +{ + int port = 3389; + char* temp_path; + char* local_file; + WSADATA wsa_data; + freerdp_listener* instance; + + instance = freerdp_listener_new(); + + instance->PeerAccepted = test_peer_accepted; + + if (WSAStartup(0x101, &wsa_data) != 0) + return 1; + + g_done_event = CreateEvent(0, 1, 0, 0); + + if (argc == 2) + port = atoi(argv[1]); + + temp_path = getenv("TEMP"); + local_file = (char*) malloc(strlen(temp_path) + strlen(WFREERDP_SERVER_LOCAL_FILE) + 2); + sprintf(local_file, "%s\\%s", temp_path, WFREERDP_SERVER_LOCAL_FILE); + + /* Open the server socket and start listening. */ + + if (instance->Open(instance, NULL, port) && instance->OpenLocal(instance, local_file)) + { + /* Entering the server main loop. In a real server the listener can be run in its own thread. */ + test_server_main_loop(instance); + } + + if (g_thread_count > 0) + WaitForSingleObject(g_done_event, INFINITE); + else + MessageBox(GetConsoleWindow(), + L"Failed to start wfreerdp-server.\n\nPlease check the debug output.", + L"FreeRDP Error", MB_ICONSTOP); + + WSACleanup(); + + freerdp_listener_free(instance); + + return 0; +} +