diff --git a/CMakeLists.txt b/CMakeLists.txt index e52db4d8a..64d844b51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,3 +133,4 @@ if(NOT WIN32) endif() add_subdirectory(client) +add_subdirectory(server) diff --git a/include/freerdp/listener.h b/include/freerdp/listener.h new file mode 100644 index 000000000..4aed16b11 --- /dev/null +++ b/include/freerdp/listener.h @@ -0,0 +1,64 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RDP Server Listener + * + * Copyright 2011 Vic Lee + * + * 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. + */ + +#ifndef __FREERDP_LISTENER_H +#define __FREERDP_LISTENER_H + +typedef struct rdp_freerdp_listener freerdp_listener; + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef boolean (*pcListenerOpen)(freerdp_listener* instance, const char* bind_address, uint16 port); +typedef boolean (*pcListenerGetFileDescriptor)(freerdp_listener* instance, void** rfds, int* rcount); +typedef boolean (*pcListenerCheckFileDescriptor)(freerdp_listener* instance); +typedef void (*pcListenerClose)(freerdp_listener* instance); +typedef void (*pcPeerAccepted)(freerdp_listener* instance, freerdp_peer* client); + +struct rdp_freerdp_listener +{ + void* listener; + void* param1; + void* param2; + void* param3; + void* param4; + + pcListenerOpen Open; + pcListenerGetFileDescriptor GetFileDescriptor; + pcListenerCheckFileDescriptor CheckFileDescriptor; + pcListenerClose Close; + + pcPeerAccepted PeerAccepted; +}; + +FREERDP_API freerdp_listener* freerdp_listener_new(void); +FREERDP_API void freerdp_listener_free(freerdp_listener* instance); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h new file mode 100644 index 000000000..953ac9bb7 --- /dev/null +++ b/include/freerdp/peer.h @@ -0,0 +1,54 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RDP Server Peer + * + * Copyright 2011 Vic Lee + * + * 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. + */ + +#ifndef __FREERDP_PEER_H +#define __FREERDP_PEER_H + +typedef struct rdp_freerdp_peer freerdp_peer; + +#include +#include +#include + +typedef boolean (*pcPeerInitialize)(freerdp_peer* client); +typedef boolean (*pcPeerGetFileDescriptor)(freerdp_peer* client, void** rfds, int* rcount); +typedef boolean (*pcPeerCheckFileDescriptor)(freerdp_peer* client); +typedef void (*pcPeerDisconnect)(freerdp_peer* client); + +struct rdp_freerdp_peer +{ + void* peer; + void* param1; + void* param2; + void* param3; + void* param4; + + rdpSettings* settings; + + pcPeerInitialize Initialize; + pcPeerGetFileDescriptor GetFileDescriptor; + pcPeerCheckFileDescriptor CheckFileDescriptor; + pcPeerDisconnect Disconnect; +}; + +FREERDP_API freerdp_peer* freerdp_peer_new(int sockfd); +FREERDP_API void freerdp_peer_free(freerdp_peer* client); + +#endif /* __FREERDP_PEER_H */ + diff --git a/libfreerdp-core/CMakeLists.txt b/libfreerdp-core/CMakeLists.txt index 50f5f5191..208a7aa50 100644 --- a/libfreerdp-core/CMakeLists.txt +++ b/libfreerdp-core/CMakeLists.txt @@ -84,6 +84,10 @@ set(LIBFREERDP_CORE_SRCS vchan.h window.c window.h + listener.c + listener.h + peer.c + peer.h ) add_library(freerdp-core SHARED ${LIBFREERDP_CORE_SRCS}) diff --git a/libfreerdp-core/listener.c b/libfreerdp-core/listener.c new file mode 100644 index 000000000..90da74624 --- /dev/null +++ b/libfreerdp-core/listener.c @@ -0,0 +1,215 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RDP Server Listener + * + * Copyright 2011 Vic Lee + * + * 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 + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#else +#define close(_fd) closesocket(_fd) +#endif + +#include "listener.h" + +static boolean freerdp_listener_open(freerdp_listener* instance, const char* bind_address, uint16 port) +{ + rdpListener* listener = (rdpListener*)instance->listener; + int status; + int sockfd; + char servname[10]; + struct addrinfo hints = { 0 }; + struct addrinfo* res; + struct addrinfo* ai; + int option_value; + void* sin_addr; + char buf[50]; + + 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) + { + perror("getaddrinfo"); + return False; + } + + for (ai = res; ai && listener->num_sockfds < 5; ai = ai->ai_next) + { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + + sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sockfd == -1) + { + perror("socket"); + continue; + } + + option_value = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option_value, sizeof(option_value)) == -1) + { + perror("setsockopt"); + } + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + status = bind(sockfd, ai->ai_addr, ai->ai_addrlen); + if (status != 0) + { + perror("bind"); + close(sockfd); + continue; + } + + status = listen(sockfd, 10); + if (status != 0) + { + perror("listen"); + close(sockfd); + continue; + } + + listener->sockfds[listener->num_sockfds++] = sockfd; + + if (ai->ai_family == AF_INET) + sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr); + else + 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); + } + + freeaddrinfo(res); + + return (listener->num_sockfds > 0 ? True : False); +} + +static void freerdp_listener_close(freerdp_listener* instance) +{ + int i; + + rdpListener* listener = (rdpListener*)instance->listener; + + for (i = 0; i < listener->num_sockfds; i++) + { + close(listener->sockfds[i]); + } + listener->num_sockfds = 0; +} + +static boolean freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount) +{ + rdpListener* listener = (rdpListener*)instance->listener; + int i; + + if (listener->num_sockfds < 1) + return False; + + for (i = 0; i < listener->num_sockfds; i++) + { + rfds[*rcount] = (void*)(long)(listener->sockfds[i]); + (*rcount)++; + } + + return True; +} + +static boolean freerdp_listener_check_fds(freerdp_listener* instance) +{ + rdpListener* listener = (rdpListener*)instance->listener; + struct sockaddr_storage peer_addr; + socklen_t peer_addr_size; + int peer_sockfd; + int i; + freerdp_peer* client; + void* sin_addr; + + if (listener->num_sockfds < 1) + return False; + + for (i = 0; i < listener->num_sockfds; i++) + { + peer_addr_size = sizeof(peer_addr); + peer_sockfd = accept(listener->sockfds[i], (struct sockaddr *)&peer_addr, &peer_addr_size); + if (peer_sockfd == -1) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + + perror("accept"); + return False; + } + + client = freerdp_peer_new(peer_sockfd); + + if (peer_addr.ss_family == AF_INET) + sin_addr = &(((struct sockaddr_in*)&peer_addr)->sin_addr); + else + sin_addr = &(((struct sockaddr_in6*)&peer_addr)->sin6_addr); + client->settings->hostname = xzalloc(50); + inet_ntop(peer_addr.ss_family, sin_addr, client->settings->hostname, 50); + + printf("Accepted client from %s.\n", client->settings->hostname); + + IFCALL(instance->PeerAccepted, instance, client); + } + + return True; +} + +freerdp_listener* freerdp_listener_new(void) +{ + freerdp_listener* instance; + rdpListener* listener; + + instance = xnew(freerdp_listener); + instance->Open = freerdp_listener_open; + instance->GetFileDescriptor = freerdp_listener_get_fds; + instance->CheckFileDescriptor = freerdp_listener_check_fds; + instance->Close = freerdp_listener_close; + + listener = xnew(rdpListener); + listener->instance = instance; + + instance->listener = (void*)listener; + + return instance; +} + +void freerdp_listener_free(freerdp_listener* instance) +{ + rdpListener* listener; + + listener = (rdpListener*)instance->listener; + xfree(listener); + + xfree(instance); +} + diff --git a/libfreerdp-core/listener.h b/libfreerdp-core/listener.h new file mode 100644 index 000000000..78a755288 --- /dev/null +++ b/libfreerdp-core/listener.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RDP Server Listener + * + * Copyright 2011 Vic Lee + * + * 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. + */ + +#ifndef __LISTENER_H +#define __LISTENER_H + +typedef struct rdp_listener rdpListener; + +#include "rdp.h" +#include + +struct rdp_listener +{ + freerdp_listener* instance; + + int sockfds[5]; + int num_sockfds; +}; + +#endif + diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c new file mode 100644 index 000000000..38decd9d1 --- /dev/null +++ b/libfreerdp-core/peer.c @@ -0,0 +1,76 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RDP Server Peer + * + * Copyright 2011 Vic Lee + * + * 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 "peer.h" + +static boolean freerdp_peer_initialize(freerdp_peer* client) +{ + return True; +} + +static boolean freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) +{ + rdpPeer* peer = (rdpPeer*)client->peer; + + rfds[*rcount] = (void*)(long)(peer->sockfd); + (*rcount)++; + + return True; +} + +static boolean freerdp_peer_check_fds(freerdp_peer* client) +{ + return True; +} + +static void freerdp_peer_disconnect(freerdp_peer* client) +{ +} + +freerdp_peer* freerdp_peer_new(int sockfd) +{ + freerdp_peer* client; + rdpPeer* peer; + + client = xnew(freerdp_peer); + + client->settings = settings_new(); + client->Initialize = freerdp_peer_initialize; + client->GetFileDescriptor = freerdp_peer_get_fds; + client->CheckFileDescriptor = freerdp_peer_check_fds; + client->Disconnect = freerdp_peer_disconnect; + + peer = xnew(rdpPeer); + peer->client = client; + peer->sockfd = sockfd; + + client->peer = (void*)peer; + + return client; +} + +void freerdp_peer_free(freerdp_peer* client) +{ + rdpPeer* peer = (rdpPeer*)client->peer; + + xfree(peer); + settings_free(client->settings); + xfree(client); +} + diff --git a/libfreerdp-core/peer.h b/libfreerdp-core/peer.h new file mode 100644 index 000000000..bb12ff78d --- /dev/null +++ b/libfreerdp-core/peer.h @@ -0,0 +1,36 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RDP Server Peer + * + * Copyright 2011 Vic Lee + * + * 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. + */ + +#ifndef __PEER +#define __PEER + +typedef struct rdp_peer rdpPeer; + +#include "rdp.h" +#include + +struct rdp_peer +{ + freerdp_peer* client; + + int sockfd; +}; + +#endif /* __PEER */ + diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt new file mode 100644 index 000000000..18c935acb --- /dev/null +++ b/server/CMakeLists.txt @@ -0,0 +1,27 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP Servers +# +# 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. + +# Servers + +if(NOT WIN32) + + # Build Test Server + add_subdirectory(test) + +endif() diff --git a/server/test/CMakeLists.txt b/server/test/CMakeLists.txt new file mode 100644 index 000000000..91b7841c6 --- /dev/null +++ b/server/test/CMakeLists.txt @@ -0,0 +1,25 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP Test 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(freerdp-server-test + freerdp_server.c) + +target_link_libraries(freerdp-server-test freerdp-core) +target_link_libraries(freerdp-server-test freerdp-utils) +target_link_libraries(freerdp-server-test freerdp-rfx) diff --git a/server/test/freerdp_server.c b/server/test/freerdp_server.c new file mode 100644 index 000000000..ffc585189 --- /dev/null +++ b/server/test/freerdp_server.c @@ -0,0 +1,183 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Test Server + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void* test_peer_mainloop(void* arg) +{ + freerdp_peer* client = (freerdp_peer*)arg; + int i; + int fds; + int max_fds; + int rcount; + void* rfds[32]; + fd_set rfds_set; + + memset(rfds, 0, sizeof(rfds)); + + printf("We've got a client %s\n", client->settings->hostname); + + client->Initialize(client); + + while (1) + { + rcount = 0; + + if (client->GetFileDescriptor(client, rfds, &rcount) != True) + { + printf("Failed to get FreeRDP file descriptor\n"); + break; + } + + max_fds = 0; + FD_ZERO(&rfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) + { + /* these are not really errors */ + if (!((errno == EAGAIN) || + (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || + (errno == EINTR))) /* signal occurred */ + { + printf("select failed\n"); + break; + } + } + + if (client->CheckFileDescriptor(client) != True) + break; + } + + client->Disconnect(client); + freerdp_peer_free(client); + + printf("Client %s disconnected.\n", client->settings->hostname); + + return NULL; +} + +static void test_peer_accepted(freerdp_listener* instance, freerdp_peer* client) +{ + pthread_t th; + + pthread_create(&th, 0, test_peer_mainloop, client); + pthread_detach(th); +} + +static void test_server_mainloop(freerdp_listener* instance) +{ + int i; + int fds; + int max_fds; + int rcount; + void* rfds[32]; + fd_set rfds_set; + + 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; + } + + max_fds = 0; + FD_ZERO(&rfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) + { + /* these are not really errors */ + if (!((errno == EAGAIN) || + (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || + (errno == EINTR))) /* signal occurred */ + { + printf("select failed\n"); + break; + } + } + + if (instance->CheckFileDescriptor(instance) != True) + { + printf("Failed to check FreeRDP file descriptor\n"); + break; + } + } + + instance->Close(instance); +} + +int main(int argc, char* argv[]) +{ + freerdp_listener* instance; + + instance = freerdp_listener_new(); + + instance->PeerAccepted = test_peer_accepted; + + /* Open the server socket and start listening. */ + if (instance->Open(instance, (argc > 1 ? argv[1] : NULL), 3389)) + { + /* Entering the server main loop. In a real server the listener can be run in its own thread. */ + test_server_mainloop(instance); + } + + freerdp_listener_free(instance); + + return 0; +} +