blob: b7c9705fde559285c5d6c8df998473fcdf72eeb4 [file] [log] [blame]
Peter Hinz56885f32011-03-02 22:03:47 +00001/*
Andy Greena0da8a82010-11-08 17:12:19 +00002 * libwebsockets - small server side websockets and web server implementation
Andy Green8f037e42010-12-19 22:13:26 +00003 *
Andy Greena0da8a82010-11-08 17:12:19 +00004 * Copyright (C) 2010 Andy Green <andy@warmcat.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
Andy Green05a0a7b2010-10-31 17:51:39 +000020 */
21
Andy Green7c212cc2010-11-08 20:20:42 +000022#include "private-libwebsockets.h"
Andy Greenff95d7a2010-10-28 22:36:01 +010023
Peter Hinz56885f32011-03-02 22:03:47 +000024#ifdef WIN32
25
26#else
27#include <ifaddrs.h>
28#endif
Andy Green2e24da02011-03-05 16:12:04 +000029
30#ifdef LWS_OPENSSL_SUPPORT
31int openssl_websocket_private_data_index;
32#endif
33
Andy Greenbe93fef2011-02-14 20:25:43 +000034/*
35 * In-place str to lower case
36 */
37
38static void
39strtolower(char *s)
40{
41 while (*s) {
42 *s = tolower(*s);
43 s++;
44 }
45}
46
Andy Green0d338332011-02-12 11:57:43 +000047/* file descriptor hash management */
48
49struct libwebsocket *
Peter Hinz56885f32011-03-02 22:03:47 +000050wsi_from_fd(struct libwebsocket_context *context, int fd)
Andy Green0d338332011-02-12 11:57:43 +000051{
52 int h = LWS_FD_HASH(fd);
53 int n = 0;
54
Peter Hinz56885f32011-03-02 22:03:47 +000055 for (n = 0; n < context->fd_hashtable[h].length; n++)
56 if (context->fd_hashtable[h].wsi[n]->sock == fd)
57 return context->fd_hashtable[h].wsi[n];
Andy Green0d338332011-02-12 11:57:43 +000058
59 return NULL;
60}
61
62int
Peter Hinz56885f32011-03-02 22:03:47 +000063insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi)
Andy Green0d338332011-02-12 11:57:43 +000064{
65 int h = LWS_FD_HASH(wsi->sock);
66
Peter Hinz56885f32011-03-02 22:03:47 +000067 if (context->fd_hashtable[h].length == MAX_CLIENTS - 1) {
Andy Green0d338332011-02-12 11:57:43 +000068 fprintf(stderr, "hash table overflow\n");
69 return 1;
70 }
71
Peter Hinz56885f32011-03-02 22:03:47 +000072 context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi;
Andy Green0d338332011-02-12 11:57:43 +000073
74 return 0;
75}
76
77int
Peter Hinz56885f32011-03-02 22:03:47 +000078delete_from_fd(struct libwebsocket_context *context, int fd)
Andy Green0d338332011-02-12 11:57:43 +000079{
80 int h = LWS_FD_HASH(fd);
81 int n = 0;
82
Peter Hinz56885f32011-03-02 22:03:47 +000083 for (n = 0; n < context->fd_hashtable[h].length; n++)
84 if (context->fd_hashtable[h].wsi[n]->sock == fd) {
85 while (n < context->fd_hashtable[h].length) {
86 context->fd_hashtable[h].wsi[n] =
87 context->fd_hashtable[h].wsi[n + 1];
Andy Green0d338332011-02-12 11:57:43 +000088 n++;
89 }
Peter Hinz56885f32011-03-02 22:03:47 +000090 context->fd_hashtable[h].length--;
Andy Green0d338332011-02-12 11:57:43 +000091
92 return 0;
93 }
94
95 fprintf(stderr, "Failed to find fd %d requested for "
96 "delete in hashtable\n", fd);
97 return 1;
98}
99
Andy Green1f9bf522011-02-14 21:14:37 +0000100#ifdef LWS_OPENSSL_SUPPORT
101static void
102libwebsockets_decode_ssl_error(void)
103{
104 char buf[256];
105 u_long err;
106
107 while ((err = ERR_get_error()) != 0) {
108 ERR_error_string_n(err, buf, sizeof(buf));
109 fprintf(stderr, "*** %s\n", buf);
110 }
111}
112#endif
Andy Green0d338332011-02-12 11:57:43 +0000113
Andy Green32375b72011-02-19 08:32:53 +0000114
115static int
116interface_to_sa(const char* ifname, struct sockaddr_in *addr, size_t addrlen)
117{
118 int rc = -1;
Peter Hinz56885f32011-03-02 22:03:47 +0000119#ifdef WIN32
120 // TODO
121#else
Andy Green32375b72011-02-19 08:32:53 +0000122 struct ifaddrs *ifr;
123 struct ifaddrs *ifc;
124 struct sockaddr_in *sin;
125
126 getifaddrs(&ifr);
127 for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
128 if (strcmp(ifc->ifa_name, ifname))
129 continue;
130 if (ifc->ifa_addr == NULL)
131 continue;
132 sin = (struct sockaddr_in *)ifc->ifa_addr;
133 if (sin->sin_family != AF_INET)
134 continue;
135 memcpy(addr, sin, addrlen);
136 rc = 0;
137 }
138
139 freeifaddrs(ifr);
Peter Hinz56885f32011-03-02 22:03:47 +0000140#endif
Andy Green32375b72011-02-19 08:32:53 +0000141 return rc;
142}
143
Andy Green8f037e42010-12-19 22:13:26 +0000144void
Peter Hinz56885f32011-03-02 22:03:47 +0000145libwebsocket_close_and_free_session(struct libwebsocket_context *context,
Andy Green687b0182011-02-26 11:04:01 +0000146 struct libwebsocket *wsi, enum lws_close_status reason)
Andy Green251f6fa2010-11-03 11:13:06 +0000147{
Andy Greenb45993c2010-12-18 15:13:50 +0000148 int n;
Andy Green62c54d22011-02-14 09:14:25 +0000149 int old_state;
Andy Green5e1fa172011-02-10 09:07:05 +0000150 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 +
151 LWS_SEND_BUFFER_POST_PADDING];
Andy Greenb45993c2010-12-18 15:13:50 +0000152
Andy Green4b6fbe12011-02-14 08:03:48 +0000153 if (!wsi)
Andy Greenb45993c2010-12-18 15:13:50 +0000154 return;
155
Andy Green62c54d22011-02-14 09:14:25 +0000156 old_state = wsi->state;
Andy Green251f6fa2010-11-03 11:13:06 +0000157
Andy Green62c54d22011-02-14 09:14:25 +0000158 if (old_state == WSI_STATE_DEAD_SOCKET)
Andy Green5e1fa172011-02-10 09:07:05 +0000159 return;
160
Andy Green4b6fbe12011-02-14 08:03:48 +0000161 /* remove this fd from wsi mapping hashtable */
162
Peter Hinz56885f32011-03-02 22:03:47 +0000163 delete_from_fd(context, wsi->sock);
Andy Green4b6fbe12011-02-14 08:03:48 +0000164
165 /* delete it from the internal poll list if still present */
166
Peter Hinz56885f32011-03-02 22:03:47 +0000167 for (n = 0; n < context->fds_count; n++) {
168 if (context->fds[n].fd != wsi->sock)
Andy Green4b6fbe12011-02-14 08:03:48 +0000169 continue;
Peter Hinz56885f32011-03-02 22:03:47 +0000170 while (n < context->fds_count - 1) {
171 context->fds[n] = context->fds[n + 1];
Andy Green4b6fbe12011-02-14 08:03:48 +0000172 n++;
173 }
Peter Hinz56885f32011-03-02 22:03:47 +0000174 context->fds_count--;
Andy Green4b6fbe12011-02-14 08:03:48 +0000175 /* we only have to deal with one */
Peter Hinz56885f32011-03-02 22:03:47 +0000176 n = context->fds_count;
Andy Green4b6fbe12011-02-14 08:03:48 +0000177 }
178
179 /* remove also from external POLL support via protocol 0 */
180
Peter Hinz56885f32011-03-02 22:03:47 +0000181 context->protocols[0].callback(context, wsi,
Andy Green4b6fbe12011-02-14 08:03:48 +0000182 LWS_CALLBACK_DEL_POLL_FD, (void *)(long)wsi->sock, NULL, 0);
183
Andy Green687b0182011-02-26 11:04:01 +0000184 wsi->close_reason = reason;
185
Andy Green5e1fa172011-02-10 09:07:05 +0000186 /*
187 * signal we are closing, libsocket_write will
188 * add any necessary version-specific stuff. If the write fails,
189 * no worries we are closing anyway. If we didn't initiate this
190 * close, then our state has been changed to
Andy Green4b6fbe12011-02-14 08:03:48 +0000191 * WSI_STATE_RETURNED_CLOSE_ALREADY and we will skip this
Andy Green5e1fa172011-02-10 09:07:05 +0000192 */
193
Andy Green62c54d22011-02-14 09:14:25 +0000194 if (old_state == WSI_STATE_ESTABLISHED)
Andy Green5e1fa172011-02-10 09:07:05 +0000195 libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 0,
196 LWS_WRITE_CLOSE);
197
Andy Green251f6fa2010-11-03 11:13:06 +0000198 wsi->state = WSI_STATE_DEAD_SOCKET;
199
Andy Green4b6fbe12011-02-14 08:03:48 +0000200 /* tell the user it's all over for this guy */
201
Andy Greend4302732011-02-28 07:45:29 +0000202 if (wsi->protocol && wsi->protocol->callback &&
203 old_state == WSI_STATE_ESTABLISHED)
Peter Hinz56885f32011-03-02 22:03:47 +0000204 wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
Andy Greene77ddd82010-11-13 10:03:47 +0000205 wsi->user_space, NULL, 0);
Andy Green251f6fa2010-11-03 11:13:06 +0000206
Andy Greenef660a92011-03-06 10:29:38 +0000207 /* deallocate any active extension contexts */
208
209 for (n = 0; n < wsi->count_active_extensions; n++) {
210 if (!wsi->active_extensions[n]->callback)
211 continue;
212
213 wsi->active_extensions[n]->callback(context, wsi,
214 LWS_EXT_CALLBACK_DESTROY,
215 wsi->active_extensions_user[n], NULL, 0);
216
217 free(wsi->active_extensions_user[n]);
218 }
219
220 /* free up his parsing allocations */
Andy Green4b6fbe12011-02-14 08:03:48 +0000221
Andy Green251f6fa2010-11-03 11:13:06 +0000222 for (n = 0; n < WSI_TOKEN_COUNT; n++)
223 if (wsi->utf8_token[n].token)
224 free(wsi->utf8_token[n].token);
225
Andy Green0ca6a172010-12-19 20:50:01 +0000226/* fprintf(stderr, "closing fd=%d\n", wsi->sock); */
Andy Green251f6fa2010-11-03 11:13:06 +0000227
Andy Green3faa9c72010-11-08 17:03:03 +0000228#ifdef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000229 if (wsi->ssl) {
Andy Green3faa9c72010-11-08 17:03:03 +0000230 n = SSL_get_fd(wsi->ssl);
231 SSL_shutdown(wsi->ssl);
Peter Hinz56885f32011-03-02 22:03:47 +0000232#ifdef WIN32
233 closesocket(n);
234#else
Andy Green3faa9c72010-11-08 17:03:03 +0000235 close(n);
Peter Hinz56885f32011-03-02 22:03:47 +0000236#endif
Andy Green3faa9c72010-11-08 17:03:03 +0000237 SSL_free(wsi->ssl);
238 } else {
239#endif
240 shutdown(wsi->sock, SHUT_RDWR);
Peter Hinz56885f32011-03-02 22:03:47 +0000241#ifdef WIN32
242 closesocket(wsi->sock);
243#else
Andy Green3faa9c72010-11-08 17:03:03 +0000244 close(wsi->sock);
Peter Hinz56885f32011-03-02 22:03:47 +0000245#endif
Andy Green3faa9c72010-11-08 17:03:03 +0000246#ifdef LWS_OPENSSL_SUPPORT
247 }
248#endif
Andy Green4f3943a2010-11-12 10:44:16 +0000249 if (wsi->user_space)
250 free(wsi->user_space);
251
Andy Green251f6fa2010-11-03 11:13:06 +0000252 free(wsi);
253}
254
Andy Green07034092011-02-13 08:37:12 +0000255/**
Andy Greenf7ee5492011-02-13 09:04:21 +0000256 * libwebsockets_hangup_on_client() - Server calls to terminate client
257 * connection
Peter Hinz56885f32011-03-02 22:03:47 +0000258 * @context: libwebsockets context
Andy Greenf7ee5492011-02-13 09:04:21 +0000259 * @fd: Connection socket descriptor
260 */
261
262void
Peter Hinz56885f32011-03-02 22:03:47 +0000263libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd)
Andy Greenf7ee5492011-02-13 09:04:21 +0000264{
Peter Hinz56885f32011-03-02 22:03:47 +0000265 struct libwebsocket *wsi = wsi_from_fd(context, fd);
Andy Greenf7ee5492011-02-13 09:04:21 +0000266
267 if (wsi == NULL)
268 return;
269
Peter Hinz56885f32011-03-02 22:03:47 +0000270 libwebsocket_close_and_free_session(context, wsi,
Andy Green6da560c2011-02-26 11:06:27 +0000271 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenf7ee5492011-02-13 09:04:21 +0000272}
273
274
275/**
Andy Green07034092011-02-13 08:37:12 +0000276 * libwebsockets_get_peer_addresses() - Get client address information
277 * @fd: Connection socket descriptor
278 * @name: Buffer to take client address name
279 * @name_len: Length of client address name buffer
280 * @rip: Buffer to take client address IP qotted quad
281 * @rip_len: Length of client address IP buffer
282 *
283 * This function fills in @name and @rip with the name and IP of
284 * the client connected with socket descriptor @fd. Names may be
285 * truncated if there is not enough room. If either cannot be
286 * determined, they will be returned as valid zero-length strings.
287 */
288
289void
290libwebsockets_get_peer_addresses(int fd, char *name, int name_len,
291 char *rip, int rip_len)
292{
293 unsigned int len;
294 struct sockaddr_in sin;
295 struct hostent *host;
296 struct hostent *host1;
297 char ip[128];
298 char *p;
299 int n;
300
301 rip[0] = '\0';
302 name[0] = '\0';
303
304 len = sizeof sin;
305 if (getpeername(fd, (struct sockaddr *) &sin, &len) < 0) {
306 perror("getpeername");
307 return;
308 }
309
310 host = gethostbyaddr((char *) &sin.sin_addr, sizeof sin.sin_addr,
311 AF_INET);
312 if (host == NULL) {
313 perror("gethostbyaddr");
314 return;
315 }
316
317 strncpy(name, host->h_name, name_len);
318 name[name_len - 1] = '\0';
319
320 host1 = gethostbyname(host->h_name);
321 if (host1 == NULL)
322 return;
323 p = (char *)host1;
324 n = 0;
325 while (p != NULL) {
326 p = host1->h_addr_list[n++];
327 if (p == NULL)
328 continue;
329 if (host1->h_addrtype != AF_INET)
330 continue;
331
332 sprintf(ip, "%d.%d.%d.%d",
333 p[0], p[1], p[2], p[3]);
334 p = NULL;
335 strncpy(rip, ip, rip_len);
336 rip[rip_len - 1] = '\0';
337 }
338}
Andy Green9f990342011-02-12 11:57:45 +0000339
Peter Hinz56885f32011-03-02 22:03:47 +0000340int libwebsockets_get_random(struct libwebsocket_context *context,
341 void *buf, int len)
342{
343 int n;
344 char *p = buf;
345
346#ifdef WIN32
347 for (n = 0; n < len; n++)
348 p[n] = (unsigned char)rand();
349#else
350 n = read(context->fd_random, p, len);
351#endif
352
353 return n;
354}
355
Andy Greeneeaacb32011-03-01 20:44:24 +0000356void libwebsockets_00_spaceout(char *key, int spaces, int seed)
357{
358 char *p;
Peter Hinz56885f32011-03-02 22:03:47 +0000359
Andy Greeneeaacb32011-03-01 20:44:24 +0000360 key++;
361 while (spaces--) {
362 if (*key && (seed & 1))
363 key++;
364 seed >>= 1;
Peter Hinz56885f32011-03-02 22:03:47 +0000365
Andy Greeneeaacb32011-03-01 20:44:24 +0000366 p = key + strlen(key);
367 while (p >= key) {
368 p[1] = p[0];
369 p--;
370 }
371 *key++ = ' ';
372 }
373}
374
375void libwebsockets_00_spam(char *key, int count, int seed)
376{
377 char *p;
378
379 key++;
380 while (count--) {
381
382 if (*key && (seed & 1))
383 key++;
384 seed >>= 1;
385
386 p = key + strlen(key);
387 while (p >= key) {
388 p[1] = p[0];
389 p--;
390 }
391 *key++ = 0x21 + ((seed & 0xffff) % 15);
392 /* 4 would use it up too fast.. not like it matters */
393 seed >>= 1;
394 }
395}
396
Andy Green95a7b5d2011-03-06 10:29:39 +0000397int lws_send_pipe_choked(struct libwebsocket *wsi)
398{
399 struct pollfd fds;
400
401 fds.fd = wsi->sock;
402 fds.events = POLLOUT;
403 fds.revents = 0;
404
405 if (poll(&fds, 1, 0) != 1)
406 return 1;
407
408 if ((fds.revents & POLLOUT) == 0)
409 return 1;
410
411 /* okay to send another packet without blocking */
412
413 return 0;
414}
415
Andy Green9f990342011-02-12 11:57:45 +0000416/**
417 * libwebsocket_service_fd() - Service polled socket with something waiting
Peter Hinz56885f32011-03-02 22:03:47 +0000418 * @context: Websocket context
Andy Green9f990342011-02-12 11:57:45 +0000419 * @pollfd: The pollfd entry describing the socket fd and which events
420 * happened.
421 *
422 * This function closes any active connections and then frees the
423 * context. After calling this, any further use of the context is
424 * undefined.
425 */
426
427int
Peter Hinz56885f32011-03-02 22:03:47 +0000428libwebsocket_service_fd(struct libwebsocket_context *context,
Andy Green0d338332011-02-12 11:57:43 +0000429 struct pollfd *pollfd)
Andy Greenb45993c2010-12-18 15:13:50 +0000430{
431 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BROADCAST_PAYLOAD +
432 LWS_SEND_BUFFER_POST_PADDING];
Andy Greena71eafc2011-02-14 17:59:43 +0000433 struct libwebsocket *wsi;
Andy Green0d338332011-02-12 11:57:43 +0000434 struct libwebsocket *new_wsi;
Andy Greenb45993c2010-12-18 15:13:50 +0000435 int n;
Andy Green0d338332011-02-12 11:57:43 +0000436 int m;
Andy Greenb45993c2010-12-18 15:13:50 +0000437 size_t len;
Andy Green0d338332011-02-12 11:57:43 +0000438 int accept_fd;
439 unsigned int clilen;
440 struct sockaddr_in cli_addr;
Andy Greena71eafc2011-02-14 17:59:43 +0000441 struct timeval tv;
Andy Greenbe93fef2011-02-14 20:25:43 +0000442 static const char magic_websocket_guid[] =
443 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
444 static const char magic_websocket_04_masking_guid[] =
445 "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
446 char hash[20];
447 char pkt[1024];
448 char *p = &pkt[0];
449 const char *pc;
450 int okay = 0;
451#ifdef LWS_OPENSSL_SUPPORT
452 char ssl_err_buf[512];
453#endif
Andy Greena71eafc2011-02-14 17:59:43 +0000454 /*
455 * you can call us with pollfd = NULL to just allow the once-per-second
456 * global timeout checks; if less than a second since the last check
457 * it returns immediately then.
458 */
459
460 gettimeofday(&tv, NULL);
461
Peter Hinz56885f32011-03-02 22:03:47 +0000462 if (context->last_timeout_check_s != tv.tv_sec) {
463 context->last_timeout_check_s = tv.tv_sec;
Andy Greena71eafc2011-02-14 17:59:43 +0000464
465 /* global timeout check once per second */
466
Peter Hinz56885f32011-03-02 22:03:47 +0000467 for (n = 0; n < context->fds_count; n++) {
468 wsi = wsi_from_fd(context, context->fds[n].fd);
Andy Greena71eafc2011-02-14 17:59:43 +0000469 if (!wsi->pending_timeout)
470 continue;
471
472 /*
473 * if we went beyond the allowed time, kill the
474 * connection
475 */
476
477 if (tv.tv_sec > wsi->pending_timeout_limit)
Peter Hinz56885f32011-03-02 22:03:47 +0000478 libwebsocket_close_and_free_session(context,
479 wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena71eafc2011-02-14 17:59:43 +0000480 }
481 }
482
483 /* just here for timeout management? */
484
485 if (pollfd == NULL)
486 return 0;
487
488 /* no, here to service a socket descriptor */
489
Peter Hinz56885f32011-03-02 22:03:47 +0000490 wsi = wsi_from_fd(context, pollfd->fd);
Andy Greenb45993c2010-12-18 15:13:50 +0000491
Andy Green0d338332011-02-12 11:57:43 +0000492 if (wsi == NULL)
493 return 1;
Andy Green8f037e42010-12-19 22:13:26 +0000494
Andy Green0d338332011-02-12 11:57:43 +0000495 switch (wsi->mode) {
496 case LWS_CONNMODE_SERVER_LISTENER:
497
498 /* pollin means a client has connected to us then */
499
500 if (!pollfd->revents & POLLIN)
501 break;
502
503 /* listen socket got an unencrypted connection... */
504
505 clilen = sizeof(cli_addr);
506 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
507 &clilen);
508 if (accept_fd < 0) {
509 fprintf(stderr, "ERROR on accept");
510 break;
511 }
512
Peter Hinz56885f32011-03-02 22:03:47 +0000513 if (context->fds_count >= MAX_CLIENTS) {
Andy Green3221f922011-02-12 13:14:11 +0000514 fprintf(stderr, "too busy to accept new client\n");
Peter Hinz56885f32011-03-02 22:03:47 +0000515#ifdef WIN32
516 closesocket(accept_fd);
517#else
Andy Green0d338332011-02-12 11:57:43 +0000518 close(accept_fd);
Peter Hinz56885f32011-03-02 22:03:47 +0000519#endif
Andy Green0d338332011-02-12 11:57:43 +0000520 break;
521 }
522
Andy Green07034092011-02-13 08:37:12 +0000523 /*
524 * look at who we connected to and give user code a chance
525 * to reject based on client IP. There's no protocol selected
526 * yet so we issue this to protocols[0]
527 */
528
Peter Hinz56885f32011-03-02 22:03:47 +0000529 if ((context->protocols[0].callback)(context, wsi,
Andy Green07034092011-02-13 08:37:12 +0000530 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
531 (void*)(long)accept_fd, NULL, 0)) {
532 fprintf(stderr, "Callback denied network connection\n");
Peter Hinz56885f32011-03-02 22:03:47 +0000533#ifdef WIN32
534 closesocket(accept_fd);
535#else
Andy Green07034092011-02-13 08:37:12 +0000536 close(accept_fd);
Peter Hinz56885f32011-03-02 22:03:47 +0000537#endif
Andy Green07034092011-02-13 08:37:12 +0000538 break;
539 }
540
Andy Green0d338332011-02-12 11:57:43 +0000541 /* accepting connection to main listener */
542
543 new_wsi = malloc(sizeof(struct libwebsocket));
544 if (new_wsi == NULL) {
545 fprintf(stderr, "Out of memory for new connection\n");
546 break;
547 }
548
549 memset(new_wsi, 0, sizeof (struct libwebsocket));
550 new_wsi->sock = accept_fd;
Andy Greend6e09112011-03-05 16:12:15 +0000551 new_wsi->count_active_extensions = 0;
Andy Greena71eafc2011-02-14 17:59:43 +0000552 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Green0d338332011-02-12 11:57:43 +0000553
554#ifdef LWS_OPENSSL_SUPPORT
555 new_wsi->ssl = NULL;
Andy Green0d338332011-02-12 11:57:43 +0000556
Peter Hinz56885f32011-03-02 22:03:47 +0000557 if (context->use_ssl) {
Andy Green0d338332011-02-12 11:57:43 +0000558
Peter Hinz56885f32011-03-02 22:03:47 +0000559 new_wsi->ssl = SSL_new(context->ssl_ctx);
Andy Green0d338332011-02-12 11:57:43 +0000560 if (new_wsi->ssl == NULL) {
561 fprintf(stderr, "SSL_new failed: %s\n",
562 ERR_error_string(SSL_get_error(
563 new_wsi->ssl, 0), NULL));
Andy Green1f9bf522011-02-14 21:14:37 +0000564 libwebsockets_decode_ssl_error();
Andy Green0d338332011-02-12 11:57:43 +0000565 free(new_wsi);
566 break;
567 }
568
569 SSL_set_fd(new_wsi->ssl, accept_fd);
570
571 n = SSL_accept(new_wsi->ssl);
572 if (n != 1) {
573 /*
574 * browsers seem to probe with various
575 * ssl params which fail then retry
576 * and succeed
577 */
578 debug("SSL_accept failed skt %u: %s\n",
579 pollfd->fd,
580 ERR_error_string(SSL_get_error(
581 new_wsi->ssl, n), NULL));
582 SSL_free(
583 new_wsi->ssl);
584 free(new_wsi);
585 break;
586 }
Andy Greenc6bf2c22011-02-20 11:10:47 +0000587
Andy Green0d338332011-02-12 11:57:43 +0000588 debug("accepted new SSL conn "
589 "port %u on fd=%d SSL ver %s\n",
590 ntohs(cli_addr.sin_port), accept_fd,
591 SSL_get_version(new_wsi->ssl));
592
593 } else
594#endif
595 debug("accepted new conn port %u on fd=%d\n",
596 ntohs(cli_addr.sin_port), accept_fd);
597
598 /* intialize the instance struct */
599
600 new_wsi->state = WSI_STATE_HTTP;
601 new_wsi->name_buffer_pos = 0;
602 new_wsi->mode = LWS_CONNMODE_WS_SERVING;
603
604 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
605 new_wsi->utf8_token[n].token = NULL;
606 new_wsi->utf8_token[n].token_len = 0;
607 }
608
609 /*
610 * these can only be set once the protocol is known
611 * we set an unestablished connection's protocol pointer
612 * to the start of the supported list, so it can look
613 * for matching ones during the handshake
614 */
Peter Hinz56885f32011-03-02 22:03:47 +0000615 new_wsi->protocol = context->protocols;
Andy Green0d338332011-02-12 11:57:43 +0000616 new_wsi->user_space = NULL;
617
618 /*
619 * Default protocol is 76 / 00
620 * After 76, there's a header specified to inform which
621 * draft the client wants, when that's seen we modify
622 * the individual connection's spec revision accordingly
623 */
624 new_wsi->ietf_spec_revision = 0;
625
Peter Hinz56885f32011-03-02 22:03:47 +0000626 insert_wsi(context, new_wsi);
Andy Green0d338332011-02-12 11:57:43 +0000627
Andy Green0d338332011-02-12 11:57:43 +0000628 /*
629 * make sure NO events are seen yet on this new socket
630 * (otherwise we inherit old fds[client].revents from
631 * previous socket there and die mysteriously! )
632 */
Peter Hinz56885f32011-03-02 22:03:47 +0000633 context->fds[context->fds_count].revents = 0;
Andy Green0d338332011-02-12 11:57:43 +0000634
Peter Hinz56885f32011-03-02 22:03:47 +0000635 context->fds[context->fds_count].events = POLLIN;
636 context->fds[context->fds_count++].fd = accept_fd;
Andy Green0d338332011-02-12 11:57:43 +0000637
Andy Green3221f922011-02-12 13:14:11 +0000638 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000639 context->protocols[0].callback(context, new_wsi,
Andy Green3221f922011-02-12 13:14:11 +0000640 LWS_CALLBACK_ADD_POLL_FD,
641 (void *)(long)accept_fd, NULL, POLLIN);
642
Andy Green0d338332011-02-12 11:57:43 +0000643 break;
644
645 case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
646
647 /* as we are listening, POLLIN means accept() is needed */
648
649 if (!pollfd->revents & POLLIN)
650 break;
651
652 /* listen socket got an unencrypted connection... */
653
654 clilen = sizeof(cli_addr);
655 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
656 &clilen);
657 if (accept_fd < 0) {
658 fprintf(stderr, "ERROR on accept");
659 break;
660 }
661
Peter Hinz56885f32011-03-02 22:03:47 +0000662 if (context->fds_count >= MAX_CLIENTS) {
Andy Green3221f922011-02-12 13:14:11 +0000663 fprintf(stderr, "too busy to accept new broadcast "
664 "proxy client\n");
Peter Hinz56885f32011-03-02 22:03:47 +0000665#ifdef WIN32
666 closesocket(accept_fd);
667#else
Andy Green0d338332011-02-12 11:57:43 +0000668 close(accept_fd);
Peter Hinz56885f32011-03-02 22:03:47 +0000669#endif
Andy Green0d338332011-02-12 11:57:43 +0000670 break;
671 }
672
673 /* create a dummy wsi for the connection and add it */
674
675 new_wsi = malloc(sizeof(struct libwebsocket));
676 memset(new_wsi, 0, sizeof (struct libwebsocket));
677 new_wsi->sock = accept_fd;
678 new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY;
679 new_wsi->state = WSI_STATE_ESTABLISHED;
Andy Greend6e09112011-03-05 16:12:15 +0000680 new_wsi->count_active_extensions = 0;
Andy Green0d338332011-02-12 11:57:43 +0000681 /* note which protocol we are proxying */
682 new_wsi->protocol_index_for_broadcast_proxy =
683 wsi->protocol_index_for_broadcast_proxy;
Peter Hinz56885f32011-03-02 22:03:47 +0000684 insert_wsi(context, new_wsi);
Andy Green0d338332011-02-12 11:57:43 +0000685
686 /* add connected socket to internal poll array */
687
Peter Hinz56885f32011-03-02 22:03:47 +0000688 context->fds[context->fds_count].revents = 0;
689 context->fds[context->fds_count].events = POLLIN;
690 context->fds[context->fds_count++].fd = accept_fd;
Andy Green0d338332011-02-12 11:57:43 +0000691
Andy Green3221f922011-02-12 13:14:11 +0000692 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000693 context->protocols[0].callback(context, new_wsi,
Andy Green3221f922011-02-12 13:14:11 +0000694 LWS_CALLBACK_ADD_POLL_FD,
695 (void *)(long)accept_fd, NULL, POLLIN);
696
Andy Green0d338332011-02-12 11:57:43 +0000697 break;
698
699 case LWS_CONNMODE_BROADCAST_PROXY:
Andy Green8f037e42010-12-19 22:13:26 +0000700
Andy Greenb45993c2010-12-18 15:13:50 +0000701 /* handle session socket closed */
Andy Green8f037e42010-12-19 22:13:26 +0000702
Andy Green0d338332011-02-12 11:57:43 +0000703 if (pollfd->revents & (POLLERR | POLLHUP)) {
Andy Green8f037e42010-12-19 22:13:26 +0000704
Andy Green0d338332011-02-12 11:57:43 +0000705 debug("Session Socket %p (fd=%d) dead\n",
Timothy J Fontaineb86d64e2011-02-14 17:55:27 +0000706 (void *)wsi, pollfd->fd);
Andy Greenb45993c2010-12-18 15:13:50 +0000707
Peter Hinz56885f32011-03-02 22:03:47 +0000708 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000709 LWS_CLOSE_STATUS_NORMAL);
Andy Green4b6fbe12011-02-14 08:03:48 +0000710 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +0000711 }
Andy Green8f037e42010-12-19 22:13:26 +0000712
Andy Green90c7cbc2011-01-27 06:26:52 +0000713 /* the guy requested a callback when it was OK to write */
714
Andy Green0d338332011-02-12 11:57:43 +0000715 if (pollfd->revents & POLLOUT) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000716
Andy Green0d338332011-02-12 11:57:43 +0000717 /* one shot */
Andy Green90c7cbc2011-01-27 06:26:52 +0000718
Andy Green0d338332011-02-12 11:57:43 +0000719 pollfd->events &= ~POLLOUT;
720
Andy Green3221f922011-02-12 13:14:11 +0000721 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000722 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +0000723 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
724 (void *)(long)wsi->sock, NULL, POLLOUT);
725
Peter Hinz56885f32011-03-02 22:03:47 +0000726 wsi->protocol->callback(context, wsi,
Andy Green90c7cbc2011-01-27 06:26:52 +0000727 LWS_CALLBACK_CLIENT_WRITEABLE,
Andy Green0d338332011-02-12 11:57:43 +0000728 wsi->user_space,
Andy Green90c7cbc2011-01-27 06:26:52 +0000729 NULL, 0);
730 }
731
Andy Greenb45993c2010-12-18 15:13:50 +0000732 /* any incoming data ready? */
733
Andy Green0d338332011-02-12 11:57:43 +0000734 if (!(pollfd->revents & POLLIN))
735 break;
Andy Greenb45993c2010-12-18 15:13:50 +0000736
Andy Green0d338332011-02-12 11:57:43 +0000737 /* get the issued broadcast payload from the socket */
Andy Greenb45993c2010-12-18 15:13:50 +0000738
Andy Green0d338332011-02-12 11:57:43 +0000739 len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING,
740 MAX_BROADCAST_PAYLOAD);
741 if (len < 0) {
742 fprintf(stderr, "Error reading broadcast payload\n");
Andy Green4b6fbe12011-02-14 08:03:48 +0000743 break;
Andy Green0d338332011-02-12 11:57:43 +0000744 }
Andy Greenb45993c2010-12-18 15:13:50 +0000745
Andy Green0d338332011-02-12 11:57:43 +0000746 /* broadcast it to all guys with this protocol index */
Andy Green8f037e42010-12-19 22:13:26 +0000747
Andy Green0d338332011-02-12 11:57:43 +0000748 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
Andy Green8f037e42010-12-19 22:13:26 +0000749
Peter Hinz56885f32011-03-02 22:03:47 +0000750 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Greenb45993c2010-12-18 15:13:50 +0000751
Peter Hinz56885f32011-03-02 22:03:47 +0000752 new_wsi = context->fd_hashtable[n].wsi[m];
Andy Greenb45993c2010-12-18 15:13:50 +0000753
Andy Green0d338332011-02-12 11:57:43 +0000754 /* only to clients we are serving to */
Andy Greenb45993c2010-12-18 15:13:50 +0000755
Andy Green0d338332011-02-12 11:57:43 +0000756 if (new_wsi->mode != LWS_CONNMODE_WS_SERVING)
Andy Greenb45993c2010-12-18 15:13:50 +0000757 continue;
758
759 /*
760 * never broadcast to non-established
761 * connection
762 */
763
Andy Green0d338332011-02-12 11:57:43 +0000764 if (new_wsi->state != WSI_STATE_ESTABLISHED)
Andy Green4739e5c2011-01-22 12:51:57 +0000765 continue;
766
Andy Greenb45993c2010-12-18 15:13:50 +0000767 /*
768 * only broadcast to connections using
769 * the requested protocol
770 */
771
Andy Green0d338332011-02-12 11:57:43 +0000772 if (new_wsi->protocol->protocol_index !=
773 wsi->protocol_index_for_broadcast_proxy)
Andy Greenb45993c2010-12-18 15:13:50 +0000774 continue;
775
Andy Green8f037e42010-12-19 22:13:26 +0000776 /* broadcast it to this connection */
777
Peter Hinz56885f32011-03-02 22:03:47 +0000778 new_wsi->protocol->callback(context, new_wsi,
Andy Green8f037e42010-12-19 22:13:26 +0000779 LWS_CALLBACK_BROADCAST,
Andy Green0d338332011-02-12 11:57:43 +0000780 new_wsi->user_space,
Andy Green0ca6a172010-12-19 20:50:01 +0000781 buf + LWS_SEND_BUFFER_PRE_PADDING, len);
Andy Greenb45993c2010-12-18 15:13:50 +0000782 }
Andy Green0d338332011-02-12 11:57:43 +0000783 }
784 break;
Andy Greenb45993c2010-12-18 15:13:50 +0000785
Andy Greenbe93fef2011-02-14 20:25:43 +0000786 case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
787
788 /* handle proxy hung up on us */
789
790 if (pollfd->revents & (POLLERR | POLLHUP)) {
791
792 fprintf(stderr, "Proxy connection %p (fd=%d) dead\n",
793 (void *)wsi, pollfd->fd);
794
Peter Hinz56885f32011-03-02 22:03:47 +0000795 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000796 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000797 return 1;
798 }
799
800 n = recv(wsi->sock, pkt, sizeof pkt, 0);
801 if (n < 0) {
Peter Hinz56885f32011-03-02 22:03:47 +0000802 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000803 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000804 fprintf(stderr, "ERROR reading from proxy socket\n");
805 return 1;
806 }
807
808 pkt[13] = '\0';
809 if (strcmp(pkt, "HTTP/1.0 200 ") != 0) {
Peter Hinz56885f32011-03-02 22:03:47 +0000810 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000811 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000812 fprintf(stderr, "ERROR from proxy: %s\n", pkt);
813 return 1;
814 }
815
816 /* clear his proxy connection timeout */
817
818 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
819
820 /* fallthru */
821
822 case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
823
824 #ifdef LWS_OPENSSL_SUPPORT
825 if (wsi->use_ssl) {
826
Peter Hinz56885f32011-03-02 22:03:47 +0000827 wsi->ssl = SSL_new(context->ssl_client_ctx);
828 wsi->client_bio = BIO_new_socket(wsi->sock,
829 BIO_NOCLOSE);
Andy Greenbe93fef2011-02-14 20:25:43 +0000830 SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
831
Andy Green6901cb32011-02-21 08:06:47 +0000832 SSL_set_ex_data(wsi->ssl,
Andy Green2e24da02011-03-05 16:12:04 +0000833 openssl_websocket_private_data_index,
Peter Hinz56885f32011-03-02 22:03:47 +0000834 context);
Andy Green6901cb32011-02-21 08:06:47 +0000835
Andy Greenbe93fef2011-02-14 20:25:43 +0000836 if (SSL_connect(wsi->ssl) <= 0) {
837 fprintf(stderr, "SSL connect error %s\n",
Andy Green687b0182011-02-26 11:04:01 +0000838 ERR_error_string(ERR_get_error(),
839 ssl_err_buf));
Peter Hinz56885f32011-03-02 22:03:47 +0000840 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000841 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000842 return 1;
843 }
844
845 n = SSL_get_verify_result(wsi->ssl);
Andy Green2e24da02011-03-05 16:12:04 +0000846 if ((n != X509_V_OK) && (
Andy Green687b0182011-02-26 11:04:01 +0000847 n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
848 wsi->use_ssl != 2)) {
Andy Greenbe93fef2011-02-14 20:25:43 +0000849
Andy Green687b0182011-02-26 11:04:01 +0000850 fprintf(stderr, "server's cert didn't "
851 "look good %d\n", n);
Peter Hinz56885f32011-03-02 22:03:47 +0000852 libwebsocket_close_and_free_session(context,
853 wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Green687b0182011-02-26 11:04:01 +0000854 return 1;
Andy Greenbe93fef2011-02-14 20:25:43 +0000855 }
856 } else {
857 wsi->ssl = NULL;
858 #endif
859
860
861 #ifdef LWS_OPENSSL_SUPPORT
862 }
863 #endif
864
865 /*
866 * create the random key
867 */
868
Peter Hinz56885f32011-03-02 22:03:47 +0000869 n = libwebsockets_get_random(context, hash, 16);
Andy Greenbe93fef2011-02-14 20:25:43 +0000870 if (n != 16) {
871 fprintf(stderr, "Unable to read from random dev %s\n",
872 SYSTEM_RANDOM_FILEPATH);
873 free(wsi->c_path);
874 free(wsi->c_host);
Andy Green08d33922011-02-26 10:22:49 +0000875 if (wsi->c_origin)
876 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000877 if (wsi->c_protocol)
878 free(wsi->c_protocol);
Peter Hinz56885f32011-03-02 22:03:47 +0000879 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000880 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000881 return 1;
882 }
883
884 lws_b64_encode_string(hash, 16, wsi->key_b64,
885 sizeof wsi->key_b64);
886
887 /*
Andy Greeneeaacb32011-03-01 20:44:24 +0000888 * 00 example client handshake
889 *
890 * GET /socket.io/websocket HTTP/1.1
891 * Upgrade: WebSocket
892 * Connection: Upgrade
893 * Host: 127.0.0.1:9999
894 * Origin: http://127.0.0.1
895 * Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^
896 * Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
897 * Cookie: socketio=websocket
898 *
899 * (Á®Ä0¶†≥
900 *
Andy Greenbe93fef2011-02-14 20:25:43 +0000901 * 04 example client handshake
902 *
903 * GET /chat HTTP/1.1
904 * Host: server.example.com
905 * Upgrade: websocket
906 * Connection: Upgrade
907 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
908 * Sec-WebSocket-Origin: http://example.com
909 * Sec-WebSocket-Protocol: chat, superchat
910 * Sec-WebSocket-Version: 4
911 */
912
Andy Green08d33922011-02-26 10:22:49 +0000913 p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", wsi->c_path);
Andy Greeneeaacb32011-03-01 20:44:24 +0000914
915 if (wsi->ietf_spec_revision == 0) {
916 unsigned char spaces_1, spaces_2;
917 unsigned int max_1, max_2;
918 unsigned int num_1, num_2;
919 unsigned long product_1, product_2;
920 char key_1[40];
921 char key_2[40];
922 unsigned int seed;
923 unsigned int count;
924 char challenge[16];
925
Peter Hinz56885f32011-03-02 22:03:47 +0000926 libwebsockets_get_random(context, &spaces_1,
927 sizeof(char));
928 libwebsockets_get_random(context, &spaces_2,
929 sizeof(char));
930
Andy Greeneeaacb32011-03-01 20:44:24 +0000931 spaces_1 = (spaces_1 % 12) + 1;
932 spaces_2 = (spaces_2 % 12) + 1;
Peter Hinz56885f32011-03-02 22:03:47 +0000933
Andy Greeneeaacb32011-03-01 20:44:24 +0000934 max_1 = 4294967295 / spaces_1;
935 max_2 = 4294967295 / spaces_2;
936
Peter Hinz56885f32011-03-02 22:03:47 +0000937 libwebsockets_get_random(context, &num_1, sizeof(int));
938 libwebsockets_get_random(context, &num_2, sizeof(int));
939
Andy Greeneeaacb32011-03-01 20:44:24 +0000940 num_1 = (num_1 % max_1);
941 num_2 = (num_2 % max_2);
Peter Hinz56885f32011-03-02 22:03:47 +0000942
Andy Greeneeaacb32011-03-01 20:44:24 +0000943 challenge[0] = num_1 >> 24;
944 challenge[1] = num_1 >> 16;
945 challenge[2] = num_1 >> 8;
946 challenge[3] = num_1;
947 challenge[4] = num_2 >> 24;
948 challenge[5] = num_2 >> 16;
949 challenge[6] = num_2 >> 8;
950 challenge[7] = num_2;
Peter Hinz56885f32011-03-02 22:03:47 +0000951
Andy Greeneeaacb32011-03-01 20:44:24 +0000952 product_1 = num_1 * spaces_1;
953 product_2 = num_2 * spaces_2;
Peter Hinz56885f32011-03-02 22:03:47 +0000954
Andy Greeneeaacb32011-03-01 20:44:24 +0000955 sprintf(key_1, "%lu", product_1);
956 sprintf(key_2, "%lu", product_2);
957
Peter Hinz56885f32011-03-02 22:03:47 +0000958 libwebsockets_get_random(context, &seed, sizeof(int));
959 libwebsockets_get_random(context, &count, sizeof(int));
960
Andy Greeneeaacb32011-03-01 20:44:24 +0000961 libwebsockets_00_spam(key_1, (count % 12) + 1, seed);
Peter Hinz56885f32011-03-02 22:03:47 +0000962
963 libwebsockets_get_random(context, &seed, sizeof(int));
964 libwebsockets_get_random(context, &count, sizeof(int));
965
Andy Greeneeaacb32011-03-01 20:44:24 +0000966 libwebsockets_00_spam(key_2, (count % 12) + 1, seed);
Peter Hinz56885f32011-03-02 22:03:47 +0000967
968 libwebsockets_get_random(context, &seed, sizeof(int));
969
Andy Greeneeaacb32011-03-01 20:44:24 +0000970 libwebsockets_00_spaceout(key_1, spaces_1, seed);
971 libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16);
Peter Hinz56885f32011-03-02 22:03:47 +0000972
Andy Greeneeaacb32011-03-01 20:44:24 +0000973 p += sprintf(p, "Upgrade: websocket\x0d\x0a"
974 "Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000975 wsi->c_host);
Andy Greeneeaacb32011-03-01 20:44:24 +0000976 if (wsi->c_origin)
977 p += sprintf(p, "Origin: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000978 wsi->c_origin);
979
Andy Greeneeaacb32011-03-01 20:44:24 +0000980 if (wsi->c_protocol)
Peter Hinz56885f32011-03-02 22:03:47 +0000981 p += sprintf(p, "Sec-WebSocket-Protocol: %s"
982 "\x0d\x0a", wsi->c_protocol);
983
Andy Greeneeaacb32011-03-01 20:44:24 +0000984 p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000985 key_1);
Andy Greeneeaacb32011-03-01 20:44:24 +0000986 p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000987 key_2);
Andy Greeneeaacb32011-03-01 20:44:24 +0000988
Andy Green385e7ad2011-03-01 21:06:02 +0000989 /* give userland a chance to append, eg, cookies */
Peter Hinz56885f32011-03-02 22:03:47 +0000990
991 context->protocols[0].callback(context, wsi,
992 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
Andy Green385e7ad2011-03-01 21:06:02 +0000993 NULL, &p, (pkt + sizeof(pkt)) - p - 12);
994
Andy Greeneeaacb32011-03-01 20:44:24 +0000995 p += sprintf(p, "\x0d\x0a");
Peter Hinz56885f32011-03-02 22:03:47 +0000996
997 read(context->fd_random, p, 8);
Andy Greeneeaacb32011-03-01 20:44:24 +0000998 memcpy(&challenge[8], p, 8);
999 p += 8;
Peter Hinz56885f32011-03-02 22:03:47 +00001000
Andy Greeneeaacb32011-03-01 20:44:24 +00001001 /* precompute what we want to see from the server */
Peter Hinz56885f32011-03-02 22:03:47 +00001002
Andy Greeneeaacb32011-03-01 20:44:24 +00001003 MD5((unsigned char *)challenge, 16,
1004 (unsigned char *)wsi->initial_handshake_hash_base64);
Peter Hinz56885f32011-03-02 22:03:47 +00001005
Andy Greeneeaacb32011-03-01 20:44:24 +00001006 goto issue_hdr;
1007 }
1008
Andy Green08d33922011-02-26 10:22:49 +00001009 p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host);
1010 p += sprintf(p, "Upgrade: websocket\x0d\x0a");
1011 p += sprintf(p, "Connection: Upgrade\x0d\x0a"
Andy Greenbe93fef2011-02-14 20:25:43 +00001012 "Sec-WebSocket-Key: ");
Andy Green08d33922011-02-26 10:22:49 +00001013 strcpy(p, wsi->key_b64);
1014 p += strlen(wsi->key_b64);
1015 p += sprintf(p, "\x0d\x0a");
1016 if (wsi->c_origin)
1017 p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a",
Andy Greenbe93fef2011-02-14 20:25:43 +00001018 wsi->c_origin);
Andy Green08d33922011-02-26 10:22:49 +00001019 if (wsi->c_protocol)
Andy Greenbe93fef2011-02-14 20:25:43 +00001020 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
1021 wsi->c_protocol);
Andy Green385e7ad2011-03-01 21:06:02 +00001022 p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +00001023 wsi->ietf_spec_revision);
Andy Green385e7ad2011-03-01 21:06:02 +00001024 /* give userland a chance to append, eg, cookies */
Peter Hinz56885f32011-03-02 22:03:47 +00001025
1026 context->protocols[0].callback(context, wsi,
1027 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
1028 NULL, &p, (pkt + sizeof(pkt)) - p - 12);
1029
Andy Green385e7ad2011-03-01 21:06:02 +00001030 p += sprintf(p, "\x0d\x0a");
1031
Andy Greenbe93fef2011-02-14 20:25:43 +00001032 /* prepare the expected server accept response */
1033
1034 strcpy((char *)buf, wsi->key_b64);
1035 strcpy((char *)&buf[strlen((char *)buf)], magic_websocket_guid);
1036
1037 SHA1(buf, strlen((char *)buf), (unsigned char *)hash);
1038
1039 lws_b64_encode_string(hash, 20,
1040 wsi->initial_handshake_hash_base64,
1041 sizeof wsi->initial_handshake_hash_base64);
Peter Hinz56885f32011-03-02 22:03:47 +00001042
Andy Greeneeaacb32011-03-01 20:44:24 +00001043issue_hdr:
Peter Hinz56885f32011-03-02 22:03:47 +00001044
Andy Greeneeaacb32011-03-01 20:44:24 +00001045 /* done with these now */
Peter Hinz56885f32011-03-02 22:03:47 +00001046
Andy Greeneeaacb32011-03-01 20:44:24 +00001047 free(wsi->c_path);
1048 free(wsi->c_host);
1049 if (wsi->c_origin)
1050 free(wsi->c_origin);
1051
Andy Greenbe93fef2011-02-14 20:25:43 +00001052 /* send our request to the server */
1053
1054 #ifdef LWS_OPENSSL_SUPPORT
1055 if (wsi->use_ssl)
1056 n = SSL_write(wsi->ssl, pkt, p - pkt);
1057 else
1058 #endif
1059 n = send(wsi->sock, pkt, p - pkt, 0);
1060
1061 if (n < 0) {
1062 fprintf(stderr, "ERROR writing to client socket\n");
Peter Hinz56885f32011-03-02 22:03:47 +00001063 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001064 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +00001065 return 1;
1066 }
1067
1068 wsi->parser_state = WSI_TOKEN_NAME_PART;
1069 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY;
1070 libwebsocket_set_timeout(wsi,
1071 PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, 5);
1072
1073 break;
1074
1075 case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
1076
1077 /* handle server hung up on us */
1078
1079 if (pollfd->revents & (POLLERR | POLLHUP)) {
1080
1081 fprintf(stderr, "Server connection %p (fd=%d) dead\n",
1082 (void *)wsi, pollfd->fd);
1083
1084 goto bail3;
1085 }
1086
1087
1088 /* interpret the server response */
1089
1090 /*
1091 * HTTP/1.1 101 Switching Protocols
1092 * Upgrade: websocket
1093 * Connection: Upgrade
1094 * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
1095 * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
1096 * Sec-WebSocket-Protocol: chat
1097 */
1098
1099 #ifdef LWS_OPENSSL_SUPPORT
1100 if (wsi->use_ssl)
1101 len = SSL_read(wsi->ssl, pkt, sizeof pkt);
1102 else
1103 #endif
1104 len = recv(wsi->sock, pkt, sizeof pkt, 0);
1105
1106 if (len < 0) {
1107 fprintf(stderr,
1108 "libwebsocket_client_handshake read error\n");
1109 goto bail3;
1110 }
1111
1112 p = pkt;
1113 for (n = 0; n < len; n++)
1114 libwebsocket_parse(wsi, *p++);
1115
1116 if (wsi->parser_state != WSI_PARSING_COMPLETE) {
1117 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001118 "server response failed parsing\n");
Andy Greenbe93fef2011-02-14 20:25:43 +00001119 goto bail3;
1120 }
1121
1122 /*
Andy Greeneeaacb32011-03-01 20:44:24 +00001123 * 00 / 76 -->
1124 *
1125 * HTTP/1.1 101 WebSocket Protocol Handshake
1126 * Upgrade: WebSocket
1127 * Connection: Upgrade
1128 * Sec-WebSocket-Origin: http://127.0.0.1
1129 * Sec-WebSocket-Location: ws://127.0.0.1:9999/socket.io/websocket
1130 *
1131 * xxxxxxxxxxxxxxxx
1132 */
Peter Hinz56885f32011-03-02 22:03:47 +00001133
Andy Greeneeaacb32011-03-01 20:44:24 +00001134 if (wsi->ietf_spec_revision == 0) {
1135 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
Peter Hinz56885f32011-03-02 22:03:47 +00001136 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
1137 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
1138 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
1139 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
1140 wsi->c_protocol != NULL)) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001141 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001142 "missing required header(s)\n");
Andy Greeneeaacb32011-03-01 20:44:24 +00001143 pkt[len] = '\0';
1144 fprintf(stderr, "%s", pkt);
1145 goto bail3;
1146 }
Andy Greeneeaacb32011-03-01 20:44:24 +00001147
Peter Hinz56885f32011-03-02 22:03:47 +00001148 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
1149 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
1150 "101 websocket protocol handshake")) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001151 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001152 "server sent bad HTTP response '%s'\n",
1153 wsi->utf8_token[WSI_TOKEN_HTTP].token);
1154 goto bail3;
1155 }
1156
1157 if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len <
1158 16) {
1159 fprintf(stderr, "libwebsocket_client_handshake "
1160 "challenge reply too short %d\n",
1161 wsi->utf8_token[
1162 WSI_TOKEN_CHALLENGE].token_len);
Andy Greeneeaacb32011-03-01 20:44:24 +00001163 pkt[len] = '\0';
1164 fprintf(stderr, "%s", pkt);
1165 goto bail3;
Peter Hinz56885f32011-03-02 22:03:47 +00001166
Andy Greeneeaacb32011-03-01 20:44:24 +00001167 }
Peter Hinz56885f32011-03-02 22:03:47 +00001168
Andy Greeneeaacb32011-03-01 20:44:24 +00001169 goto select_protocol;
1170 }
Peter Hinz56885f32011-03-02 22:03:47 +00001171
Andy Greeneeaacb32011-03-01 20:44:24 +00001172 /*
Andy Greenbe93fef2011-02-14 20:25:43 +00001173 * well, what the server sent looked reasonable for syntax.
1174 * Now let's confirm it sent all the necessary headers
1175 */
1176
1177 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
1178 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
1179 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
1180 !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len ||
Andy Green4eaa86b2011-02-26 11:17:48 +00001181 (!wsi->utf8_token[WSI_TOKEN_NONCE].token_len &&
1182 wsi->ietf_spec_revision == 4) ||
Andy Greenbe93fef2011-02-14 20:25:43 +00001183 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
1184 wsi->c_protocol != NULL)) {
1185 fprintf(stderr, "libwebsocket_client_handshake "
Andy Green687b0182011-02-26 11:04:01 +00001186 "missing required header(s)\n");
Andy Greenbe93fef2011-02-14 20:25:43 +00001187 pkt[len] = '\0';
1188 fprintf(stderr, "%s", pkt);
1189 goto bail3;
1190 }
1191
1192 /*
1193 * Everything seems to be there, now take a closer look at what
1194 * is in each header
1195 */
1196
1197 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
1198 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
1199 "101 switching protocols")) {
1200 fprintf(stderr, "libwebsocket_client_handshake "
1201 "server sent bad HTTP response '%s'\n",
1202 wsi->utf8_token[WSI_TOKEN_HTTP].token);
1203 goto bail3;
1204 }
1205
1206 strtolower(wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
1207 if (strcmp(wsi->utf8_token[WSI_TOKEN_UPGRADE].token,
1208 "websocket")) {
1209 fprintf(stderr, "libwebsocket_client_handshake server "
1210 "sent bad Upgrade header '%s'\n",
1211 wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
1212 goto bail3;
1213 }
1214
1215 strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
1216 if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token,
1217 "upgrade")) {
1218 fprintf(stderr, "libwebsocket_client_handshake server "
1219 "sent bad Connection hdr '%s'\n",
1220 wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
1221 goto bail3;
1222 }
1223
Andy Greeneeaacb32011-03-01 20:44:24 +00001224select_protocol:
Andy Greenbe93fef2011-02-14 20:25:43 +00001225 pc = wsi->c_protocol;
1226
1227 /*
1228 * confirm the protocol the server wants to talk was in the list
1229 * of protocols we offered
1230 */
1231
1232 if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
1233
1234 /*
1235 * no protocol name to work from,
1236 * default to first protocol
1237 */
Peter Hinz56885f32011-03-02 22:03:47 +00001238 wsi->protocol = &context->protocols[0];
Andy Greenbe93fef2011-02-14 20:25:43 +00001239
1240 free(wsi->c_protocol);
1241
1242 goto check_accept;
1243 }
1244
1245 while (*pc && !okay) {
1246 if ((!strncmp(pc,
1247 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
1248 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len)) &&
1249 (pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == ',' ||
1250 pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == '\0')) {
1251 okay = 1;
1252 continue;
1253 }
1254 while (*pc && *pc != ',')
1255 pc++;
1256 while (*pc && *pc != ' ')
1257 pc++;
1258 }
1259
1260 /* done with him now */
1261
1262 if (wsi->c_protocol)
1263 free(wsi->c_protocol);
1264
1265
1266 if (!okay) {
1267 fprintf(stderr, "libwebsocket_client_handshake server "
1268 "sent bad protocol '%s'\n",
1269 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
1270 goto bail2;
1271 }
1272
1273 /*
1274 * identify the selected protocol struct and set it
1275 */
1276 n = 0;
1277 wsi->protocol = NULL;
Peter Hinz56885f32011-03-02 22:03:47 +00001278 while (context->protocols[n].callback) {
Andy Greenbe93fef2011-02-14 20:25:43 +00001279 if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
Peter Hinz56885f32011-03-02 22:03:47 +00001280 context->protocols[n].name) == 0)
1281 wsi->protocol = &context->protocols[n];
Andy Greenbe93fef2011-02-14 20:25:43 +00001282 n++;
1283 }
1284
1285 if (wsi->protocol == NULL) {
1286 fprintf(stderr, "libwebsocket_client_handshake server "
1287 "requested protocol '%s', which we "
1288 "said we supported but we don't!\n",
1289 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
1290 goto bail2;
1291 }
1292
1293 check_accept:
Andy Greeneeaacb32011-03-01 20:44:24 +00001294
1295 if (wsi->ietf_spec_revision == 0) {
Peter Hinz56885f32011-03-02 22:03:47 +00001296
Andy Greeneeaacb32011-03-01 20:44:24 +00001297 if (memcmp(wsi->initial_handshake_hash_base64,
Peter Hinz56885f32011-03-02 22:03:47 +00001298 wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001299 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001300 "failed 00 challenge compare\n");
1301 pkt[len] = '\0';
1302 fprintf(stderr, "%s", pkt);
1303 goto bail2;
Andy Greeneeaacb32011-03-01 20:44:24 +00001304 }
Peter Hinz56885f32011-03-02 22:03:47 +00001305
Andy Greeneeaacb32011-03-01 20:44:24 +00001306 goto accept_ok;
1307 }
Peter Hinz56885f32011-03-02 22:03:47 +00001308
Andy Greenbe93fef2011-02-14 20:25:43 +00001309 /*
1310 * Confirm his accept token is the one we precomputed
1311 */
1312
1313 if (strcmp(wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
1314 wsi->initial_handshake_hash_base64)) {
1315 fprintf(stderr, "libwebsocket_client_handshake server "
1316 "sent bad ACCEPT '%s' vs computed '%s'\n",
1317 wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
1318 wsi->initial_handshake_hash_base64);
1319 goto bail2;
1320 }
1321
Andy Green4eaa86b2011-02-26 11:17:48 +00001322 if (wsi->ietf_spec_revision == 4) {
1323 /*
1324 * Calculate the 04 masking key to use when
1325 * sending data to server
1326 */
Andy Greenbe93fef2011-02-14 20:25:43 +00001327
Andy Green4eaa86b2011-02-26 11:17:48 +00001328 strcpy((char *)buf, wsi->key_b64);
1329 p = (char *)buf + strlen(wsi->key_b64);
1330 strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token);
1331 p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len;
1332 strcpy(p, magic_websocket_04_masking_guid);
1333 SHA1(buf, strlen((char *)buf), wsi->masking_key_04);
1334 }
Andy Greeneeaacb32011-03-01 20:44:24 +00001335accept_ok:
1336
Andy Greenbe93fef2011-02-14 20:25:43 +00001337 /* allocate the per-connection user memory (if any) */
1338
1339 if (wsi->protocol->per_session_data_size) {
1340 wsi->user_space = malloc(
1341 wsi->protocol->per_session_data_size);
1342 if (wsi->user_space == NULL) {
1343 fprintf(stderr, "Out of memory for "
1344 "conn user space\n");
1345 goto bail2;
1346 }
1347 } else
1348 wsi->user_space = NULL;
1349
1350 /* clear his proxy connection timeout */
1351
1352 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1353
1354 /* mark him as being alive */
1355
1356 wsi->state = WSI_STATE_ESTABLISHED;
1357 wsi->mode = LWS_CONNMODE_WS_CLIENT;
1358
1359 fprintf(stderr, "handshake OK for protocol %s\n",
1360 wsi->protocol->name);
1361
1362 /* call him back to inform him he is up */
1363
Peter Hinz56885f32011-03-02 22:03:47 +00001364 wsi->protocol->callback(context, wsi,
Andy Greenbe93fef2011-02-14 20:25:43 +00001365 LWS_CALLBACK_CLIENT_ESTABLISHED,
1366 wsi->user_space,
1367 NULL, 0);
1368
1369 break;
1370
1371bail3:
1372 if (wsi->c_protocol)
1373 free(wsi->c_protocol);
1374
1375bail2:
Peter Hinz56885f32011-03-02 22:03:47 +00001376 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001377 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +00001378 return 1;
1379
1380
Andy Green0d338332011-02-12 11:57:43 +00001381 case LWS_CONNMODE_WS_SERVING:
1382 case LWS_CONNMODE_WS_CLIENT:
1383
1384 /* handle session socket closed */
1385
1386 if (pollfd->revents & (POLLERR | POLLHUP)) {
1387
Andy Green62c54d22011-02-14 09:14:25 +00001388 fprintf(stderr, "Session Socket %p (fd=%d) dead\n",
Andy Green0d338332011-02-12 11:57:43 +00001389 (void *)wsi, pollfd->fd);
1390
Peter Hinz56885f32011-03-02 22:03:47 +00001391 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001392 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green4b6fbe12011-02-14 08:03:48 +00001393 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001394 }
1395
Andy Green0d338332011-02-12 11:57:43 +00001396 /* the guy requested a callback when it was OK to write */
1397
1398 if (pollfd->revents & POLLOUT) {
1399
1400 pollfd->events &= ~POLLOUT;
1401
Andy Green3221f922011-02-12 13:14:11 +00001402 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001403 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001404 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
1405 (void *)(long)wsi->sock, NULL, POLLOUT);
1406
Peter Hinz56885f32011-03-02 22:03:47 +00001407 wsi->protocol->callback(context, wsi,
Andy Green0d338332011-02-12 11:57:43 +00001408 LWS_CALLBACK_CLIENT_WRITEABLE,
1409 wsi->user_space,
1410 NULL, 0);
1411 }
1412
1413 /* any incoming data ready? */
1414
1415 if (!(pollfd->revents & POLLIN))
1416 break;
1417
Andy Greenb45993c2010-12-18 15:13:50 +00001418#ifdef LWS_OPENSSL_SUPPORT
Andy Green0d338332011-02-12 11:57:43 +00001419 if (wsi->ssl)
1420 n = SSL_read(wsi->ssl, buf, sizeof buf);
Andy Greenb45993c2010-12-18 15:13:50 +00001421 else
1422#endif
Andy Green0d338332011-02-12 11:57:43 +00001423 n = recv(pollfd->fd, buf, sizeof buf, 0);
Andy Greenb45993c2010-12-18 15:13:50 +00001424
1425 if (n < 0) {
1426 fprintf(stderr, "Socket read returned %d\n", n);
Andy Green4b6fbe12011-02-14 08:03:48 +00001427 break;
Andy Greenb45993c2010-12-18 15:13:50 +00001428 }
1429 if (!n) {
Peter Hinz56885f32011-03-02 22:03:47 +00001430 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001431 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green4b6fbe12011-02-14 08:03:48 +00001432 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001433 }
1434
Andy Greenb45993c2010-12-18 15:13:50 +00001435 /* service incoming data */
1436
Peter Hinz56885f32011-03-02 22:03:47 +00001437 n = libwebsocket_read(context, wsi, buf, n);
Andy Green6964bb52011-01-23 16:50:33 +00001438 if (n >= 0)
Andy Green4b6fbe12011-02-14 08:03:48 +00001439 break;
Andy Greenb45993c2010-12-18 15:13:50 +00001440
Andy Green4b6fbe12011-02-14 08:03:48 +00001441 /* we closed wsi */
Andy Green0d338332011-02-12 11:57:43 +00001442
Andy Green4b6fbe12011-02-14 08:03:48 +00001443 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001444 }
1445
1446 return 0;
1447}
1448
Andy Green0d338332011-02-12 11:57:43 +00001449
Andy Green6964bb52011-01-23 16:50:33 +00001450/**
1451 * libwebsocket_context_destroy() - Destroy the websocket context
Peter Hinz56885f32011-03-02 22:03:47 +00001452 * @context: Websocket context
Andy Green6964bb52011-01-23 16:50:33 +00001453 *
1454 * This function closes any active connections and then frees the
1455 * context. After calling this, any further use of the context is
1456 * undefined.
1457 */
1458void
Peter Hinz56885f32011-03-02 22:03:47 +00001459libwebsocket_context_destroy(struct libwebsocket_context *context)
Andy Green6964bb52011-01-23 16:50:33 +00001460{
Andy Green0d338332011-02-12 11:57:43 +00001461 int n;
1462 int m;
1463 struct libwebsocket *wsi;
Andy Green6964bb52011-01-23 16:50:33 +00001464
Andy Green4b6fbe12011-02-14 08:03:48 +00001465 for (n = 0; n < FD_HASHTABLE_MODULUS; n++)
Peter Hinz56885f32011-03-02 22:03:47 +00001466 for (m = 0; m < context->fd_hashtable[n].length; m++) {
1467 wsi = context->fd_hashtable[n].wsi[m];
1468 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001469 LWS_CLOSE_STATUS_GOINGAWAY);
Andy Greenf3d3b402011-02-09 07:16:34 +00001470 }
Andy Green6964bb52011-01-23 16:50:33 +00001471
Peter Hinz56885f32011-03-02 22:03:47 +00001472#ifdef WIN32
1473#else
1474 close(context->fd_random);
Andy Green6964bb52011-01-23 16:50:33 +00001475#endif
1476
Peter Hinz56885f32011-03-02 22:03:47 +00001477#ifdef LWS_OPENSSL_SUPPORT
1478 if (context->ssl_ctx)
1479 SSL_CTX_free(context->ssl_ctx);
1480 if (context->ssl_client_ctx)
1481 SSL_CTX_free(context->ssl_client_ctx);
1482#endif
1483
1484 free(context);
1485
1486#ifdef WIN32
1487 WSACleanup();
1488#endif
Andy Green6964bb52011-01-23 16:50:33 +00001489}
1490
1491/**
1492 * libwebsocket_service() - Service any pending websocket activity
Peter Hinz56885f32011-03-02 22:03:47 +00001493 * @context: Websocket context
Andy Green6964bb52011-01-23 16:50:33 +00001494 * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed
1495 * service otherwise block and service immediately, returning
1496 * after the timeout if nothing needed service.
1497 *
1498 * This function deals with any pending websocket traffic, for three
1499 * kinds of event. It handles these events on both server and client
1500 * types of connection the same.
1501 *
1502 * 1) Accept new connections to our context's server
1503 *
1504 * 2) Perform pending broadcast writes initiated from other forked
1505 * processes (effectively serializing asynchronous broadcasts)
1506 *
1507 * 3) Call the receive callback for incoming frame data received by
1508 * server or client connections.
1509 *
1510 * You need to call this service function periodically to all the above
1511 * functions to happen; if your application is single-threaded you can
1512 * just call it in your main event loop.
1513 *
1514 * Alternatively you can fork a new process that asynchronously handles
1515 * calling this service in a loop. In that case you are happy if this
1516 * call blocks your thread until it needs to take care of something and
1517 * would call it with a large nonzero timeout. Your loop then takes no
1518 * CPU while there is nothing happening.
1519 *
1520 * If you are calling it in a single-threaded app, you don't want it to
1521 * wait around blocking other things in your loop from happening, so you
1522 * would call it with a timeout_ms of 0, so it returns immediately if
1523 * nothing is pending, or as soon as it services whatever was pending.
1524 */
1525
Andy Greenb45993c2010-12-18 15:13:50 +00001526
Andy Greene92cd172011-01-19 13:11:55 +00001527int
Peter Hinz56885f32011-03-02 22:03:47 +00001528libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
Andy Greene92cd172011-01-19 13:11:55 +00001529{
1530 int n;
Andy Greene92cd172011-01-19 13:11:55 +00001531
1532 /* stay dead once we are dead */
1533
Peter Hinz56885f32011-03-02 22:03:47 +00001534 if (context == NULL)
Andy Greene92cd172011-01-19 13:11:55 +00001535 return 1;
1536
Andy Green0d338332011-02-12 11:57:43 +00001537 /* wait for something to need service */
Andy Green4739e5c2011-01-22 12:51:57 +00001538
Peter Hinz56885f32011-03-02 22:03:47 +00001539 n = poll(context->fds, context->fds_count, timeout_ms);
Andy Green3221f922011-02-12 13:14:11 +00001540 if (n == 0) /* poll timeout */
1541 return 0;
Andy Greene92cd172011-01-19 13:11:55 +00001542
Andy Green62c54d22011-02-14 09:14:25 +00001543 if (n < 0) {
Andy Green5e1fa172011-02-10 09:07:05 +00001544 /*
Andy Greene92cd172011-01-19 13:11:55 +00001545 fprintf(stderr, "Listen Socket dead\n");
Andy Green5e1fa172011-02-10 09:07:05 +00001546 */
Andy Green0d338332011-02-12 11:57:43 +00001547 return 1;
Andy Greene92cd172011-01-19 13:11:55 +00001548 }
Andy Greene92cd172011-01-19 13:11:55 +00001549
1550 /* handle accept on listening socket? */
1551
Peter Hinz56885f32011-03-02 22:03:47 +00001552 for (n = 0; n < context->fds_count; n++)
1553 if (context->fds[n].revents)
1554 libwebsocket_service_fd(context, &context->fds[n]);
Andy Greene92cd172011-01-19 13:11:55 +00001555
1556 return 0;
Andy Greene92cd172011-01-19 13:11:55 +00001557}
1558
Andy Green90c7cbc2011-01-27 06:26:52 +00001559/**
1560 * libwebsocket_callback_on_writable() - Request a callback when this socket
1561 * becomes able to be written to without
1562 * blocking
Andy Green32375b72011-02-19 08:32:53 +00001563 *
Peter Hinz56885f32011-03-02 22:03:47 +00001564 * @context: libwebsockets context
Andy Green90c7cbc2011-01-27 06:26:52 +00001565 * @wsi: Websocket connection instance to get callback for
1566 */
1567
1568int
Peter Hinz56885f32011-03-02 22:03:47 +00001569libwebsocket_callback_on_writable(struct libwebsocket_context *context,
Andy Green62c54d22011-02-14 09:14:25 +00001570 struct libwebsocket *wsi)
Andy Green90c7cbc2011-01-27 06:26:52 +00001571{
Andy Green90c7cbc2011-01-27 06:26:52 +00001572 int n;
1573
Peter Hinz56885f32011-03-02 22:03:47 +00001574 for (n = 0; n < context->fds_count; n++)
1575 if (context->fds[n].fd == wsi->sock) {
1576 context->fds[n].events |= POLLOUT;
1577 n = context->fds_count;
Andy Green90c7cbc2011-01-27 06:26:52 +00001578 }
1579
Andy Green3221f922011-02-12 13:14:11 +00001580 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001581 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001582 LWS_CALLBACK_SET_MODE_POLL_FD,
1583 (void *)(long)wsi->sock, NULL, POLLOUT);
1584
Andy Green90c7cbc2011-01-27 06:26:52 +00001585 return 1;
1586}
1587
1588/**
1589 * libwebsocket_callback_on_writable_all_protocol() - Request a callback for
1590 * all connections using the given protocol when it
1591 * becomes possible to write to each socket without
1592 * blocking in turn.
1593 *
1594 * @protocol: Protocol whose connections will get callbacks
1595 */
1596
1597int
1598libwebsocket_callback_on_writable_all_protocol(
1599 const struct libwebsocket_protocols *protocol)
1600{
Peter Hinz56885f32011-03-02 22:03:47 +00001601 struct libwebsocket_context *context = protocol->owning_server;
Andy Green90c7cbc2011-01-27 06:26:52 +00001602 int n;
Andy Green0d338332011-02-12 11:57:43 +00001603 int m;
1604 struct libwebsocket *wsi;
Andy Green90c7cbc2011-01-27 06:26:52 +00001605
Andy Green0d338332011-02-12 11:57:43 +00001606 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
1607
Peter Hinz56885f32011-03-02 22:03:47 +00001608 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Green0d338332011-02-12 11:57:43 +00001609
Peter Hinz56885f32011-03-02 22:03:47 +00001610 wsi = context->fd_hashtable[n].wsi[m];
Andy Green0d338332011-02-12 11:57:43 +00001611
1612 if (wsi->protocol == protocol)
Peter Hinz56885f32011-03-02 22:03:47 +00001613 libwebsocket_callback_on_writable(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00001614 }
1615 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001616
1617 return 0;
1618}
1619
Andy Greenbe93fef2011-02-14 20:25:43 +00001620/**
1621 * libwebsocket_set_timeout() - marks the wsi as subject to a timeout
1622 *
1623 * You will not need this unless you are doing something special
1624 *
1625 * @wsi: Websocket connection instance
1626 * @reason: timeout reason
1627 * @secs: how many seconds
1628 */
1629
1630void
1631libwebsocket_set_timeout(struct libwebsocket *wsi,
1632 enum pending_timeout reason, int secs)
1633{
1634 struct timeval tv;
1635
1636 gettimeofday(&tv, NULL);
1637
1638 wsi->pending_timeout_limit = tv.tv_sec + secs;
1639 wsi->pending_timeout = reason;
1640}
1641
Andy Greena6cbece2011-01-27 20:06:03 +00001642
1643/**
1644 * libwebsocket_get_socket_fd() - returns the socket file descriptor
1645 *
1646 * You will not need this unless you are doing something special
1647 *
1648 * @wsi: Websocket connection instance
1649 */
1650
1651int
1652libwebsocket_get_socket_fd(struct libwebsocket *wsi)
1653{
1654 return wsi->sock;
1655}
1656
Andy Green90c7cbc2011-01-27 06:26:52 +00001657/**
1658 * libwebsocket_rx_flow_control() - Enable and disable socket servicing for
1659 * receieved packets.
1660 *
1661 * If the output side of a server process becomes choked, this allows flow
1662 * control for the input side.
1663 *
1664 * @wsi: Websocket connection instance to get callback for
1665 * @enable: 0 = disable read servicing for this connection, 1 = enable
1666 */
1667
1668int
1669libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
1670{
Peter Hinz56885f32011-03-02 22:03:47 +00001671 struct libwebsocket_context *context = wsi->protocol->owning_server;
Andy Green90c7cbc2011-01-27 06:26:52 +00001672 int n;
1673
Peter Hinz56885f32011-03-02 22:03:47 +00001674 for (n = 0; n < context->fds_count; n++)
1675 if (context->fds[n].fd == wsi->sock) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001676 if (enable)
Peter Hinz56885f32011-03-02 22:03:47 +00001677 context->fds[n].events |= POLLIN;
Andy Green90c7cbc2011-01-27 06:26:52 +00001678 else
Peter Hinz56885f32011-03-02 22:03:47 +00001679 context->fds[n].events &= ~POLLIN;
Andy Green90c7cbc2011-01-27 06:26:52 +00001680
1681 return 0;
1682 }
1683
Andy Green3221f922011-02-12 13:14:11 +00001684 if (enable)
1685 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001686 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001687 LWS_CALLBACK_SET_MODE_POLL_FD,
1688 (void *)(long)wsi->sock, NULL, POLLIN);
1689 else
1690 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001691 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001692 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
1693 (void *)(long)wsi->sock, NULL, POLLIN);
1694
1695
Andy Green90c7cbc2011-01-27 06:26:52 +00001696 fprintf(stderr, "libwebsocket_callback_on_writable "
1697 "unable to find socket\n");
1698 return 1;
1699}
1700
Andy Green2ac5a6f2011-01-28 10:00:18 +00001701/**
1702 * libwebsocket_canonical_hostname() - returns this host's hostname
1703 *
1704 * This is typically used by client code to fill in the host parameter
1705 * when making a client connection. You can only call it after the context
1706 * has been created.
1707 *
Peter Hinz56885f32011-03-02 22:03:47 +00001708 * @context: Websocket context
Andy Green2ac5a6f2011-01-28 10:00:18 +00001709 */
1710
1711
1712extern const char *
Peter Hinz56885f32011-03-02 22:03:47 +00001713libwebsocket_canonical_hostname(struct libwebsocket_context *context)
Andy Green2ac5a6f2011-01-28 10:00:18 +00001714{
Peter Hinz56885f32011-03-02 22:03:47 +00001715 return (const char *)context->canonical_hostname;
Andy Green2ac5a6f2011-01-28 10:00:18 +00001716}
1717
1718
Andy Green90c7cbc2011-01-27 06:26:52 +00001719static void sigpipe_handler(int x)
1720{
1721}
1722
Andy Green6901cb32011-02-21 08:06:47 +00001723#ifdef LWS_OPENSSL_SUPPORT
1724static int
1725OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
1726{
1727
1728 SSL *ssl;
1729 int n;
Andy Green2e24da02011-03-05 16:12:04 +00001730 struct libwebsocket_context *context;
Andy Green6901cb32011-02-21 08:06:47 +00001731
1732 ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
1733 SSL_get_ex_data_X509_STORE_CTX_idx());
1734
1735 /*
Andy Green2e24da02011-03-05 16:12:04 +00001736 * !!! nasty openssl requires the index to come as a library-scope
1737 * static
Andy Green6901cb32011-02-21 08:06:47 +00001738 */
Andy Green2e24da02011-03-05 16:12:04 +00001739 context = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
Andy Green6901cb32011-02-21 08:06:47 +00001740
Peter Hinz56885f32011-03-02 22:03:47 +00001741 n = context->protocols[0].callback(NULL, NULL,
Andy Green6901cb32011-02-21 08:06:47 +00001742 LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
1743 x509_ctx, ssl, preverify_ok);
1744
1745 /* convert return code from 0 = OK to 1 = OK */
1746
1747 if (!n)
1748 n = 1;
1749 else
1750 n = 0;
1751
1752 return n;
1753}
1754#endif
1755
Andy Greenb45993c2010-12-18 15:13:50 +00001756
Andy Greenab990e42010-10-31 12:42:52 +00001757/**
Andy Green4739e5c2011-01-22 12:51:57 +00001758 * libwebsocket_create_context() - Create the websocket handler
1759 * @port: Port to listen on... you can use 0 to suppress listening on
Andy Green6964bb52011-01-23 16:50:33 +00001760 * any port, that's what you want if you are not running a
1761 * websocket server at all but just using it as a client
Peter Hinz56885f32011-03-02 22:03:47 +00001762 * @interf: NULL to bind the listen socket to all interfaces, or the
Andy Green32375b72011-02-19 08:32:53 +00001763 * interface name, eg, "eth2"
Andy Green4f3943a2010-11-12 10:44:16 +00001764 * @protocols: Array of structures listing supported protocols and a protocol-
Andy Green8f037e42010-12-19 22:13:26 +00001765 * specific callback for each one. The list is ended with an
1766 * entry that has a NULL callback pointer.
Andy Green6964bb52011-01-23 16:50:33 +00001767 * It's not const because we write the owning_server member
Andy Greenc5114822011-03-06 10:29:35 +00001768 * @extensions: NULL or array of libwebsocket_extension structs listing the
1769 * extensions this context supports
Andy Green3faa9c72010-11-08 17:03:03 +00001770 * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want
Andy Green8f037e42010-12-19 22:13:26 +00001771 * to listen using SSL, set to the filepath to fetch the
1772 * server cert from, otherwise NULL for unencrypted
Andy Green3faa9c72010-11-08 17:03:03 +00001773 * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
Andy Green8f037e42010-12-19 22:13:26 +00001774 * else ignored
Andy Green3faa9c72010-11-08 17:03:03 +00001775 * @gid: group id to change to after setting listen socket, or -1.
1776 * @uid: user id to change to after setting listen socket, or -1.
Andy Greenbfb051f2011-02-09 08:49:14 +00001777 * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK
Andy Green05464c62010-11-12 10:44:18 +00001778 *
Andy Green8f037e42010-12-19 22:13:26 +00001779 * This function creates the listening socket and takes care
1780 * of all initialization in one step.
1781 *
Andy Greene92cd172011-01-19 13:11:55 +00001782 * After initialization, it returns a struct libwebsocket_context * that
1783 * represents this server. After calling, user code needs to take care
1784 * of calling libwebsocket_service() with the context pointer to get the
1785 * server's sockets serviced. This can be done in the same process context
1786 * or a forked process, or another thread,
Andy Green05464c62010-11-12 10:44:18 +00001787 *
Andy Green8f037e42010-12-19 22:13:26 +00001788 * The protocol callback functions are called for a handful of events
1789 * including http requests coming in, websocket connections becoming
1790 * established, and data arriving; it's also called periodically to allow
1791 * async transmission.
1792 *
1793 * HTTP requests are sent always to the FIRST protocol in @protocol, since
1794 * at that time websocket protocol has not been negotiated. Other
1795 * protocols after the first one never see any HTTP callack activity.
1796 *
1797 * The server created is a simple http server by default; part of the
1798 * websocket standard is upgrading this http connection to a websocket one.
1799 *
1800 * This allows the same server to provide files like scripts and favicon /
1801 * images or whatever over http and dynamic data over websockets all in
1802 * one place; they're all handled in the user callback.
Andy Greenab990e42010-10-31 12:42:52 +00001803 */
Andy Green4ea60062010-10-30 12:15:07 +01001804
Andy Greene92cd172011-01-19 13:11:55 +00001805struct libwebsocket_context *
Peter Hinz56885f32011-03-02 22:03:47 +00001806libwebsocket_create_context(int port, const char *interf,
Andy Greenb45993c2010-12-18 15:13:50 +00001807 struct libwebsocket_protocols *protocols,
Andy Greend6e09112011-03-05 16:12:15 +00001808 struct libwebsocket_extension *extensions,
Andy Green8f037e42010-12-19 22:13:26 +00001809 const char *ssl_cert_filepath,
1810 const char *ssl_private_key_filepath,
Andy Green8014b292011-01-30 20:57:25 +00001811 int gid, int uid, unsigned int options)
Andy Greenff95d7a2010-10-28 22:36:01 +01001812{
1813 int n;
Andy Green4739e5c2011-01-22 12:51:57 +00001814 int sockfd = 0;
Andy Green251f6fa2010-11-03 11:13:06 +00001815 int fd;
Andy Greenff95d7a2010-10-28 22:36:01 +01001816 struct sockaddr_in serv_addr, cli_addr;
Andy Green251f6fa2010-11-03 11:13:06 +00001817 int opt = 1;
Peter Hinz56885f32011-03-02 22:03:47 +00001818 struct libwebsocket_context *context = NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00001819 unsigned int slen;
Andy Green9659f372011-01-27 22:01:43 +00001820 char *p;
Andy Green2ac5a6f2011-01-28 10:00:18 +00001821 char hostname[1024];
Andy Green42f69142011-01-30 08:10:02 +00001822 struct hostent *he;
Andy Green0d338332011-02-12 11:57:43 +00001823 struct libwebsocket *wsi;
Andy Greenff95d7a2010-10-28 22:36:01 +01001824
Andy Green3faa9c72010-11-08 17:03:03 +00001825#ifdef LWS_OPENSSL_SUPPORT
Andy Greenf2f54d52010-11-15 22:08:00 +00001826 SSL_METHOD *method;
Andy Green3faa9c72010-11-08 17:03:03 +00001827 char ssl_err_buf[512];
Andy Green3faa9c72010-11-08 17:03:03 +00001828#endif
1829
Peter Hinz56885f32011-03-02 22:03:47 +00001830#ifdef _WIN32
1831 {
1832 WORD wVersionRequested;
1833 WSADATA wsaData;
1834 int err;
1835
1836 /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
1837 wVersionRequested = MAKEWORD(2, 2);
1838
1839 err = WSAStartup(wVersionRequested, &wsaData);
1840 if (err != 0) {
1841 /* Tell the user that we could not find a usable */
1842 /* Winsock DLL. */
1843 fprintf(stderr, "WSAStartup failed with error: %d\n",
1844 err);
1845 return NULL;
1846 }
1847 }
1848#endif
1849
1850
1851 context = malloc(sizeof(struct libwebsocket_context));
1852 if (!context) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001853 fprintf(stderr, "No memory for websocket context\n");
1854 return NULL;
1855 }
Peter Hinz56885f32011-03-02 22:03:47 +00001856 context->protocols = protocols;
1857 context->listen_port = port;
1858 context->http_proxy_port = 0;
1859 context->http_proxy_address[0] = '\0';
1860 context->options = options;
1861 context->fds_count = 0;
Andy Greend6e09112011-03-05 16:12:15 +00001862 context->extensions = extensions;
Andy Green9659f372011-01-27 22:01:43 +00001863
Peter Hinz56885f32011-03-02 22:03:47 +00001864#ifdef WIN32
1865 context->fd_random = 0;
1866#else
1867 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
1868 if (context->fd_random < 0) {
Andy Green44eee682011-02-10 09:32:24 +00001869 fprintf(stderr, "Unable to open random device %s %d\n",
Peter Hinz56885f32011-03-02 22:03:47 +00001870 SYSTEM_RANDOM_FILEPATH, context->fd_random);
Andy Green44eee682011-02-10 09:32:24 +00001871 return NULL;
1872 }
Peter Hinz56885f32011-03-02 22:03:47 +00001873#endif
Andy Green44eee682011-02-10 09:32:24 +00001874
Peter Hinz56885f32011-03-02 22:03:47 +00001875#ifdef LWS_OPENSSL_SUPPORT
1876 context->use_ssl = 0;
1877 context->ssl_ctx = NULL;
1878 context->ssl_client_ctx = NULL;
Andy Green2e24da02011-03-05 16:12:04 +00001879 openssl_websocket_private_data_index = 0;
Peter Hinz56885f32011-03-02 22:03:47 +00001880#endif
Andy Green2ac5a6f2011-01-28 10:00:18 +00001881 /* find canonical hostname */
1882
1883 hostname[(sizeof hostname) - 1] = '\0';
1884 gethostname(hostname, (sizeof hostname) - 1);
1885 he = gethostbyname(hostname);
Darin Willitsc19456f2011-02-14 17:52:39 +00001886 if (he) {
Peter Hinz56885f32011-03-02 22:03:47 +00001887 strncpy(context->canonical_hostname, he->h_name,
1888 sizeof context->canonical_hostname - 1);
1889 context->canonical_hostname[
1890 sizeof context->canonical_hostname - 1] = '\0';
Darin Willitsc19456f2011-02-14 17:52:39 +00001891 } else
Peter Hinz56885f32011-03-02 22:03:47 +00001892 strncpy(context->canonical_hostname, hostname,
1893 sizeof context->canonical_hostname - 1);
Andy Green2ac5a6f2011-01-28 10:00:18 +00001894
Andy Green9659f372011-01-27 22:01:43 +00001895 /* split the proxy ads:port if given */
1896
1897 p = getenv("http_proxy");
1898 if (p) {
Peter Hinz56885f32011-03-02 22:03:47 +00001899 strncpy(context->http_proxy_address, p,
1900 sizeof context->http_proxy_address - 1);
1901 context->http_proxy_address[
1902 sizeof context->http_proxy_address - 1] = '\0';
Andy Green9659f372011-01-27 22:01:43 +00001903
Peter Hinz56885f32011-03-02 22:03:47 +00001904 p = strchr(context->http_proxy_address, ':');
Andy Green9659f372011-01-27 22:01:43 +00001905 if (p == NULL) {
1906 fprintf(stderr, "http_proxy needs to be ads:port\n");
1907 return NULL;
1908 }
1909 *p = '\0';
Peter Hinz56885f32011-03-02 22:03:47 +00001910 context->http_proxy_port = atoi(p + 1);
Andy Green9659f372011-01-27 22:01:43 +00001911
1912 fprintf(stderr, "Using proxy %s:%u\n",
Peter Hinz56885f32011-03-02 22:03:47 +00001913 context->http_proxy_address,
1914 context->http_proxy_port);
Andy Green9659f372011-01-27 22:01:43 +00001915 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001916
1917 if (port) {
1918
Andy Green3faa9c72010-11-08 17:03:03 +00001919#ifdef LWS_OPENSSL_SUPPORT
Peter Hinz56885f32011-03-02 22:03:47 +00001920 context->use_ssl = ssl_cert_filepath != NULL &&
Andy Green90c7cbc2011-01-27 06:26:52 +00001921 ssl_private_key_filepath != NULL;
Peter Hinz56885f32011-03-02 22:03:47 +00001922 if (context->use_ssl)
Andy Green90c7cbc2011-01-27 06:26:52 +00001923 fprintf(stderr, " Compiled with SSL support, "
1924 "using it\n");
1925 else
1926 fprintf(stderr, " Compiled with SSL support, "
1927 "not using it\n");
Andy Green3faa9c72010-11-08 17:03:03 +00001928
Andy Green90c7cbc2011-01-27 06:26:52 +00001929#else
1930 if (ssl_cert_filepath != NULL &&
1931 ssl_private_key_filepath != NULL) {
1932 fprintf(stderr, " Not compiled for OpenSSl support!\n");
Andy Greene92cd172011-01-19 13:11:55 +00001933 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00001934 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001935 fprintf(stderr, " Compiled without SSL support, "
1936 "serving unencrypted\n");
1937#endif
1938 }
1939
1940 /* ignore SIGPIPE */
Peter Hinz56885f32011-03-02 22:03:47 +00001941#ifdef WIN32
1942#else
Andy Green90c7cbc2011-01-27 06:26:52 +00001943 signal(SIGPIPE, sigpipe_handler);
Peter Hinz56885f32011-03-02 22:03:47 +00001944#endif
Andy Green90c7cbc2011-01-27 06:26:52 +00001945
1946
1947#ifdef LWS_OPENSSL_SUPPORT
1948
1949 /* basic openssl init */
1950
1951 SSL_library_init();
1952
1953 OpenSSL_add_all_algorithms();
1954 SSL_load_error_strings();
1955
Andy Green2e24da02011-03-05 16:12:04 +00001956 openssl_websocket_private_data_index =
Andy Green6901cb32011-02-21 08:06:47 +00001957 SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);
1958
Andy Green90c7cbc2011-01-27 06:26:52 +00001959 /*
1960 * Firefox insists on SSLv23 not SSLv3
1961 * Konq disables SSLv2 by default now, SSLv23 works
1962 */
1963
1964 method = (SSL_METHOD *)SSLv23_server_method();
1965 if (!method) {
1966 fprintf(stderr, "problem creating ssl method: %s\n",
1967 ERR_error_string(ERR_get_error(), ssl_err_buf));
1968 return NULL;
1969 }
Peter Hinz56885f32011-03-02 22:03:47 +00001970 context->ssl_ctx = SSL_CTX_new(method); /* create context */
1971 if (!context->ssl_ctx) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001972 fprintf(stderr, "problem creating ssl context: %s\n",
1973 ERR_error_string(ERR_get_error(), ssl_err_buf));
1974 return NULL;
1975 }
1976
1977 /* client context */
Peter Hinz56885f32011-03-02 22:03:47 +00001978 if (port == CONTEXT_PORT_NO_LISTEN)
1979 {
1980 method = (SSL_METHOD *)SSLv23_client_method();
1981 if (!method) {
1982 fprintf(stderr, "problem creating ssl method: %s\n",
1983 ERR_error_string(ERR_get_error(), ssl_err_buf));
1984 return NULL;
1985 }
1986 /* create context */
1987 context->ssl_client_ctx = SSL_CTX_new(method);
1988 if (!context->ssl_client_ctx) {
1989 fprintf(stderr, "problem creating ssl context: %s\n",
1990 ERR_error_string(ERR_get_error(), ssl_err_buf));
1991 return NULL;
1992 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001993
Peter Hinz56885f32011-03-02 22:03:47 +00001994 /* openssl init for cert verification (for client sockets) */
Andy Green90c7cbc2011-01-27 06:26:52 +00001995
Peter Hinz56885f32011-03-02 22:03:47 +00001996 if (!SSL_CTX_load_verify_locations(
1997 context->ssl_client_ctx, NULL,
1998 LWS_OPENSSL_CLIENT_CERTS))
1999 fprintf(stderr,
2000 "Unable to load SSL Client certs from %s "
2001 "(set by --with-client-cert-dir= in configure) -- "
2002 " client ssl isn't going to work",
Andy Green90c7cbc2011-01-27 06:26:52 +00002003 LWS_OPENSSL_CLIENT_CERTS);
Peter Hinz56885f32011-03-02 22:03:47 +00002004
2005 /*
2006 * callback allowing user code to load extra verification certs
2007 * helping the client to verify server identity
2008 */
2009
2010 context->protocols[0].callback(context, NULL,
2011 LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
2012 context->ssl_client_ctx, NULL, 0);
Andy Green90c7cbc2011-01-27 06:26:52 +00002013 }
Andy Greenc6bf2c22011-02-20 11:10:47 +00002014 /* as a server, are we requiring clients to identify themselves? */
2015
2016 if (options & LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
2017
2018 /* absolutely require the client cert */
2019
Peter Hinz56885f32011-03-02 22:03:47 +00002020 SSL_CTX_set_verify(context->ssl_ctx,
Andy Green6901cb32011-02-21 08:06:47 +00002021 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
2022 OpenSSL_verify_callback);
Andy Greenc6bf2c22011-02-20 11:10:47 +00002023
2024 /*
2025 * give user code a chance to load certs into the server
2026 * allowing it to verify incoming client certs
2027 */
2028
Peter Hinz56885f32011-03-02 22:03:47 +00002029 context->protocols[0].callback(context, NULL,
Andy Greenc6bf2c22011-02-20 11:10:47 +00002030 LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
Peter Hinz56885f32011-03-02 22:03:47 +00002031 context->ssl_ctx, NULL, 0);
Andy Greenc6bf2c22011-02-20 11:10:47 +00002032 }
2033
Peter Hinz56885f32011-03-02 22:03:47 +00002034 if (context->use_ssl) {
Andy Green90c7cbc2011-01-27 06:26:52 +00002035
2036 /* openssl init for server sockets */
2037
Andy Green3faa9c72010-11-08 17:03:03 +00002038 /* set the local certificate from CertFile */
Peter Hinz56885f32011-03-02 22:03:47 +00002039 n = SSL_CTX_use_certificate_file(context->ssl_ctx,
Andy Green3faa9c72010-11-08 17:03:03 +00002040 ssl_cert_filepath, SSL_FILETYPE_PEM);
2041 if (n != 1) {
2042 fprintf(stderr, "problem getting cert '%s': %s\n",
2043 ssl_cert_filepath,
2044 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Greene92cd172011-01-19 13:11:55 +00002045 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002046 }
2047 /* set the private key from KeyFile */
Peter Hinz56885f32011-03-02 22:03:47 +00002048 if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx,
2049 ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) {
Andy Green018d8eb2010-11-08 21:04:23 +00002050 fprintf(stderr, "ssl problem getting key '%s': %s\n",
2051 ssl_private_key_filepath,
2052 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Greene92cd172011-01-19 13:11:55 +00002053 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002054 }
2055 /* verify private key */
Peter Hinz56885f32011-03-02 22:03:47 +00002056 if (!SSL_CTX_check_private_key(context->ssl_ctx)) {
Andy Green018d8eb2010-11-08 21:04:23 +00002057 fprintf(stderr, "Private SSL key doesn't match cert\n");
Andy Greene92cd172011-01-19 13:11:55 +00002058 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002059 }
2060
2061 /* SSL is happy and has a cert it's content with */
2062 }
2063#endif
Andy Greenb45993c2010-12-18 15:13:50 +00002064
Andy Greendf736162011-01-18 15:39:02 +00002065 /* selftest */
2066
2067 if (lws_b64_selftest())
Andy Greene92cd172011-01-19 13:11:55 +00002068 return NULL;
Andy Greendf736162011-01-18 15:39:02 +00002069
Andy Green0d338332011-02-12 11:57:43 +00002070 /* fd hashtable init */
2071
2072 for (n = 0; n < FD_HASHTABLE_MODULUS; n++)
Peter Hinz56885f32011-03-02 22:03:47 +00002073 context->fd_hashtable[n].length = 0;
Andy Green0d338332011-02-12 11:57:43 +00002074
Andy Greenb45993c2010-12-18 15:13:50 +00002075 /* set up our external listening socket we serve on */
Andy Green8f037e42010-12-19 22:13:26 +00002076
Andy Green4739e5c2011-01-22 12:51:57 +00002077 if (port) {
Andy Green8f037e42010-12-19 22:13:26 +00002078
Andy Green4739e5c2011-01-22 12:51:57 +00002079 sockfd = socket(AF_INET, SOCK_STREAM, 0);
2080 if (sockfd < 0) {
2081 fprintf(stderr, "ERROR opening socket");
2082 return NULL;
2083 }
Andy Green775c0dd2010-10-29 14:15:22 +01002084
Andy Green4739e5c2011-01-22 12:51:57 +00002085 /* allow us to restart even if old sockets in TIME_WAIT */
2086 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Andy Greene77ddd82010-11-13 10:03:47 +00002087
Andy Green4739e5c2011-01-22 12:51:57 +00002088 bzero((char *) &serv_addr, sizeof(serv_addr));
2089 serv_addr.sin_family = AF_INET;
Peter Hinz56885f32011-03-02 22:03:47 +00002090 if (interf == NULL)
Andy Green32375b72011-02-19 08:32:53 +00002091 serv_addr.sin_addr.s_addr = INADDR_ANY;
2092 else
Peter Hinz56885f32011-03-02 22:03:47 +00002093 interface_to_sa(interf, &serv_addr,
Andy Green32375b72011-02-19 08:32:53 +00002094 sizeof(serv_addr));
Andy Green4739e5c2011-01-22 12:51:57 +00002095 serv_addr.sin_port = htons(port);
2096
2097 n = bind(sockfd, (struct sockaddr *) &serv_addr,
2098 sizeof(serv_addr));
2099 if (n < 0) {
2100 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
Andy Green8f037e42010-12-19 22:13:26 +00002101 port, n, errno);
Andy Green4739e5c2011-01-22 12:51:57 +00002102 return NULL;
2103 }
Andy Green0d338332011-02-12 11:57:43 +00002104
2105 wsi = malloc(sizeof(struct libwebsocket));
2106 memset(wsi, 0, sizeof (struct libwebsocket));
2107 wsi->sock = sockfd;
Andy Greend6e09112011-03-05 16:12:15 +00002108 wsi->count_active_extensions = 0;
Andy Green0d338332011-02-12 11:57:43 +00002109 wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
Peter Hinz56885f32011-03-02 22:03:47 +00002110 insert_wsi(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00002111
2112 listen(sockfd, 5);
2113 fprintf(stderr, " Listening on port %d\n", port);
2114
2115 /* list in the internal poll array */
2116
Peter Hinz56885f32011-03-02 22:03:47 +00002117 context->fds[context->fds_count].fd = sockfd;
2118 context->fds[context->fds_count++].events = POLLIN;
Andy Green3221f922011-02-12 13:14:11 +00002119
2120 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00002121 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00002122 LWS_CALLBACK_ADD_POLL_FD,
2123 (void *)(long)sockfd, NULL, POLLIN);
2124
Andy Green8f037e42010-12-19 22:13:26 +00002125 }
Andy Greenb45993c2010-12-18 15:13:50 +00002126
Andy Greene77ddd82010-11-13 10:03:47 +00002127 /* drop any root privs for this process */
Peter Hinz56885f32011-03-02 22:03:47 +00002128#ifdef WIN32
2129#else
Andy Green3faa9c72010-11-08 17:03:03 +00002130 if (gid != -1)
2131 if (setgid(gid))
2132 fprintf(stderr, "setgid: %s\n", strerror(errno));
2133 if (uid != -1)
2134 if (setuid(uid))
2135 fprintf(stderr, "setuid: %s\n", strerror(errno));
Peter Hinz56885f32011-03-02 22:03:47 +00002136#endif
Andy Greenb45993c2010-12-18 15:13:50 +00002137
2138 /* set up our internal broadcast trigger sockets per-protocol */
2139
Peter Hinz56885f32011-03-02 22:03:47 +00002140 for (context->count_protocols = 0;
2141 protocols[context->count_protocols].callback;
2142 context->count_protocols++) {
2143 protocols[context->count_protocols].owning_server = context;
2144 protocols[context->count_protocols].protocol_index =
2145 context->count_protocols;
Andy Greenb45993c2010-12-18 15:13:50 +00002146
2147 fd = socket(AF_INET, SOCK_STREAM, 0);
2148 if (fd < 0) {
2149 fprintf(stderr, "ERROR opening socket");
Andy Greene92cd172011-01-19 13:11:55 +00002150 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002151 }
Andy Green8f037e42010-12-19 22:13:26 +00002152
Andy Greenb45993c2010-12-18 15:13:50 +00002153 /* allow us to restart even if old sockets in TIME_WAIT */
2154 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
2155
2156 bzero((char *) &serv_addr, sizeof(serv_addr));
2157 serv_addr.sin_family = AF_INET;
2158 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2159 serv_addr.sin_port = 0; /* pick the port for us */
2160
2161 n = bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
2162 if (n < 0) {
Andy Green8f037e42010-12-19 22:13:26 +00002163 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
Andy Greenb45993c2010-12-18 15:13:50 +00002164 port, n, errno);
Andy Greene92cd172011-01-19 13:11:55 +00002165 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002166 }
2167
2168 slen = sizeof cli_addr;
2169 n = getsockname(fd, (struct sockaddr *)&cli_addr, &slen);
2170 if (n < 0) {
2171 fprintf(stderr, "getsockname failed\n");
Andy Greene92cd172011-01-19 13:11:55 +00002172 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002173 }
Peter Hinz56885f32011-03-02 22:03:47 +00002174 protocols[context->count_protocols].broadcast_socket_port =
Andy Greenb45993c2010-12-18 15:13:50 +00002175 ntohs(cli_addr.sin_port);
2176 listen(fd, 5);
2177
2178 debug(" Protocol %s broadcast socket %d\n",
Peter Hinz56885f32011-03-02 22:03:47 +00002179 protocols[context->count_protocols].name,
Andy Greenb45993c2010-12-18 15:13:50 +00002180 ntohs(cli_addr.sin_port));
2181
Andy Green0d338332011-02-12 11:57:43 +00002182 /* dummy wsi per broadcast proxy socket */
2183
2184 wsi = malloc(sizeof(struct libwebsocket));
2185 memset(wsi, 0, sizeof (struct libwebsocket));
2186 wsi->sock = fd;
2187 wsi->mode = LWS_CONNMODE_BROADCAST_PROXY_LISTENER;
Andy Greend6e09112011-03-05 16:12:15 +00002188 wsi->count_active_extensions = 0;
Andy Green0d338332011-02-12 11:57:43 +00002189 /* note which protocol we are proxying */
Peter Hinz56885f32011-03-02 22:03:47 +00002190 wsi->protocol_index_for_broadcast_proxy =
2191 context->count_protocols;
2192 insert_wsi(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00002193
2194 /* list in internal poll array */
2195
Peter Hinz56885f32011-03-02 22:03:47 +00002196 context->fds[context->fds_count].fd = fd;
2197 context->fds[context->fds_count].events = POLLIN;
2198 context->fds[context->fds_count].revents = 0;
2199 context->fds_count++;
Andy Green3221f922011-02-12 13:14:11 +00002200
2201 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00002202 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00002203 LWS_CALLBACK_ADD_POLL_FD,
2204 (void *)(long)fd, NULL, POLLIN);
Andy Greenb45993c2010-12-18 15:13:50 +00002205 }
2206
Peter Hinz56885f32011-03-02 22:03:47 +00002207 return context;
Andy Greene92cd172011-01-19 13:11:55 +00002208}
Andy Greenb45993c2010-12-18 15:13:50 +00002209
Andy Green4739e5c2011-01-22 12:51:57 +00002210
Andy Greened11a022011-01-20 10:23:50 +00002211#ifndef LWS_NO_FORK
2212
Andy Greene92cd172011-01-19 13:11:55 +00002213/**
2214 * libwebsockets_fork_service_loop() - Optional helper function forks off
2215 * a process for the websocket server loop.
Andy Green6964bb52011-01-23 16:50:33 +00002216 * You don't have to use this but if not, you
2217 * have to make sure you are calling
2218 * libwebsocket_service periodically to service
2219 * the websocket traffic
Peter Hinz56885f32011-03-02 22:03:47 +00002220 * @context: server context returned by creation function
Andy Greene92cd172011-01-19 13:11:55 +00002221 */
Andy Greenb45993c2010-12-18 15:13:50 +00002222
Andy Greene92cd172011-01-19 13:11:55 +00002223int
Peter Hinz56885f32011-03-02 22:03:47 +00002224libwebsockets_fork_service_loop(struct libwebsocket_context *context)
Andy Greene92cd172011-01-19 13:11:55 +00002225{
Andy Greene92cd172011-01-19 13:11:55 +00002226 int fd;
2227 struct sockaddr_in cli_addr;
2228 int n;
Andy Green3221f922011-02-12 13:14:11 +00002229 int p;
Andy Greenb45993c2010-12-18 15:13:50 +00002230
Andy Greened11a022011-01-20 10:23:50 +00002231 n = fork();
2232 if (n < 0)
2233 return n;
2234
2235 if (!n) {
2236
2237 /* main process context */
2238
Andy Green3221f922011-02-12 13:14:11 +00002239 /*
2240 * set up the proxy sockets to allow broadcast from
2241 * service process context
2242 */
2243
Peter Hinz56885f32011-03-02 22:03:47 +00002244 for (p = 0; p < context->count_protocols; p++) {
Andy Greened11a022011-01-20 10:23:50 +00002245 fd = socket(AF_INET, SOCK_STREAM, 0);
2246 if (fd < 0) {
2247 fprintf(stderr, "Unable to create socket\n");
2248 return -1;
2249 }
2250 cli_addr.sin_family = AF_INET;
2251 cli_addr.sin_port = htons(
Peter Hinz56885f32011-03-02 22:03:47 +00002252 context->protocols[p].broadcast_socket_port);
Andy Greened11a022011-01-20 10:23:50 +00002253 cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2254 n = connect(fd, (struct sockaddr *)&cli_addr,
2255 sizeof cli_addr);
2256 if (n < 0) {
2257 fprintf(stderr, "Unable to connect to "
2258 "broadcast socket %d, %s\n",
Andy Green3221f922011-02-12 13:14:11 +00002259 n, strerror(errno));
Andy Greened11a022011-01-20 10:23:50 +00002260 return -1;
2261 }
2262
Peter Hinz56885f32011-03-02 22:03:47 +00002263 context->protocols[p].broadcast_socket_user_fd = fd;
Andy Greened11a022011-01-20 10:23:50 +00002264 }
2265
Andy Greene92cd172011-01-19 13:11:55 +00002266 return 0;
Andy Greenb45993c2010-12-18 15:13:50 +00002267 }
2268
2269 /* we want a SIGHUP when our parent goes down */
2270 prctl(PR_SET_PDEATHSIG, SIGHUP);
2271
2272 /* in this forked process, sit and service websocket connections */
Andy Green8f037e42010-12-19 22:13:26 +00002273
Andy Greene92cd172011-01-19 13:11:55 +00002274 while (1)
Peter Hinz56885f32011-03-02 22:03:47 +00002275 if (libwebsocket_service(context, 1000))
Andy Greene92cd172011-01-19 13:11:55 +00002276 return -1;
Andy Green8f037e42010-12-19 22:13:26 +00002277
Andy Green251f6fa2010-11-03 11:13:06 +00002278 return 0;
Andy Greenff95d7a2010-10-28 22:36:01 +01002279}
2280
Andy Greened11a022011-01-20 10:23:50 +00002281#endif
2282
Andy Greenb45993c2010-12-18 15:13:50 +00002283/**
2284 * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket
Andy Green8f037e42010-12-19 22:13:26 +00002285 * connection.
Andy Greenb45993c2010-12-18 15:13:50 +00002286 * @wsi: pointer to struct websocket you want to know the protocol of
2287 *
Andy Green8f037e42010-12-19 22:13:26 +00002288 *
2289 * This is useful to get the protocol to broadcast back to from inside
Andy Greenb45993c2010-12-18 15:13:50 +00002290 * the callback.
2291 */
Andy Greenab990e42010-10-31 12:42:52 +00002292
Andy Greenb45993c2010-12-18 15:13:50 +00002293const struct libwebsocket_protocols *
2294libwebsockets_get_protocol(struct libwebsocket *wsi)
2295{
2296 return wsi->protocol;
2297}
2298
2299/**
Andy Greene92cd172011-01-19 13:11:55 +00002300 * libwebsockets_broadcast() - Sends a buffer to the callback for all active
Andy Green8f037e42010-12-19 22:13:26 +00002301 * connections of the given protocol.
Andy Greenb45993c2010-12-18 15:13:50 +00002302 * @protocol: pointer to the protocol you will broadcast to all members of
2303 * @buf: buffer containing the data to be broadcase. NOTE: this has to be
Andy Green8f037e42010-12-19 22:13:26 +00002304 * allocated with LWS_SEND_BUFFER_PRE_PADDING valid bytes before
2305 * the pointer and LWS_SEND_BUFFER_POST_PADDING afterwards in the
2306 * case you are calling this function from callback context.
Andy Greenb45993c2010-12-18 15:13:50 +00002307 * @len: length of payload data in buf, starting from buf.
Andy Green8f037e42010-12-19 22:13:26 +00002308 *
2309 * This function allows bulk sending of a packet to every connection using
Andy Greenb45993c2010-12-18 15:13:50 +00002310 * the given protocol. It does not send the data directly; instead it calls
2311 * the callback with a reason type of LWS_CALLBACK_BROADCAST. If the callback
2312 * wants to actually send the data for that connection, the callback itself
2313 * should call libwebsocket_write().
2314 *
2315 * libwebsockets_broadcast() can be called from another fork context without
2316 * having to take any care about data visibility between the processes, it'll
2317 * "just work".
2318 */
2319
2320
2321int
Andy Green8f037e42010-12-19 22:13:26 +00002322libwebsockets_broadcast(const struct libwebsocket_protocols *protocol,
Andy Greenb45993c2010-12-18 15:13:50 +00002323 unsigned char *buf, size_t len)
2324{
Peter Hinz56885f32011-03-02 22:03:47 +00002325 struct libwebsocket_context *context = protocol->owning_server;
Andy Greenb45993c2010-12-18 15:13:50 +00002326 int n;
Andy Green0d338332011-02-12 11:57:43 +00002327 int m;
2328 struct libwebsocket * wsi;
Andy Greenb45993c2010-12-18 15:13:50 +00002329
2330 if (!protocol->broadcast_socket_user_fd) {
2331 /*
Andy Greene92cd172011-01-19 13:11:55 +00002332 * We are either running unforked / flat, or we are being
2333 * called from poll thread context
Andy Greenb45993c2010-12-18 15:13:50 +00002334 * eg, from a callback. In that case don't use sockets for
2335 * broadcast IPC (since we can't open a socket connection to
2336 * a socket listening on our own thread) but directly do the
2337 * send action.
2338 *
2339 * Locking is not needed because we are by definition being
2340 * called in the poll thread context and are serialized.
2341 */
2342
Andy Green0d338332011-02-12 11:57:43 +00002343 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
Andy Greenb45993c2010-12-18 15:13:50 +00002344
Peter Hinz56885f32011-03-02 22:03:47 +00002345 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Greenb45993c2010-12-18 15:13:50 +00002346
Peter Hinz56885f32011-03-02 22:03:47 +00002347 wsi = context->fd_hashtable[n].wsi[m];
Andy Greenb45993c2010-12-18 15:13:50 +00002348
Andy Green0d338332011-02-12 11:57:43 +00002349 if (wsi->mode != LWS_CONNMODE_WS_SERVING)
2350 continue;
Andy Greenb45993c2010-12-18 15:13:50 +00002351
Andy Green0d338332011-02-12 11:57:43 +00002352 /*
2353 * never broadcast to
2354 * non-established connections
2355 */
2356 if (wsi->state != WSI_STATE_ESTABLISHED)
2357 continue;
2358
2359 /* only broadcast to guys using
2360 * requested protocol
2361 */
2362 if (wsi->protocol != protocol)
2363 continue;
2364
Peter Hinz56885f32011-03-02 22:03:47 +00002365 wsi->protocol->callback(context, wsi,
Andy Green8f037e42010-12-19 22:13:26 +00002366 LWS_CALLBACK_BROADCAST,
Andy Green0d338332011-02-12 11:57:43 +00002367 wsi->user_space,
Andy Greenb45993c2010-12-18 15:13:50 +00002368 buf, len);
Andy Green0d338332011-02-12 11:57:43 +00002369 }
Andy Greenb45993c2010-12-18 15:13:50 +00002370 }
2371
2372 return 0;
2373 }
2374
Andy Green0ca6a172010-12-19 20:50:01 +00002375 /*
2376 * We're being called from a different process context than the server
2377 * loop. Instead of broadcasting directly, we send our
2378 * payload on a socket to do the IPC; the server process will serialize
2379 * the broadcast action in its main poll() loop.
2380 *
2381 * There's one broadcast socket listening for each protocol supported
2382 * set up when the websocket server initializes
2383 */
2384
Andy Green6964bb52011-01-23 16:50:33 +00002385 n = send(protocol->broadcast_socket_user_fd, buf, len, MSG_NOSIGNAL);
Andy Greenb45993c2010-12-18 15:13:50 +00002386
2387 return n;
2388}