Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-core / listener.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * RDP Server Listener
4  *
5  * Copyright 2011 Vic Lee
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <freerdp/utils/print.h>
25
26 #ifndef _WIN32
27 #include <netdb.h>
28 #include <unistd.h>
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
33 #include <net/if.h>
34 #else
35 #define close(_fd) closesocket(_fd)
36 #endif
37
38 #include "listener.h"
39
40 static boolean freerdp_listener_open(freerdp_listener* instance, const char* bind_address, uint16 port)
41 {
42         rdpListener* listener = (rdpListener*)instance->listener;
43         int status;
44         int sockfd;
45         char servname[10];
46         struct addrinfo hints = { 0 };
47         struct addrinfo* res;
48         struct addrinfo* ai;
49         int option_value;
50         void* sin_addr;
51         char buf[50];
52 #ifdef _WIN32
53         u_long arg;
54 #endif
55
56         hints.ai_family = AF_UNSPEC;
57         hints.ai_socktype = SOCK_STREAM;
58         if (bind_address == NULL)
59                 hints.ai_flags = AI_PASSIVE;
60
61         snprintf(servname, sizeof(servname), "%d", port);
62         status = getaddrinfo(bind_address, servname, &hints, &res);
63         if (status != 0)
64         {
65                 perror("getaddrinfo");
66                 return false;
67         }
68
69         for (ai = res; ai && listener->num_sockfds < 5; ai = ai->ai_next)
70         {
71                 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
72                         continue;
73
74                 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
75                 if (sockfd == -1)
76                 {
77                         perror("socket");
78                         continue;
79                 }
80
81                 option_value = 1;
82
83                 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*) &option_value, sizeof(option_value)) == -1)
84                         perror("setsockopt");
85
86 #ifndef _WIN32
87                 fcntl(sockfd, F_SETFL, O_NONBLOCK);
88 #else
89                 arg = 1;
90                 ioctlsocket(sockfd, FIONBIO, &arg);
91 #endif
92
93                 status = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
94                 if (status != 0)
95                 {
96                         perror("bind");
97                         close(sockfd);
98                         continue;
99                 }
100
101                 status = listen(sockfd, 10);
102                 if (status != 0)
103                 {
104                         perror("listen");
105                         close(sockfd);
106                         continue;
107                 }
108
109                 listener->sockfds[listener->num_sockfds++] = sockfd;
110
111                 if (ai->ai_family == AF_INET)
112                         sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr);
113                 else
114                         sin_addr = &(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr);
115
116                 printf("Listening on %s port %s.\n", inet_ntop(ai->ai_family, sin_addr, buf, sizeof(buf)), servname);
117         }
118
119         freeaddrinfo(res);
120
121         return (listener->num_sockfds > 0 ? true : false);
122 }
123
124 static void freerdp_listener_close(freerdp_listener* instance)
125 {
126         int i;
127
128         rdpListener* listener = (rdpListener*)instance->listener;
129
130         for (i = 0; i < listener->num_sockfds; i++)
131         {
132                 close(listener->sockfds[i]);
133         }
134         listener->num_sockfds = 0;
135 }
136
137 static boolean freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
138 {
139         rdpListener* listener = (rdpListener*)instance->listener;
140         int i;
141
142         if (listener->num_sockfds < 1)
143                 return false;
144
145         for (i = 0; i < listener->num_sockfds; i++)
146         {
147                 rfds[*rcount] = (void*)(long)(listener->sockfds[i]);
148                 (*rcount)++;
149         }
150
151         return true;
152 }
153
154 static boolean freerdp_listener_check_fds(freerdp_listener* instance)
155 {
156         rdpListener* listener = (rdpListener*)instance->listener;
157         struct sockaddr_storage peer_addr;
158         socklen_t peer_addr_size;
159         int peer_sockfd;
160         int i;
161         freerdp_peer* client;
162         void* sin_addr;
163
164         if (listener->num_sockfds < 1)
165                 return false;
166
167         for (i = 0; i < listener->num_sockfds; i++)
168         {
169                 peer_addr_size = sizeof(peer_addr);
170                 peer_sockfd = accept(listener->sockfds[i], (struct sockaddr *)&peer_addr, &peer_addr_size);
171
172                 if (peer_sockfd == -1)
173                 {
174 #ifdef _WIN32
175                         int wsa_error = WSAGetLastError();
176
177                         /* No data available */
178                         if (wsa_error == WSAEWOULDBLOCK)
179                                 continue;
180 #else
181                         if (errno == EAGAIN || errno == EWOULDBLOCK)
182                                 continue;
183 #endif
184                         perror("accept");
185                         return false;
186                 }
187
188                 client = freerdp_peer_new(peer_sockfd);
189
190                 if (peer_addr.ss_family == AF_INET)
191                         sin_addr = &(((struct sockaddr_in*)&peer_addr)->sin_addr);
192                 else
193                         sin_addr = &(((struct sockaddr_in6*)&peer_addr)->sin6_addr);
194                 inet_ntop(peer_addr.ss_family, sin_addr, client->hostname, sizeof(client->hostname));
195
196                 IFCALL(instance->PeerAccepted, instance, client);
197         }
198
199         return true;
200 }
201
202 freerdp_listener* freerdp_listener_new(void)
203 {
204         freerdp_listener* instance;
205         rdpListener* listener;
206
207         instance = xnew(freerdp_listener);
208         instance->Open = freerdp_listener_open;
209         instance->GetFileDescriptor = freerdp_listener_get_fds;
210         instance->CheckFileDescriptor = freerdp_listener_check_fds;
211         instance->Close = freerdp_listener_close;
212
213         listener = xnew(rdpListener);
214         listener->instance = instance;
215
216         instance->listener = (void*)listener;
217
218         return instance;
219 }
220
221 void freerdp_listener_free(freerdp_listener* instance)
222 {
223         rdpListener* listener;
224
225         listener = (rdpListener*)instance->listener;
226         xfree(listener);
227
228         xfree(instance);
229 }
230