blob: c00a8ea5e7826535ae9f888a3be4f98130adf8c0 [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 Green4b6fbe12011-02-14 08:03:48 +0000207 /* free up his allocations */
208
Andy Green251f6fa2010-11-03 11:13:06 +0000209 for (n = 0; n < WSI_TOKEN_COUNT; n++)
210 if (wsi->utf8_token[n].token)
211 free(wsi->utf8_token[n].token);
212
Andy Green0ca6a172010-12-19 20:50:01 +0000213/* fprintf(stderr, "closing fd=%d\n", wsi->sock); */
Andy Green251f6fa2010-11-03 11:13:06 +0000214
Andy Green3faa9c72010-11-08 17:03:03 +0000215#ifdef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000216 if (wsi->ssl) {
Andy Green3faa9c72010-11-08 17:03:03 +0000217 n = SSL_get_fd(wsi->ssl);
218 SSL_shutdown(wsi->ssl);
Peter Hinz56885f32011-03-02 22:03:47 +0000219#ifdef WIN32
220 closesocket(n);
221#else
Andy Green3faa9c72010-11-08 17:03:03 +0000222 close(n);
Peter Hinz56885f32011-03-02 22:03:47 +0000223#endif
Andy Green3faa9c72010-11-08 17:03:03 +0000224 SSL_free(wsi->ssl);
225 } else {
226#endif
227 shutdown(wsi->sock, SHUT_RDWR);
Peter Hinz56885f32011-03-02 22:03:47 +0000228#ifdef WIN32
229 closesocket(wsi->sock);
230#else
Andy Green3faa9c72010-11-08 17:03:03 +0000231 close(wsi->sock);
Peter Hinz56885f32011-03-02 22:03:47 +0000232#endif
Andy Green3faa9c72010-11-08 17:03:03 +0000233#ifdef LWS_OPENSSL_SUPPORT
234 }
235#endif
Andy Green4f3943a2010-11-12 10:44:16 +0000236 if (wsi->user_space)
237 free(wsi->user_space);
238
Andy Green251f6fa2010-11-03 11:13:06 +0000239 free(wsi);
240}
241
Andy Green07034092011-02-13 08:37:12 +0000242/**
Andy Greenf7ee5492011-02-13 09:04:21 +0000243 * libwebsockets_hangup_on_client() - Server calls to terminate client
244 * connection
Peter Hinz56885f32011-03-02 22:03:47 +0000245 * @context: libwebsockets context
Andy Greenf7ee5492011-02-13 09:04:21 +0000246 * @fd: Connection socket descriptor
247 */
248
249void
Peter Hinz56885f32011-03-02 22:03:47 +0000250libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd)
Andy Greenf7ee5492011-02-13 09:04:21 +0000251{
Peter Hinz56885f32011-03-02 22:03:47 +0000252 struct libwebsocket *wsi = wsi_from_fd(context, fd);
Andy Greenf7ee5492011-02-13 09:04:21 +0000253
254 if (wsi == NULL)
255 return;
256
Peter Hinz56885f32011-03-02 22:03:47 +0000257 libwebsocket_close_and_free_session(context, wsi,
Andy Green6da560c2011-02-26 11:06:27 +0000258 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenf7ee5492011-02-13 09:04:21 +0000259}
260
261
262/**
Andy Green07034092011-02-13 08:37:12 +0000263 * libwebsockets_get_peer_addresses() - Get client address information
264 * @fd: Connection socket descriptor
265 * @name: Buffer to take client address name
266 * @name_len: Length of client address name buffer
267 * @rip: Buffer to take client address IP qotted quad
268 * @rip_len: Length of client address IP buffer
269 *
270 * This function fills in @name and @rip with the name and IP of
271 * the client connected with socket descriptor @fd. Names may be
272 * truncated if there is not enough room. If either cannot be
273 * determined, they will be returned as valid zero-length strings.
274 */
275
276void
277libwebsockets_get_peer_addresses(int fd, char *name, int name_len,
278 char *rip, int rip_len)
279{
280 unsigned int len;
281 struct sockaddr_in sin;
282 struct hostent *host;
283 struct hostent *host1;
284 char ip[128];
285 char *p;
286 int n;
287
288 rip[0] = '\0';
289 name[0] = '\0';
290
291 len = sizeof sin;
292 if (getpeername(fd, (struct sockaddr *) &sin, &len) < 0) {
293 perror("getpeername");
294 return;
295 }
296
297 host = gethostbyaddr((char *) &sin.sin_addr, sizeof sin.sin_addr,
298 AF_INET);
299 if (host == NULL) {
300 perror("gethostbyaddr");
301 return;
302 }
303
304 strncpy(name, host->h_name, name_len);
305 name[name_len - 1] = '\0';
306
307 host1 = gethostbyname(host->h_name);
308 if (host1 == NULL)
309 return;
310 p = (char *)host1;
311 n = 0;
312 while (p != NULL) {
313 p = host1->h_addr_list[n++];
314 if (p == NULL)
315 continue;
316 if (host1->h_addrtype != AF_INET)
317 continue;
318
319 sprintf(ip, "%d.%d.%d.%d",
320 p[0], p[1], p[2], p[3]);
321 p = NULL;
322 strncpy(rip, ip, rip_len);
323 rip[rip_len - 1] = '\0';
324 }
325}
Andy Green9f990342011-02-12 11:57:45 +0000326
Peter Hinz56885f32011-03-02 22:03:47 +0000327int libwebsockets_get_random(struct libwebsocket_context *context,
328 void *buf, int len)
329{
330 int n;
331 char *p = buf;
332
333#ifdef WIN32
334 for (n = 0; n < len; n++)
335 p[n] = (unsigned char)rand();
336#else
337 n = read(context->fd_random, p, len);
338#endif
339
340 return n;
341}
342
Andy Greeneeaacb32011-03-01 20:44:24 +0000343void libwebsockets_00_spaceout(char *key, int spaces, int seed)
344{
345 char *p;
Peter Hinz56885f32011-03-02 22:03:47 +0000346
Andy Greeneeaacb32011-03-01 20:44:24 +0000347 key++;
348 while (spaces--) {
349 if (*key && (seed & 1))
350 key++;
351 seed >>= 1;
Peter Hinz56885f32011-03-02 22:03:47 +0000352
Andy Greeneeaacb32011-03-01 20:44:24 +0000353 p = key + strlen(key);
354 while (p >= key) {
355 p[1] = p[0];
356 p--;
357 }
358 *key++ = ' ';
359 }
360}
361
362void libwebsockets_00_spam(char *key, int count, int seed)
363{
364 char *p;
365
366 key++;
367 while (count--) {
368
369 if (*key && (seed & 1))
370 key++;
371 seed >>= 1;
372
373 p = key + strlen(key);
374 while (p >= key) {
375 p[1] = p[0];
376 p--;
377 }
378 *key++ = 0x21 + ((seed & 0xffff) % 15);
379 /* 4 would use it up too fast.. not like it matters */
380 seed >>= 1;
381 }
382}
383
Andy Green9f990342011-02-12 11:57:45 +0000384/**
385 * libwebsocket_service_fd() - Service polled socket with something waiting
Peter Hinz56885f32011-03-02 22:03:47 +0000386 * @context: Websocket context
Andy Green9f990342011-02-12 11:57:45 +0000387 * @pollfd: The pollfd entry describing the socket fd and which events
388 * happened.
389 *
390 * This function closes any active connections and then frees the
391 * context. After calling this, any further use of the context is
392 * undefined.
393 */
394
395int
Peter Hinz56885f32011-03-02 22:03:47 +0000396libwebsocket_service_fd(struct libwebsocket_context *context,
Andy Green0d338332011-02-12 11:57:43 +0000397 struct pollfd *pollfd)
Andy Greenb45993c2010-12-18 15:13:50 +0000398{
399 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BROADCAST_PAYLOAD +
400 LWS_SEND_BUFFER_POST_PADDING];
Andy Greena71eafc2011-02-14 17:59:43 +0000401 struct libwebsocket *wsi;
Andy Green0d338332011-02-12 11:57:43 +0000402 struct libwebsocket *new_wsi;
Andy Greenb45993c2010-12-18 15:13:50 +0000403 int n;
Andy Green0d338332011-02-12 11:57:43 +0000404 int m;
Andy Greenb45993c2010-12-18 15:13:50 +0000405 size_t len;
Andy Green0d338332011-02-12 11:57:43 +0000406 int accept_fd;
407 unsigned int clilen;
408 struct sockaddr_in cli_addr;
Andy Greena71eafc2011-02-14 17:59:43 +0000409 struct timeval tv;
Andy Greenbe93fef2011-02-14 20:25:43 +0000410 static const char magic_websocket_guid[] =
411 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
412 static const char magic_websocket_04_masking_guid[] =
413 "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
414 char hash[20];
415 char pkt[1024];
416 char *p = &pkt[0];
417 const char *pc;
418 int okay = 0;
419#ifdef LWS_OPENSSL_SUPPORT
420 char ssl_err_buf[512];
421#endif
Andy Greena71eafc2011-02-14 17:59:43 +0000422 /*
423 * you can call us with pollfd = NULL to just allow the once-per-second
424 * global timeout checks; if less than a second since the last check
425 * it returns immediately then.
426 */
427
428 gettimeofday(&tv, NULL);
429
Peter Hinz56885f32011-03-02 22:03:47 +0000430 if (context->last_timeout_check_s != tv.tv_sec) {
431 context->last_timeout_check_s = tv.tv_sec;
Andy Greena71eafc2011-02-14 17:59:43 +0000432
433 /* global timeout check once per second */
434
Peter Hinz56885f32011-03-02 22:03:47 +0000435 for (n = 0; n < context->fds_count; n++) {
436 wsi = wsi_from_fd(context, context->fds[n].fd);
Andy Greena71eafc2011-02-14 17:59:43 +0000437 if (!wsi->pending_timeout)
438 continue;
439
440 /*
441 * if we went beyond the allowed time, kill the
442 * connection
443 */
444
445 if (tv.tv_sec > wsi->pending_timeout_limit)
Peter Hinz56885f32011-03-02 22:03:47 +0000446 libwebsocket_close_and_free_session(context,
447 wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena71eafc2011-02-14 17:59:43 +0000448 }
449 }
450
451 /* just here for timeout management? */
452
453 if (pollfd == NULL)
454 return 0;
455
456 /* no, here to service a socket descriptor */
457
Peter Hinz56885f32011-03-02 22:03:47 +0000458 wsi = wsi_from_fd(context, pollfd->fd);
Andy Greenb45993c2010-12-18 15:13:50 +0000459
Andy Green0d338332011-02-12 11:57:43 +0000460 if (wsi == NULL)
461 return 1;
Andy Green8f037e42010-12-19 22:13:26 +0000462
Andy Green0d338332011-02-12 11:57:43 +0000463 switch (wsi->mode) {
464 case LWS_CONNMODE_SERVER_LISTENER:
465
466 /* pollin means a client has connected to us then */
467
468 if (!pollfd->revents & POLLIN)
469 break;
470
471 /* listen socket got an unencrypted connection... */
472
473 clilen = sizeof(cli_addr);
474 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
475 &clilen);
476 if (accept_fd < 0) {
477 fprintf(stderr, "ERROR on accept");
478 break;
479 }
480
Peter Hinz56885f32011-03-02 22:03:47 +0000481 if (context->fds_count >= MAX_CLIENTS) {
Andy Green3221f922011-02-12 13:14:11 +0000482 fprintf(stderr, "too busy to accept new client\n");
Peter Hinz56885f32011-03-02 22:03:47 +0000483#ifdef WIN32
484 closesocket(accept_fd);
485#else
Andy Green0d338332011-02-12 11:57:43 +0000486 close(accept_fd);
Peter Hinz56885f32011-03-02 22:03:47 +0000487#endif
Andy Green0d338332011-02-12 11:57:43 +0000488 break;
489 }
490
Andy Green07034092011-02-13 08:37:12 +0000491 /*
492 * look at who we connected to and give user code a chance
493 * to reject based on client IP. There's no protocol selected
494 * yet so we issue this to protocols[0]
495 */
496
Peter Hinz56885f32011-03-02 22:03:47 +0000497 if ((context->protocols[0].callback)(context, wsi,
Andy Green07034092011-02-13 08:37:12 +0000498 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
499 (void*)(long)accept_fd, NULL, 0)) {
500 fprintf(stderr, "Callback denied network connection\n");
Peter Hinz56885f32011-03-02 22:03:47 +0000501#ifdef WIN32
502 closesocket(accept_fd);
503#else
Andy Green07034092011-02-13 08:37:12 +0000504 close(accept_fd);
Peter Hinz56885f32011-03-02 22:03:47 +0000505#endif
Andy Green07034092011-02-13 08:37:12 +0000506 break;
507 }
508
Andy Green0d338332011-02-12 11:57:43 +0000509 /* accepting connection to main listener */
510
511 new_wsi = malloc(sizeof(struct libwebsocket));
512 if (new_wsi == NULL) {
513 fprintf(stderr, "Out of memory for new connection\n");
514 break;
515 }
516
517 memset(new_wsi, 0, sizeof (struct libwebsocket));
518 new_wsi->sock = accept_fd;
Andy Greena71eafc2011-02-14 17:59:43 +0000519 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Green0d338332011-02-12 11:57:43 +0000520
521#ifdef LWS_OPENSSL_SUPPORT
522 new_wsi->ssl = NULL;
Andy Green0d338332011-02-12 11:57:43 +0000523
Peter Hinz56885f32011-03-02 22:03:47 +0000524 if (context->use_ssl) {
Andy Green0d338332011-02-12 11:57:43 +0000525
Peter Hinz56885f32011-03-02 22:03:47 +0000526 new_wsi->ssl = SSL_new(context->ssl_ctx);
Andy Green0d338332011-02-12 11:57:43 +0000527 if (new_wsi->ssl == NULL) {
528 fprintf(stderr, "SSL_new failed: %s\n",
529 ERR_error_string(SSL_get_error(
530 new_wsi->ssl, 0), NULL));
Andy Green1f9bf522011-02-14 21:14:37 +0000531 libwebsockets_decode_ssl_error();
Andy Green0d338332011-02-12 11:57:43 +0000532 free(new_wsi);
533 break;
534 }
535
536 SSL_set_fd(new_wsi->ssl, accept_fd);
537
538 n = SSL_accept(new_wsi->ssl);
539 if (n != 1) {
540 /*
541 * browsers seem to probe with various
542 * ssl params which fail then retry
543 * and succeed
544 */
545 debug("SSL_accept failed skt %u: %s\n",
546 pollfd->fd,
547 ERR_error_string(SSL_get_error(
548 new_wsi->ssl, n), NULL));
549 SSL_free(
550 new_wsi->ssl);
551 free(new_wsi);
552 break;
553 }
Andy Greenc6bf2c22011-02-20 11:10:47 +0000554
Andy Green0d338332011-02-12 11:57:43 +0000555 debug("accepted new SSL conn "
556 "port %u on fd=%d SSL ver %s\n",
557 ntohs(cli_addr.sin_port), accept_fd,
558 SSL_get_version(new_wsi->ssl));
559
560 } else
561#endif
562 debug("accepted new conn port %u on fd=%d\n",
563 ntohs(cli_addr.sin_port), accept_fd);
564
565 /* intialize the instance struct */
566
567 new_wsi->state = WSI_STATE_HTTP;
568 new_wsi->name_buffer_pos = 0;
569 new_wsi->mode = LWS_CONNMODE_WS_SERVING;
570
571 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
572 new_wsi->utf8_token[n].token = NULL;
573 new_wsi->utf8_token[n].token_len = 0;
574 }
575
576 /*
577 * these can only be set once the protocol is known
578 * we set an unestablished connection's protocol pointer
579 * to the start of the supported list, so it can look
580 * for matching ones during the handshake
581 */
Peter Hinz56885f32011-03-02 22:03:47 +0000582 new_wsi->protocol = context->protocols;
Andy Green0d338332011-02-12 11:57:43 +0000583 new_wsi->user_space = NULL;
584
585 /*
586 * Default protocol is 76 / 00
587 * After 76, there's a header specified to inform which
588 * draft the client wants, when that's seen we modify
589 * the individual connection's spec revision accordingly
590 */
591 new_wsi->ietf_spec_revision = 0;
592
Peter Hinz56885f32011-03-02 22:03:47 +0000593 insert_wsi(context, new_wsi);
Andy Green0d338332011-02-12 11:57:43 +0000594
Andy Green0d338332011-02-12 11:57:43 +0000595 /*
596 * make sure NO events are seen yet on this new socket
597 * (otherwise we inherit old fds[client].revents from
598 * previous socket there and die mysteriously! )
599 */
Peter Hinz56885f32011-03-02 22:03:47 +0000600 context->fds[context->fds_count].revents = 0;
Andy Green0d338332011-02-12 11:57:43 +0000601
Peter Hinz56885f32011-03-02 22:03:47 +0000602 context->fds[context->fds_count].events = POLLIN;
603 context->fds[context->fds_count++].fd = accept_fd;
Andy Green0d338332011-02-12 11:57:43 +0000604
Andy Green3221f922011-02-12 13:14:11 +0000605 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000606 context->protocols[0].callback(context, new_wsi,
Andy Green3221f922011-02-12 13:14:11 +0000607 LWS_CALLBACK_ADD_POLL_FD,
608 (void *)(long)accept_fd, NULL, POLLIN);
609
Andy Green0d338332011-02-12 11:57:43 +0000610 break;
611
612 case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
613
614 /* as we are listening, POLLIN means accept() is needed */
615
616 if (!pollfd->revents & POLLIN)
617 break;
618
619 /* listen socket got an unencrypted connection... */
620
621 clilen = sizeof(cli_addr);
622 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
623 &clilen);
624 if (accept_fd < 0) {
625 fprintf(stderr, "ERROR on accept");
626 break;
627 }
628
Peter Hinz56885f32011-03-02 22:03:47 +0000629 if (context->fds_count >= MAX_CLIENTS) {
Andy Green3221f922011-02-12 13:14:11 +0000630 fprintf(stderr, "too busy to accept new broadcast "
631 "proxy client\n");
Peter Hinz56885f32011-03-02 22:03:47 +0000632#ifdef WIN32
633 closesocket(accept_fd);
634#else
Andy Green0d338332011-02-12 11:57:43 +0000635 close(accept_fd);
Peter Hinz56885f32011-03-02 22:03:47 +0000636#endif
Andy Green0d338332011-02-12 11:57:43 +0000637 break;
638 }
639
640 /* create a dummy wsi for the connection and add it */
641
642 new_wsi = malloc(sizeof(struct libwebsocket));
643 memset(new_wsi, 0, sizeof (struct libwebsocket));
644 new_wsi->sock = accept_fd;
645 new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY;
646 new_wsi->state = WSI_STATE_ESTABLISHED;
647 /* note which protocol we are proxying */
648 new_wsi->protocol_index_for_broadcast_proxy =
649 wsi->protocol_index_for_broadcast_proxy;
Peter Hinz56885f32011-03-02 22:03:47 +0000650 insert_wsi(context, new_wsi);
Andy Green0d338332011-02-12 11:57:43 +0000651
652 /* add connected socket to internal poll array */
653
Peter Hinz56885f32011-03-02 22:03:47 +0000654 context->fds[context->fds_count].revents = 0;
655 context->fds[context->fds_count].events = POLLIN;
656 context->fds[context->fds_count++].fd = accept_fd;
Andy Green0d338332011-02-12 11:57:43 +0000657
Andy Green3221f922011-02-12 13:14:11 +0000658 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000659 context->protocols[0].callback(context, new_wsi,
Andy Green3221f922011-02-12 13:14:11 +0000660 LWS_CALLBACK_ADD_POLL_FD,
661 (void *)(long)accept_fd, NULL, POLLIN);
662
Andy Green0d338332011-02-12 11:57:43 +0000663 break;
664
665 case LWS_CONNMODE_BROADCAST_PROXY:
Andy Green8f037e42010-12-19 22:13:26 +0000666
Andy Greenb45993c2010-12-18 15:13:50 +0000667 /* handle session socket closed */
Andy Green8f037e42010-12-19 22:13:26 +0000668
Andy Green0d338332011-02-12 11:57:43 +0000669 if (pollfd->revents & (POLLERR | POLLHUP)) {
Andy Green8f037e42010-12-19 22:13:26 +0000670
Andy Green0d338332011-02-12 11:57:43 +0000671 debug("Session Socket %p (fd=%d) dead\n",
Timothy J Fontaineb86d64e2011-02-14 17:55:27 +0000672 (void *)wsi, pollfd->fd);
Andy Greenb45993c2010-12-18 15:13:50 +0000673
Peter Hinz56885f32011-03-02 22:03:47 +0000674 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000675 LWS_CLOSE_STATUS_NORMAL);
Andy Green4b6fbe12011-02-14 08:03:48 +0000676 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +0000677 }
Andy Green8f037e42010-12-19 22:13:26 +0000678
Andy Green90c7cbc2011-01-27 06:26:52 +0000679 /* the guy requested a callback when it was OK to write */
680
Andy Green0d338332011-02-12 11:57:43 +0000681 if (pollfd->revents & POLLOUT) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000682
Andy Green0d338332011-02-12 11:57:43 +0000683 /* one shot */
Andy Green90c7cbc2011-01-27 06:26:52 +0000684
Andy Green0d338332011-02-12 11:57:43 +0000685 pollfd->events &= ~POLLOUT;
686
Andy Green3221f922011-02-12 13:14:11 +0000687 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000688 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +0000689 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
690 (void *)(long)wsi->sock, NULL, POLLOUT);
691
Peter Hinz56885f32011-03-02 22:03:47 +0000692 wsi->protocol->callback(context, wsi,
Andy Green90c7cbc2011-01-27 06:26:52 +0000693 LWS_CALLBACK_CLIENT_WRITEABLE,
Andy Green0d338332011-02-12 11:57:43 +0000694 wsi->user_space,
Andy Green90c7cbc2011-01-27 06:26:52 +0000695 NULL, 0);
696 }
697
Andy Greenb45993c2010-12-18 15:13:50 +0000698 /* any incoming data ready? */
699
Andy Green0d338332011-02-12 11:57:43 +0000700 if (!(pollfd->revents & POLLIN))
701 break;
Andy Greenb45993c2010-12-18 15:13:50 +0000702
Andy Green0d338332011-02-12 11:57:43 +0000703 /* get the issued broadcast payload from the socket */
Andy Greenb45993c2010-12-18 15:13:50 +0000704
Andy Green0d338332011-02-12 11:57:43 +0000705 len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING,
706 MAX_BROADCAST_PAYLOAD);
707 if (len < 0) {
708 fprintf(stderr, "Error reading broadcast payload\n");
Andy Green4b6fbe12011-02-14 08:03:48 +0000709 break;
Andy Green0d338332011-02-12 11:57:43 +0000710 }
Andy Greenb45993c2010-12-18 15:13:50 +0000711
Andy Green0d338332011-02-12 11:57:43 +0000712 /* broadcast it to all guys with this protocol index */
Andy Green8f037e42010-12-19 22:13:26 +0000713
Andy Green0d338332011-02-12 11:57:43 +0000714 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
Andy Green8f037e42010-12-19 22:13:26 +0000715
Peter Hinz56885f32011-03-02 22:03:47 +0000716 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Greenb45993c2010-12-18 15:13:50 +0000717
Peter Hinz56885f32011-03-02 22:03:47 +0000718 new_wsi = context->fd_hashtable[n].wsi[m];
Andy Greenb45993c2010-12-18 15:13:50 +0000719
Andy Green0d338332011-02-12 11:57:43 +0000720 /* only to clients we are serving to */
Andy Greenb45993c2010-12-18 15:13:50 +0000721
Andy Green0d338332011-02-12 11:57:43 +0000722 if (new_wsi->mode != LWS_CONNMODE_WS_SERVING)
Andy Greenb45993c2010-12-18 15:13:50 +0000723 continue;
724
725 /*
726 * never broadcast to non-established
727 * connection
728 */
729
Andy Green0d338332011-02-12 11:57:43 +0000730 if (new_wsi->state != WSI_STATE_ESTABLISHED)
Andy Green4739e5c2011-01-22 12:51:57 +0000731 continue;
732
Andy Greenb45993c2010-12-18 15:13:50 +0000733 /*
734 * only broadcast to connections using
735 * the requested protocol
736 */
737
Andy Green0d338332011-02-12 11:57:43 +0000738 if (new_wsi->protocol->protocol_index !=
739 wsi->protocol_index_for_broadcast_proxy)
Andy Greenb45993c2010-12-18 15:13:50 +0000740 continue;
741
Andy Green8f037e42010-12-19 22:13:26 +0000742 /* broadcast it to this connection */
743
Peter Hinz56885f32011-03-02 22:03:47 +0000744 new_wsi->protocol->callback(context, new_wsi,
Andy Green8f037e42010-12-19 22:13:26 +0000745 LWS_CALLBACK_BROADCAST,
Andy Green0d338332011-02-12 11:57:43 +0000746 new_wsi->user_space,
Andy Green0ca6a172010-12-19 20:50:01 +0000747 buf + LWS_SEND_BUFFER_PRE_PADDING, len);
Andy Greenb45993c2010-12-18 15:13:50 +0000748 }
Andy Green0d338332011-02-12 11:57:43 +0000749 }
750 break;
Andy Greenb45993c2010-12-18 15:13:50 +0000751
Andy Greenbe93fef2011-02-14 20:25:43 +0000752 case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
753
754 /* handle proxy hung up on us */
755
756 if (pollfd->revents & (POLLERR | POLLHUP)) {
757
758 fprintf(stderr, "Proxy connection %p (fd=%d) dead\n",
759 (void *)wsi, pollfd->fd);
760
Peter Hinz56885f32011-03-02 22:03:47 +0000761 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000762 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000763 return 1;
764 }
765
766 n = recv(wsi->sock, pkt, sizeof pkt, 0);
767 if (n < 0) {
Peter Hinz56885f32011-03-02 22:03:47 +0000768 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000769 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000770 fprintf(stderr, "ERROR reading from proxy socket\n");
771 return 1;
772 }
773
774 pkt[13] = '\0';
775 if (strcmp(pkt, "HTTP/1.0 200 ") != 0) {
Peter Hinz56885f32011-03-02 22:03:47 +0000776 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000777 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000778 fprintf(stderr, "ERROR from proxy: %s\n", pkt);
779 return 1;
780 }
781
782 /* clear his proxy connection timeout */
783
784 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
785
786 /* fallthru */
787
788 case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
789
790 #ifdef LWS_OPENSSL_SUPPORT
791 if (wsi->use_ssl) {
792
Peter Hinz56885f32011-03-02 22:03:47 +0000793 wsi->ssl = SSL_new(context->ssl_client_ctx);
794 wsi->client_bio = BIO_new_socket(wsi->sock,
795 BIO_NOCLOSE);
Andy Greenbe93fef2011-02-14 20:25:43 +0000796 SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
797
Andy Green6901cb32011-02-21 08:06:47 +0000798 SSL_set_ex_data(wsi->ssl,
Andy Green2e24da02011-03-05 16:12:04 +0000799 openssl_websocket_private_data_index,
Peter Hinz56885f32011-03-02 22:03:47 +0000800 context);
Andy Green6901cb32011-02-21 08:06:47 +0000801
Andy Greenbe93fef2011-02-14 20:25:43 +0000802 if (SSL_connect(wsi->ssl) <= 0) {
803 fprintf(stderr, "SSL connect error %s\n",
Andy Green687b0182011-02-26 11:04:01 +0000804 ERR_error_string(ERR_get_error(),
805 ssl_err_buf));
Peter Hinz56885f32011-03-02 22:03:47 +0000806 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000807 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000808 return 1;
809 }
810
811 n = SSL_get_verify_result(wsi->ssl);
Andy Green2e24da02011-03-05 16:12:04 +0000812 if ((n != X509_V_OK) && (
Andy Green687b0182011-02-26 11:04:01 +0000813 n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
814 wsi->use_ssl != 2)) {
Andy Greenbe93fef2011-02-14 20:25:43 +0000815
Andy Green687b0182011-02-26 11:04:01 +0000816 fprintf(stderr, "server's cert didn't "
817 "look good %d\n", n);
Peter Hinz56885f32011-03-02 22:03:47 +0000818 libwebsocket_close_and_free_session(context,
819 wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Green687b0182011-02-26 11:04:01 +0000820 return 1;
Andy Greenbe93fef2011-02-14 20:25:43 +0000821 }
822 } else {
823 wsi->ssl = NULL;
824 #endif
825
826
827 #ifdef LWS_OPENSSL_SUPPORT
828 }
829 #endif
830
831 /*
832 * create the random key
833 */
834
Peter Hinz56885f32011-03-02 22:03:47 +0000835 n = libwebsockets_get_random(context, hash, 16);
Andy Greenbe93fef2011-02-14 20:25:43 +0000836 if (n != 16) {
837 fprintf(stderr, "Unable to read from random dev %s\n",
838 SYSTEM_RANDOM_FILEPATH);
839 free(wsi->c_path);
840 free(wsi->c_host);
Andy Green08d33922011-02-26 10:22:49 +0000841 if (wsi->c_origin)
842 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000843 if (wsi->c_protocol)
844 free(wsi->c_protocol);
Peter Hinz56885f32011-03-02 22:03:47 +0000845 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000846 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000847 return 1;
848 }
849
850 lws_b64_encode_string(hash, 16, wsi->key_b64,
851 sizeof wsi->key_b64);
852
853 /*
Andy Greeneeaacb32011-03-01 20:44:24 +0000854 * 00 example client handshake
855 *
856 * GET /socket.io/websocket HTTP/1.1
857 * Upgrade: WebSocket
858 * Connection: Upgrade
859 * Host: 127.0.0.1:9999
860 * Origin: http://127.0.0.1
861 * Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^
862 * Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
863 * Cookie: socketio=websocket
864 *
865 * (Á®Ä0¶†≥
866 *
Andy Greenbe93fef2011-02-14 20:25:43 +0000867 * 04 example client handshake
868 *
869 * GET /chat HTTP/1.1
870 * Host: server.example.com
871 * Upgrade: websocket
872 * Connection: Upgrade
873 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
874 * Sec-WebSocket-Origin: http://example.com
875 * Sec-WebSocket-Protocol: chat, superchat
876 * Sec-WebSocket-Version: 4
877 */
878
Andy Green08d33922011-02-26 10:22:49 +0000879 p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", wsi->c_path);
Andy Greeneeaacb32011-03-01 20:44:24 +0000880
881 if (wsi->ietf_spec_revision == 0) {
882 unsigned char spaces_1, spaces_2;
883 unsigned int max_1, max_2;
884 unsigned int num_1, num_2;
885 unsigned long product_1, product_2;
886 char key_1[40];
887 char key_2[40];
888 unsigned int seed;
889 unsigned int count;
890 char challenge[16];
891
Peter Hinz56885f32011-03-02 22:03:47 +0000892 libwebsockets_get_random(context, &spaces_1,
893 sizeof(char));
894 libwebsockets_get_random(context, &spaces_2,
895 sizeof(char));
896
Andy Greeneeaacb32011-03-01 20:44:24 +0000897 spaces_1 = (spaces_1 % 12) + 1;
898 spaces_2 = (spaces_2 % 12) + 1;
Peter Hinz56885f32011-03-02 22:03:47 +0000899
Andy Greeneeaacb32011-03-01 20:44:24 +0000900 max_1 = 4294967295 / spaces_1;
901 max_2 = 4294967295 / spaces_2;
902
Peter Hinz56885f32011-03-02 22:03:47 +0000903 libwebsockets_get_random(context, &num_1, sizeof(int));
904 libwebsockets_get_random(context, &num_2, sizeof(int));
905
Andy Greeneeaacb32011-03-01 20:44:24 +0000906 num_1 = (num_1 % max_1);
907 num_2 = (num_2 % max_2);
Peter Hinz56885f32011-03-02 22:03:47 +0000908
Andy Greeneeaacb32011-03-01 20:44:24 +0000909 challenge[0] = num_1 >> 24;
910 challenge[1] = num_1 >> 16;
911 challenge[2] = num_1 >> 8;
912 challenge[3] = num_1;
913 challenge[4] = num_2 >> 24;
914 challenge[5] = num_2 >> 16;
915 challenge[6] = num_2 >> 8;
916 challenge[7] = num_2;
Peter Hinz56885f32011-03-02 22:03:47 +0000917
Andy Greeneeaacb32011-03-01 20:44:24 +0000918 product_1 = num_1 * spaces_1;
919 product_2 = num_2 * spaces_2;
Peter Hinz56885f32011-03-02 22:03:47 +0000920
Andy Greeneeaacb32011-03-01 20:44:24 +0000921 sprintf(key_1, "%lu", product_1);
922 sprintf(key_2, "%lu", product_2);
923
Peter Hinz56885f32011-03-02 22:03:47 +0000924 libwebsockets_get_random(context, &seed, sizeof(int));
925 libwebsockets_get_random(context, &count, sizeof(int));
926
Andy Greeneeaacb32011-03-01 20:44:24 +0000927 libwebsockets_00_spam(key_1, (count % 12) + 1, seed);
Peter Hinz56885f32011-03-02 22:03:47 +0000928
929 libwebsockets_get_random(context, &seed, sizeof(int));
930 libwebsockets_get_random(context, &count, sizeof(int));
931
Andy Greeneeaacb32011-03-01 20:44:24 +0000932 libwebsockets_00_spam(key_2, (count % 12) + 1, seed);
Peter Hinz56885f32011-03-02 22:03:47 +0000933
934 libwebsockets_get_random(context, &seed, sizeof(int));
935
Andy Greeneeaacb32011-03-01 20:44:24 +0000936 libwebsockets_00_spaceout(key_1, spaces_1, seed);
937 libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16);
Peter Hinz56885f32011-03-02 22:03:47 +0000938
Andy Greeneeaacb32011-03-01 20:44:24 +0000939 p += sprintf(p, "Upgrade: websocket\x0d\x0a"
940 "Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000941 wsi->c_host);
Andy Greeneeaacb32011-03-01 20:44:24 +0000942 if (wsi->c_origin)
943 p += sprintf(p, "Origin: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000944 wsi->c_origin);
945
Andy Greeneeaacb32011-03-01 20:44:24 +0000946 if (wsi->c_protocol)
Peter Hinz56885f32011-03-02 22:03:47 +0000947 p += sprintf(p, "Sec-WebSocket-Protocol: %s"
948 "\x0d\x0a", wsi->c_protocol);
949
Andy Greeneeaacb32011-03-01 20:44:24 +0000950 p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000951 key_1);
Andy Greeneeaacb32011-03-01 20:44:24 +0000952 p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000953 key_2);
Andy Greeneeaacb32011-03-01 20:44:24 +0000954
Andy Green385e7ad2011-03-01 21:06:02 +0000955 /* give userland a chance to append, eg, cookies */
Peter Hinz56885f32011-03-02 22:03:47 +0000956
957 context->protocols[0].callback(context, wsi,
958 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
Andy Green385e7ad2011-03-01 21:06:02 +0000959 NULL, &p, (pkt + sizeof(pkt)) - p - 12);
960
Andy Greeneeaacb32011-03-01 20:44:24 +0000961 p += sprintf(p, "\x0d\x0a");
Peter Hinz56885f32011-03-02 22:03:47 +0000962
963 read(context->fd_random, p, 8);
Andy Greeneeaacb32011-03-01 20:44:24 +0000964 memcpy(&challenge[8], p, 8);
965 p += 8;
Peter Hinz56885f32011-03-02 22:03:47 +0000966
Andy Greeneeaacb32011-03-01 20:44:24 +0000967 /* precompute what we want to see from the server */
Peter Hinz56885f32011-03-02 22:03:47 +0000968
Andy Greeneeaacb32011-03-01 20:44:24 +0000969 MD5((unsigned char *)challenge, 16,
970 (unsigned char *)wsi->initial_handshake_hash_base64);
Peter Hinz56885f32011-03-02 22:03:47 +0000971
Andy Greeneeaacb32011-03-01 20:44:24 +0000972 goto issue_hdr;
973 }
974
Andy Green08d33922011-02-26 10:22:49 +0000975 p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host);
976 p += sprintf(p, "Upgrade: websocket\x0d\x0a");
977 p += sprintf(p, "Connection: Upgrade\x0d\x0a"
Andy Greenbe93fef2011-02-14 20:25:43 +0000978 "Sec-WebSocket-Key: ");
Andy Green08d33922011-02-26 10:22:49 +0000979 strcpy(p, wsi->key_b64);
980 p += strlen(wsi->key_b64);
981 p += sprintf(p, "\x0d\x0a");
982 if (wsi->c_origin)
983 p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a",
Andy Greenbe93fef2011-02-14 20:25:43 +0000984 wsi->c_origin);
Andy Green08d33922011-02-26 10:22:49 +0000985 if (wsi->c_protocol)
Andy Greenbe93fef2011-02-14 20:25:43 +0000986 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
987 wsi->c_protocol);
Andy Green385e7ad2011-03-01 21:06:02 +0000988 p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000989 wsi->ietf_spec_revision);
Andy Green385e7ad2011-03-01 21:06:02 +0000990 /* give userland a chance to append, eg, cookies */
Peter Hinz56885f32011-03-02 22:03:47 +0000991
992 context->protocols[0].callback(context, wsi,
993 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
994 NULL, &p, (pkt + sizeof(pkt)) - p - 12);
995
Andy Green385e7ad2011-03-01 21:06:02 +0000996 p += sprintf(p, "\x0d\x0a");
997
Andy Greenbe93fef2011-02-14 20:25:43 +0000998 /* prepare the expected server accept response */
999
1000 strcpy((char *)buf, wsi->key_b64);
1001 strcpy((char *)&buf[strlen((char *)buf)], magic_websocket_guid);
1002
1003 SHA1(buf, strlen((char *)buf), (unsigned char *)hash);
1004
1005 lws_b64_encode_string(hash, 20,
1006 wsi->initial_handshake_hash_base64,
1007 sizeof wsi->initial_handshake_hash_base64);
Peter Hinz56885f32011-03-02 22:03:47 +00001008
Andy Greeneeaacb32011-03-01 20:44:24 +00001009issue_hdr:
Peter Hinz56885f32011-03-02 22:03:47 +00001010
Andy Greeneeaacb32011-03-01 20:44:24 +00001011 /* done with these now */
Peter Hinz56885f32011-03-02 22:03:47 +00001012
Andy Greeneeaacb32011-03-01 20:44:24 +00001013 free(wsi->c_path);
1014 free(wsi->c_host);
1015 if (wsi->c_origin)
1016 free(wsi->c_origin);
1017
Andy Greenbe93fef2011-02-14 20:25:43 +00001018 /* send our request to the server */
1019
1020 #ifdef LWS_OPENSSL_SUPPORT
1021 if (wsi->use_ssl)
1022 n = SSL_write(wsi->ssl, pkt, p - pkt);
1023 else
1024 #endif
1025 n = send(wsi->sock, pkt, p - pkt, 0);
1026
1027 if (n < 0) {
1028 fprintf(stderr, "ERROR writing to client socket\n");
Peter Hinz56885f32011-03-02 22:03:47 +00001029 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001030 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +00001031 return 1;
1032 }
1033
1034 wsi->parser_state = WSI_TOKEN_NAME_PART;
1035 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY;
1036 libwebsocket_set_timeout(wsi,
1037 PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, 5);
1038
1039 break;
1040
1041 case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
1042
1043 /* handle server hung up on us */
1044
1045 if (pollfd->revents & (POLLERR | POLLHUP)) {
1046
1047 fprintf(stderr, "Server connection %p (fd=%d) dead\n",
1048 (void *)wsi, pollfd->fd);
1049
1050 goto bail3;
1051 }
1052
1053
1054 /* interpret the server response */
1055
1056 /*
1057 * HTTP/1.1 101 Switching Protocols
1058 * Upgrade: websocket
1059 * Connection: Upgrade
1060 * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
1061 * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
1062 * Sec-WebSocket-Protocol: chat
1063 */
1064
1065 #ifdef LWS_OPENSSL_SUPPORT
1066 if (wsi->use_ssl)
1067 len = SSL_read(wsi->ssl, pkt, sizeof pkt);
1068 else
1069 #endif
1070 len = recv(wsi->sock, pkt, sizeof pkt, 0);
1071
1072 if (len < 0) {
1073 fprintf(stderr,
1074 "libwebsocket_client_handshake read error\n");
1075 goto bail3;
1076 }
1077
1078 p = pkt;
1079 for (n = 0; n < len; n++)
1080 libwebsocket_parse(wsi, *p++);
1081
1082 if (wsi->parser_state != WSI_PARSING_COMPLETE) {
1083 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001084 "server response failed parsing\n");
Andy Greenbe93fef2011-02-14 20:25:43 +00001085 goto bail3;
1086 }
1087
1088 /*
Andy Greeneeaacb32011-03-01 20:44:24 +00001089 * 00 / 76 -->
1090 *
1091 * HTTP/1.1 101 WebSocket Protocol Handshake
1092 * Upgrade: WebSocket
1093 * Connection: Upgrade
1094 * Sec-WebSocket-Origin: http://127.0.0.1
1095 * Sec-WebSocket-Location: ws://127.0.0.1:9999/socket.io/websocket
1096 *
1097 * xxxxxxxxxxxxxxxx
1098 */
Peter Hinz56885f32011-03-02 22:03:47 +00001099
Andy Greeneeaacb32011-03-01 20:44:24 +00001100 if (wsi->ietf_spec_revision == 0) {
1101 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
Peter Hinz56885f32011-03-02 22:03:47 +00001102 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
1103 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
1104 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
1105 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
1106 wsi->c_protocol != NULL)) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001107 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001108 "missing required header(s)\n");
Andy Greeneeaacb32011-03-01 20:44:24 +00001109 pkt[len] = '\0';
1110 fprintf(stderr, "%s", pkt);
1111 goto bail3;
1112 }
Andy Greeneeaacb32011-03-01 20:44:24 +00001113
Peter Hinz56885f32011-03-02 22:03:47 +00001114 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
1115 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
1116 "101 websocket protocol handshake")) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001117 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001118 "server sent bad HTTP response '%s'\n",
1119 wsi->utf8_token[WSI_TOKEN_HTTP].token);
1120 goto bail3;
1121 }
1122
1123 if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len <
1124 16) {
1125 fprintf(stderr, "libwebsocket_client_handshake "
1126 "challenge reply too short %d\n",
1127 wsi->utf8_token[
1128 WSI_TOKEN_CHALLENGE].token_len);
Andy Greeneeaacb32011-03-01 20:44:24 +00001129 pkt[len] = '\0';
1130 fprintf(stderr, "%s", pkt);
1131 goto bail3;
Peter Hinz56885f32011-03-02 22:03:47 +00001132
Andy Greeneeaacb32011-03-01 20:44:24 +00001133 }
Peter Hinz56885f32011-03-02 22:03:47 +00001134
Andy Greeneeaacb32011-03-01 20:44:24 +00001135 goto select_protocol;
1136 }
Peter Hinz56885f32011-03-02 22:03:47 +00001137
Andy Greeneeaacb32011-03-01 20:44:24 +00001138 /*
Andy Greenbe93fef2011-02-14 20:25:43 +00001139 * well, what the server sent looked reasonable for syntax.
1140 * Now let's confirm it sent all the necessary headers
1141 */
1142
1143 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
1144 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
1145 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
1146 !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len ||
Andy Green4eaa86b2011-02-26 11:17:48 +00001147 (!wsi->utf8_token[WSI_TOKEN_NONCE].token_len &&
1148 wsi->ietf_spec_revision == 4) ||
Andy Greenbe93fef2011-02-14 20:25:43 +00001149 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
1150 wsi->c_protocol != NULL)) {
1151 fprintf(stderr, "libwebsocket_client_handshake "
Andy Green687b0182011-02-26 11:04:01 +00001152 "missing required header(s)\n");
Andy Greenbe93fef2011-02-14 20:25:43 +00001153 pkt[len] = '\0';
1154 fprintf(stderr, "%s", pkt);
1155 goto bail3;
1156 }
1157
1158 /*
1159 * Everything seems to be there, now take a closer look at what
1160 * is in each header
1161 */
1162
1163 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
1164 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
1165 "101 switching protocols")) {
1166 fprintf(stderr, "libwebsocket_client_handshake "
1167 "server sent bad HTTP response '%s'\n",
1168 wsi->utf8_token[WSI_TOKEN_HTTP].token);
1169 goto bail3;
1170 }
1171
1172 strtolower(wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
1173 if (strcmp(wsi->utf8_token[WSI_TOKEN_UPGRADE].token,
1174 "websocket")) {
1175 fprintf(stderr, "libwebsocket_client_handshake server "
1176 "sent bad Upgrade header '%s'\n",
1177 wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
1178 goto bail3;
1179 }
1180
1181 strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
1182 if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token,
1183 "upgrade")) {
1184 fprintf(stderr, "libwebsocket_client_handshake server "
1185 "sent bad Connection hdr '%s'\n",
1186 wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
1187 goto bail3;
1188 }
1189
Andy Greeneeaacb32011-03-01 20:44:24 +00001190select_protocol:
Andy Greenbe93fef2011-02-14 20:25:43 +00001191 pc = wsi->c_protocol;
1192
1193 /*
1194 * confirm the protocol the server wants to talk was in the list
1195 * of protocols we offered
1196 */
1197
1198 if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
1199
1200 /*
1201 * no protocol name to work from,
1202 * default to first protocol
1203 */
Peter Hinz56885f32011-03-02 22:03:47 +00001204 wsi->protocol = &context->protocols[0];
Andy Greenbe93fef2011-02-14 20:25:43 +00001205
1206 free(wsi->c_protocol);
1207
1208 goto check_accept;
1209 }
1210
1211 while (*pc && !okay) {
1212 if ((!strncmp(pc,
1213 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
1214 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len)) &&
1215 (pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == ',' ||
1216 pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == '\0')) {
1217 okay = 1;
1218 continue;
1219 }
1220 while (*pc && *pc != ',')
1221 pc++;
1222 while (*pc && *pc != ' ')
1223 pc++;
1224 }
1225
1226 /* done with him now */
1227
1228 if (wsi->c_protocol)
1229 free(wsi->c_protocol);
1230
1231
1232 if (!okay) {
1233 fprintf(stderr, "libwebsocket_client_handshake server "
1234 "sent bad protocol '%s'\n",
1235 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
1236 goto bail2;
1237 }
1238
1239 /*
1240 * identify the selected protocol struct and set it
1241 */
1242 n = 0;
1243 wsi->protocol = NULL;
Peter Hinz56885f32011-03-02 22:03:47 +00001244 while (context->protocols[n].callback) {
Andy Greenbe93fef2011-02-14 20:25:43 +00001245 if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
Peter Hinz56885f32011-03-02 22:03:47 +00001246 context->protocols[n].name) == 0)
1247 wsi->protocol = &context->protocols[n];
Andy Greenbe93fef2011-02-14 20:25:43 +00001248 n++;
1249 }
1250
1251 if (wsi->protocol == NULL) {
1252 fprintf(stderr, "libwebsocket_client_handshake server "
1253 "requested protocol '%s', which we "
1254 "said we supported but we don't!\n",
1255 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
1256 goto bail2;
1257 }
1258
1259 check_accept:
Andy Greeneeaacb32011-03-01 20:44:24 +00001260
1261 if (wsi->ietf_spec_revision == 0) {
Peter Hinz56885f32011-03-02 22:03:47 +00001262
Andy Greeneeaacb32011-03-01 20:44:24 +00001263 if (memcmp(wsi->initial_handshake_hash_base64,
Peter Hinz56885f32011-03-02 22:03:47 +00001264 wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001265 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001266 "failed 00 challenge compare\n");
1267 pkt[len] = '\0';
1268 fprintf(stderr, "%s", pkt);
1269 goto bail2;
Andy Greeneeaacb32011-03-01 20:44:24 +00001270 }
Peter Hinz56885f32011-03-02 22:03:47 +00001271
Andy Greeneeaacb32011-03-01 20:44:24 +00001272 goto accept_ok;
1273 }
Peter Hinz56885f32011-03-02 22:03:47 +00001274
Andy Greenbe93fef2011-02-14 20:25:43 +00001275 /*
1276 * Confirm his accept token is the one we precomputed
1277 */
1278
1279 if (strcmp(wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
1280 wsi->initial_handshake_hash_base64)) {
1281 fprintf(stderr, "libwebsocket_client_handshake server "
1282 "sent bad ACCEPT '%s' vs computed '%s'\n",
1283 wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
1284 wsi->initial_handshake_hash_base64);
1285 goto bail2;
1286 }
1287
Andy Green4eaa86b2011-02-26 11:17:48 +00001288 if (wsi->ietf_spec_revision == 4) {
1289 /*
1290 * Calculate the 04 masking key to use when
1291 * sending data to server
1292 */
Andy Greenbe93fef2011-02-14 20:25:43 +00001293
Andy Green4eaa86b2011-02-26 11:17:48 +00001294 strcpy((char *)buf, wsi->key_b64);
1295 p = (char *)buf + strlen(wsi->key_b64);
1296 strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token);
1297 p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len;
1298 strcpy(p, magic_websocket_04_masking_guid);
1299 SHA1(buf, strlen((char *)buf), wsi->masking_key_04);
1300 }
Andy Greeneeaacb32011-03-01 20:44:24 +00001301accept_ok:
1302
Andy Greenbe93fef2011-02-14 20:25:43 +00001303 /* allocate the per-connection user memory (if any) */
1304
1305 if (wsi->protocol->per_session_data_size) {
1306 wsi->user_space = malloc(
1307 wsi->protocol->per_session_data_size);
1308 if (wsi->user_space == NULL) {
1309 fprintf(stderr, "Out of memory for "
1310 "conn user space\n");
1311 goto bail2;
1312 }
1313 } else
1314 wsi->user_space = NULL;
1315
1316 /* clear his proxy connection timeout */
1317
1318 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1319
1320 /* mark him as being alive */
1321
1322 wsi->state = WSI_STATE_ESTABLISHED;
1323 wsi->mode = LWS_CONNMODE_WS_CLIENT;
1324
1325 fprintf(stderr, "handshake OK for protocol %s\n",
1326 wsi->protocol->name);
1327
1328 /* call him back to inform him he is up */
1329
Peter Hinz56885f32011-03-02 22:03:47 +00001330 wsi->protocol->callback(context, wsi,
Andy Greenbe93fef2011-02-14 20:25:43 +00001331 LWS_CALLBACK_CLIENT_ESTABLISHED,
1332 wsi->user_space,
1333 NULL, 0);
1334
1335 break;
1336
1337bail3:
1338 if (wsi->c_protocol)
1339 free(wsi->c_protocol);
1340
1341bail2:
Peter Hinz56885f32011-03-02 22:03:47 +00001342 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001343 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +00001344 return 1;
1345
1346
Andy Green0d338332011-02-12 11:57:43 +00001347 case LWS_CONNMODE_WS_SERVING:
1348 case LWS_CONNMODE_WS_CLIENT:
1349
1350 /* handle session socket closed */
1351
1352 if (pollfd->revents & (POLLERR | POLLHUP)) {
1353
Andy Green62c54d22011-02-14 09:14:25 +00001354 fprintf(stderr, "Session Socket %p (fd=%d) dead\n",
Andy Green0d338332011-02-12 11:57:43 +00001355 (void *)wsi, pollfd->fd);
1356
Peter Hinz56885f32011-03-02 22:03:47 +00001357 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001358 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green4b6fbe12011-02-14 08:03:48 +00001359 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001360 }
1361
Andy Green0d338332011-02-12 11:57:43 +00001362 /* the guy requested a callback when it was OK to write */
1363
1364 if (pollfd->revents & POLLOUT) {
1365
1366 pollfd->events &= ~POLLOUT;
1367
Andy Green3221f922011-02-12 13:14:11 +00001368 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001369 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001370 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
1371 (void *)(long)wsi->sock, NULL, POLLOUT);
1372
Peter Hinz56885f32011-03-02 22:03:47 +00001373 wsi->protocol->callback(context, wsi,
Andy Green0d338332011-02-12 11:57:43 +00001374 LWS_CALLBACK_CLIENT_WRITEABLE,
1375 wsi->user_space,
1376 NULL, 0);
1377 }
1378
1379 /* any incoming data ready? */
1380
1381 if (!(pollfd->revents & POLLIN))
1382 break;
1383
Andy Greenb45993c2010-12-18 15:13:50 +00001384#ifdef LWS_OPENSSL_SUPPORT
Andy Green0d338332011-02-12 11:57:43 +00001385 if (wsi->ssl)
1386 n = SSL_read(wsi->ssl, buf, sizeof buf);
Andy Greenb45993c2010-12-18 15:13:50 +00001387 else
1388#endif
Andy Green0d338332011-02-12 11:57:43 +00001389 n = recv(pollfd->fd, buf, sizeof buf, 0);
Andy Greenb45993c2010-12-18 15:13:50 +00001390
1391 if (n < 0) {
1392 fprintf(stderr, "Socket read returned %d\n", n);
Andy Green4b6fbe12011-02-14 08:03:48 +00001393 break;
Andy Greenb45993c2010-12-18 15:13:50 +00001394 }
1395 if (!n) {
Peter Hinz56885f32011-03-02 22:03:47 +00001396 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001397 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green4b6fbe12011-02-14 08:03:48 +00001398 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001399 }
1400
Andy Greenb45993c2010-12-18 15:13:50 +00001401 /* service incoming data */
1402
Peter Hinz56885f32011-03-02 22:03:47 +00001403 n = libwebsocket_read(context, wsi, buf, n);
Andy Green6964bb52011-01-23 16:50:33 +00001404 if (n >= 0)
Andy Green4b6fbe12011-02-14 08:03:48 +00001405 break;
Andy Greenb45993c2010-12-18 15:13:50 +00001406
Andy Green4b6fbe12011-02-14 08:03:48 +00001407 /* we closed wsi */
Andy Green0d338332011-02-12 11:57:43 +00001408
Andy Green4b6fbe12011-02-14 08:03:48 +00001409 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001410 }
1411
1412 return 0;
1413}
1414
Andy Green0d338332011-02-12 11:57:43 +00001415
Andy Green6964bb52011-01-23 16:50:33 +00001416/**
1417 * libwebsocket_context_destroy() - Destroy the websocket context
Peter Hinz56885f32011-03-02 22:03:47 +00001418 * @context: Websocket context
Andy Green6964bb52011-01-23 16:50:33 +00001419 *
1420 * This function closes any active connections and then frees the
1421 * context. After calling this, any further use of the context is
1422 * undefined.
1423 */
1424void
Peter Hinz56885f32011-03-02 22:03:47 +00001425libwebsocket_context_destroy(struct libwebsocket_context *context)
Andy Green6964bb52011-01-23 16:50:33 +00001426{
Andy Green0d338332011-02-12 11:57:43 +00001427 int n;
1428 int m;
1429 struct libwebsocket *wsi;
Andy Green6964bb52011-01-23 16:50:33 +00001430
Andy Green4b6fbe12011-02-14 08:03:48 +00001431 for (n = 0; n < FD_HASHTABLE_MODULUS; n++)
Peter Hinz56885f32011-03-02 22:03:47 +00001432 for (m = 0; m < context->fd_hashtable[n].length; m++) {
1433 wsi = context->fd_hashtable[n].wsi[m];
1434 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001435 LWS_CLOSE_STATUS_GOINGAWAY);
Andy Greenf3d3b402011-02-09 07:16:34 +00001436 }
Andy Green6964bb52011-01-23 16:50:33 +00001437
Peter Hinz56885f32011-03-02 22:03:47 +00001438#ifdef WIN32
1439#else
1440 close(context->fd_random);
Andy Green6964bb52011-01-23 16:50:33 +00001441#endif
1442
Peter Hinz56885f32011-03-02 22:03:47 +00001443#ifdef LWS_OPENSSL_SUPPORT
1444 if (context->ssl_ctx)
1445 SSL_CTX_free(context->ssl_ctx);
1446 if (context->ssl_client_ctx)
1447 SSL_CTX_free(context->ssl_client_ctx);
1448#endif
1449
1450 free(context);
1451
1452#ifdef WIN32
1453 WSACleanup();
1454#endif
Andy Green6964bb52011-01-23 16:50:33 +00001455}
1456
1457/**
1458 * libwebsocket_service() - Service any pending websocket activity
Peter Hinz56885f32011-03-02 22:03:47 +00001459 * @context: Websocket context
Andy Green6964bb52011-01-23 16:50:33 +00001460 * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed
1461 * service otherwise block and service immediately, returning
1462 * after the timeout if nothing needed service.
1463 *
1464 * This function deals with any pending websocket traffic, for three
1465 * kinds of event. It handles these events on both server and client
1466 * types of connection the same.
1467 *
1468 * 1) Accept new connections to our context's server
1469 *
1470 * 2) Perform pending broadcast writes initiated from other forked
1471 * processes (effectively serializing asynchronous broadcasts)
1472 *
1473 * 3) Call the receive callback for incoming frame data received by
1474 * server or client connections.
1475 *
1476 * You need to call this service function periodically to all the above
1477 * functions to happen; if your application is single-threaded you can
1478 * just call it in your main event loop.
1479 *
1480 * Alternatively you can fork a new process that asynchronously handles
1481 * calling this service in a loop. In that case you are happy if this
1482 * call blocks your thread until it needs to take care of something and
1483 * would call it with a large nonzero timeout. Your loop then takes no
1484 * CPU while there is nothing happening.
1485 *
1486 * If you are calling it in a single-threaded app, you don't want it to
1487 * wait around blocking other things in your loop from happening, so you
1488 * would call it with a timeout_ms of 0, so it returns immediately if
1489 * nothing is pending, or as soon as it services whatever was pending.
1490 */
1491
Andy Greenb45993c2010-12-18 15:13:50 +00001492
Andy Greene92cd172011-01-19 13:11:55 +00001493int
Peter Hinz56885f32011-03-02 22:03:47 +00001494libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
Andy Greene92cd172011-01-19 13:11:55 +00001495{
1496 int n;
Andy Greene92cd172011-01-19 13:11:55 +00001497
1498 /* stay dead once we are dead */
1499
Peter Hinz56885f32011-03-02 22:03:47 +00001500 if (context == NULL)
Andy Greene92cd172011-01-19 13:11:55 +00001501 return 1;
1502
Andy Green0d338332011-02-12 11:57:43 +00001503 /* wait for something to need service */
Andy Green4739e5c2011-01-22 12:51:57 +00001504
Peter Hinz56885f32011-03-02 22:03:47 +00001505 n = poll(context->fds, context->fds_count, timeout_ms);
Andy Green3221f922011-02-12 13:14:11 +00001506 if (n == 0) /* poll timeout */
1507 return 0;
Andy Greene92cd172011-01-19 13:11:55 +00001508
Andy Green62c54d22011-02-14 09:14:25 +00001509 if (n < 0) {
Andy Green5e1fa172011-02-10 09:07:05 +00001510 /*
Andy Greene92cd172011-01-19 13:11:55 +00001511 fprintf(stderr, "Listen Socket dead\n");
Andy Green5e1fa172011-02-10 09:07:05 +00001512 */
Andy Green0d338332011-02-12 11:57:43 +00001513 return 1;
Andy Greene92cd172011-01-19 13:11:55 +00001514 }
Andy Greene92cd172011-01-19 13:11:55 +00001515
1516 /* handle accept on listening socket? */
1517
Peter Hinz56885f32011-03-02 22:03:47 +00001518 for (n = 0; n < context->fds_count; n++)
1519 if (context->fds[n].revents)
1520 libwebsocket_service_fd(context, &context->fds[n]);
Andy Greene92cd172011-01-19 13:11:55 +00001521
1522 return 0;
Andy Greene92cd172011-01-19 13:11:55 +00001523}
1524
Andy Green90c7cbc2011-01-27 06:26:52 +00001525/**
1526 * libwebsocket_callback_on_writable() - Request a callback when this socket
1527 * becomes able to be written to without
1528 * blocking
Andy Green32375b72011-02-19 08:32:53 +00001529 *
Peter Hinz56885f32011-03-02 22:03:47 +00001530 * @context: libwebsockets context
Andy Green90c7cbc2011-01-27 06:26:52 +00001531 * @wsi: Websocket connection instance to get callback for
1532 */
1533
1534int
Peter Hinz56885f32011-03-02 22:03:47 +00001535libwebsocket_callback_on_writable(struct libwebsocket_context *context,
Andy Green62c54d22011-02-14 09:14:25 +00001536 struct libwebsocket *wsi)
Andy Green90c7cbc2011-01-27 06:26:52 +00001537{
Andy Green90c7cbc2011-01-27 06:26:52 +00001538 int n;
1539
Peter Hinz56885f32011-03-02 22:03:47 +00001540 for (n = 0; n < context->fds_count; n++)
1541 if (context->fds[n].fd == wsi->sock) {
1542 context->fds[n].events |= POLLOUT;
1543 n = context->fds_count;
Andy Green90c7cbc2011-01-27 06:26:52 +00001544 }
1545
Andy Green3221f922011-02-12 13:14:11 +00001546 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001547 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001548 LWS_CALLBACK_SET_MODE_POLL_FD,
1549 (void *)(long)wsi->sock, NULL, POLLOUT);
1550
Andy Green90c7cbc2011-01-27 06:26:52 +00001551 return 1;
1552}
1553
1554/**
1555 * libwebsocket_callback_on_writable_all_protocol() - Request a callback for
1556 * all connections using the given protocol when it
1557 * becomes possible to write to each socket without
1558 * blocking in turn.
1559 *
1560 * @protocol: Protocol whose connections will get callbacks
1561 */
1562
1563int
1564libwebsocket_callback_on_writable_all_protocol(
1565 const struct libwebsocket_protocols *protocol)
1566{
Peter Hinz56885f32011-03-02 22:03:47 +00001567 struct libwebsocket_context *context = protocol->owning_server;
Andy Green90c7cbc2011-01-27 06:26:52 +00001568 int n;
Andy Green0d338332011-02-12 11:57:43 +00001569 int m;
1570 struct libwebsocket *wsi;
Andy Green90c7cbc2011-01-27 06:26:52 +00001571
Andy Green0d338332011-02-12 11:57:43 +00001572 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
1573
Peter Hinz56885f32011-03-02 22:03:47 +00001574 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Green0d338332011-02-12 11:57:43 +00001575
Peter Hinz56885f32011-03-02 22:03:47 +00001576 wsi = context->fd_hashtable[n].wsi[m];
Andy Green0d338332011-02-12 11:57:43 +00001577
1578 if (wsi->protocol == protocol)
Peter Hinz56885f32011-03-02 22:03:47 +00001579 libwebsocket_callback_on_writable(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00001580 }
1581 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001582
1583 return 0;
1584}
1585
Andy Greenbe93fef2011-02-14 20:25:43 +00001586/**
1587 * libwebsocket_set_timeout() - marks the wsi as subject to a timeout
1588 *
1589 * You will not need this unless you are doing something special
1590 *
1591 * @wsi: Websocket connection instance
1592 * @reason: timeout reason
1593 * @secs: how many seconds
1594 */
1595
1596void
1597libwebsocket_set_timeout(struct libwebsocket *wsi,
1598 enum pending_timeout reason, int secs)
1599{
1600 struct timeval tv;
1601
1602 gettimeofday(&tv, NULL);
1603
1604 wsi->pending_timeout_limit = tv.tv_sec + secs;
1605 wsi->pending_timeout = reason;
1606}
1607
Andy Greena6cbece2011-01-27 20:06:03 +00001608
1609/**
1610 * libwebsocket_get_socket_fd() - returns the socket file descriptor
1611 *
1612 * You will not need this unless you are doing something special
1613 *
1614 * @wsi: Websocket connection instance
1615 */
1616
1617int
1618libwebsocket_get_socket_fd(struct libwebsocket *wsi)
1619{
1620 return wsi->sock;
1621}
1622
Andy Green90c7cbc2011-01-27 06:26:52 +00001623/**
1624 * libwebsocket_rx_flow_control() - Enable and disable socket servicing for
1625 * receieved packets.
1626 *
1627 * If the output side of a server process becomes choked, this allows flow
1628 * control for the input side.
1629 *
1630 * @wsi: Websocket connection instance to get callback for
1631 * @enable: 0 = disable read servicing for this connection, 1 = enable
1632 */
1633
1634int
1635libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
1636{
Peter Hinz56885f32011-03-02 22:03:47 +00001637 struct libwebsocket_context *context = wsi->protocol->owning_server;
Andy Green90c7cbc2011-01-27 06:26:52 +00001638 int n;
1639
Peter Hinz56885f32011-03-02 22:03:47 +00001640 for (n = 0; n < context->fds_count; n++)
1641 if (context->fds[n].fd == wsi->sock) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001642 if (enable)
Peter Hinz56885f32011-03-02 22:03:47 +00001643 context->fds[n].events |= POLLIN;
Andy Green90c7cbc2011-01-27 06:26:52 +00001644 else
Peter Hinz56885f32011-03-02 22:03:47 +00001645 context->fds[n].events &= ~POLLIN;
Andy Green90c7cbc2011-01-27 06:26:52 +00001646
1647 return 0;
1648 }
1649
Andy Green3221f922011-02-12 13:14:11 +00001650 if (enable)
1651 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001652 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001653 LWS_CALLBACK_SET_MODE_POLL_FD,
1654 (void *)(long)wsi->sock, NULL, POLLIN);
1655 else
1656 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001657 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001658 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
1659 (void *)(long)wsi->sock, NULL, POLLIN);
1660
1661
Andy Green90c7cbc2011-01-27 06:26:52 +00001662 fprintf(stderr, "libwebsocket_callback_on_writable "
1663 "unable to find socket\n");
1664 return 1;
1665}
1666
Andy Green2ac5a6f2011-01-28 10:00:18 +00001667/**
1668 * libwebsocket_canonical_hostname() - returns this host's hostname
1669 *
1670 * This is typically used by client code to fill in the host parameter
1671 * when making a client connection. You can only call it after the context
1672 * has been created.
1673 *
Peter Hinz56885f32011-03-02 22:03:47 +00001674 * @context: Websocket context
Andy Green2ac5a6f2011-01-28 10:00:18 +00001675 */
1676
1677
1678extern const char *
Peter Hinz56885f32011-03-02 22:03:47 +00001679libwebsocket_canonical_hostname(struct libwebsocket_context *context)
Andy Green2ac5a6f2011-01-28 10:00:18 +00001680{
Peter Hinz56885f32011-03-02 22:03:47 +00001681 return (const char *)context->canonical_hostname;
Andy Green2ac5a6f2011-01-28 10:00:18 +00001682}
1683
1684
Andy Green90c7cbc2011-01-27 06:26:52 +00001685static void sigpipe_handler(int x)
1686{
1687}
1688
Andy Green6901cb32011-02-21 08:06:47 +00001689#ifdef LWS_OPENSSL_SUPPORT
1690static int
1691OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
1692{
1693
1694 SSL *ssl;
1695 int n;
Andy Green2e24da02011-03-05 16:12:04 +00001696 struct libwebsocket_context *context;
Andy Green6901cb32011-02-21 08:06:47 +00001697
1698 ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
1699 SSL_get_ex_data_X509_STORE_CTX_idx());
1700
1701 /*
Andy Green2e24da02011-03-05 16:12:04 +00001702 * !!! nasty openssl requires the index to come as a library-scope
1703 * static
Andy Green6901cb32011-02-21 08:06:47 +00001704 */
Andy Green2e24da02011-03-05 16:12:04 +00001705 context = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
Andy Green6901cb32011-02-21 08:06:47 +00001706
Peter Hinz56885f32011-03-02 22:03:47 +00001707 n = context->protocols[0].callback(NULL, NULL,
Andy Green6901cb32011-02-21 08:06:47 +00001708 LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
1709 x509_ctx, ssl, preverify_ok);
1710
1711 /* convert return code from 0 = OK to 1 = OK */
1712
1713 if (!n)
1714 n = 1;
1715 else
1716 n = 0;
1717
1718 return n;
1719}
1720#endif
1721
Andy Greenb45993c2010-12-18 15:13:50 +00001722
Andy Greenab990e42010-10-31 12:42:52 +00001723/**
Andy Green4739e5c2011-01-22 12:51:57 +00001724 * libwebsocket_create_context() - Create the websocket handler
1725 * @port: Port to listen on... you can use 0 to suppress listening on
Andy Green6964bb52011-01-23 16:50:33 +00001726 * any port, that's what you want if you are not running a
1727 * websocket server at all but just using it as a client
Peter Hinz56885f32011-03-02 22:03:47 +00001728 * @interf: NULL to bind the listen socket to all interfaces, or the
Andy Green32375b72011-02-19 08:32:53 +00001729 * interface name, eg, "eth2"
Andy Green4f3943a2010-11-12 10:44:16 +00001730 * @protocols: Array of structures listing supported protocols and a protocol-
Andy Green8f037e42010-12-19 22:13:26 +00001731 * specific callback for each one. The list is ended with an
1732 * entry that has a NULL callback pointer.
Andy Green6964bb52011-01-23 16:50:33 +00001733 * It's not const because we write the owning_server member
Andy Green3faa9c72010-11-08 17:03:03 +00001734 * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want
Andy Green8f037e42010-12-19 22:13:26 +00001735 * to listen using SSL, set to the filepath to fetch the
1736 * server cert from, otherwise NULL for unencrypted
Andy Green3faa9c72010-11-08 17:03:03 +00001737 * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
Andy Green8f037e42010-12-19 22:13:26 +00001738 * else ignored
Andy Green3faa9c72010-11-08 17:03:03 +00001739 * @gid: group id to change to after setting listen socket, or -1.
1740 * @uid: user id to change to after setting listen socket, or -1.
Andy Greenbfb051f2011-02-09 08:49:14 +00001741 * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK
Andy Green05464c62010-11-12 10:44:18 +00001742 *
Andy Green8f037e42010-12-19 22:13:26 +00001743 * This function creates the listening socket and takes care
1744 * of all initialization in one step.
1745 *
Andy Greene92cd172011-01-19 13:11:55 +00001746 * After initialization, it returns a struct libwebsocket_context * that
1747 * represents this server. After calling, user code needs to take care
1748 * of calling libwebsocket_service() with the context pointer to get the
1749 * server's sockets serviced. This can be done in the same process context
1750 * or a forked process, or another thread,
Andy Green05464c62010-11-12 10:44:18 +00001751 *
Andy Green8f037e42010-12-19 22:13:26 +00001752 * The protocol callback functions are called for a handful of events
1753 * including http requests coming in, websocket connections becoming
1754 * established, and data arriving; it's also called periodically to allow
1755 * async transmission.
1756 *
1757 * HTTP requests are sent always to the FIRST protocol in @protocol, since
1758 * at that time websocket protocol has not been negotiated. Other
1759 * protocols after the first one never see any HTTP callack activity.
1760 *
1761 * The server created is a simple http server by default; part of the
1762 * websocket standard is upgrading this http connection to a websocket one.
1763 *
1764 * This allows the same server to provide files like scripts and favicon /
1765 * images or whatever over http and dynamic data over websockets all in
1766 * one place; they're all handled in the user callback.
Andy Greenab990e42010-10-31 12:42:52 +00001767 */
Andy Green4ea60062010-10-30 12:15:07 +01001768
Andy Greene92cd172011-01-19 13:11:55 +00001769struct libwebsocket_context *
Peter Hinz56885f32011-03-02 22:03:47 +00001770libwebsocket_create_context(int port, const char *interf,
Andy Greenb45993c2010-12-18 15:13:50 +00001771 struct libwebsocket_protocols *protocols,
Andy Green8f037e42010-12-19 22:13:26 +00001772 const char *ssl_cert_filepath,
1773 const char *ssl_private_key_filepath,
Andy Green8014b292011-01-30 20:57:25 +00001774 int gid, int uid, unsigned int options)
Andy Greenff95d7a2010-10-28 22:36:01 +01001775{
1776 int n;
Andy Green4739e5c2011-01-22 12:51:57 +00001777 int sockfd = 0;
Andy Green251f6fa2010-11-03 11:13:06 +00001778 int fd;
Andy Greenff95d7a2010-10-28 22:36:01 +01001779 struct sockaddr_in serv_addr, cli_addr;
Andy Green251f6fa2010-11-03 11:13:06 +00001780 int opt = 1;
Peter Hinz56885f32011-03-02 22:03:47 +00001781 struct libwebsocket_context *context = NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00001782 unsigned int slen;
Andy Green9659f372011-01-27 22:01:43 +00001783 char *p;
Andy Green2ac5a6f2011-01-28 10:00:18 +00001784 char hostname[1024];
Andy Green42f69142011-01-30 08:10:02 +00001785 struct hostent *he;
Andy Green0d338332011-02-12 11:57:43 +00001786 struct libwebsocket *wsi;
Andy Greenff95d7a2010-10-28 22:36:01 +01001787
Andy Green3faa9c72010-11-08 17:03:03 +00001788#ifdef LWS_OPENSSL_SUPPORT
Andy Greenf2f54d52010-11-15 22:08:00 +00001789 SSL_METHOD *method;
Andy Green3faa9c72010-11-08 17:03:03 +00001790 char ssl_err_buf[512];
Andy Green3faa9c72010-11-08 17:03:03 +00001791#endif
1792
Peter Hinz56885f32011-03-02 22:03:47 +00001793#ifdef _WIN32
1794 {
1795 WORD wVersionRequested;
1796 WSADATA wsaData;
1797 int err;
1798
1799 /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
1800 wVersionRequested = MAKEWORD(2, 2);
1801
1802 err = WSAStartup(wVersionRequested, &wsaData);
1803 if (err != 0) {
1804 /* Tell the user that we could not find a usable */
1805 /* Winsock DLL. */
1806 fprintf(stderr, "WSAStartup failed with error: %d\n",
1807 err);
1808 return NULL;
1809 }
1810 }
1811#endif
1812
1813
1814 context = malloc(sizeof(struct libwebsocket_context));
1815 if (!context) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001816 fprintf(stderr, "No memory for websocket context\n");
1817 return NULL;
1818 }
Peter Hinz56885f32011-03-02 22:03:47 +00001819 context->protocols = protocols;
1820 context->listen_port = port;
1821 context->http_proxy_port = 0;
1822 context->http_proxy_address[0] = '\0';
1823 context->options = options;
1824 context->fds_count = 0;
Andy Green9659f372011-01-27 22:01:43 +00001825
Peter Hinz56885f32011-03-02 22:03:47 +00001826#ifdef WIN32
1827 context->fd_random = 0;
1828#else
1829 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
1830 if (context->fd_random < 0) {
Andy Green44eee682011-02-10 09:32:24 +00001831 fprintf(stderr, "Unable to open random device %s %d\n",
Peter Hinz56885f32011-03-02 22:03:47 +00001832 SYSTEM_RANDOM_FILEPATH, context->fd_random);
Andy Green44eee682011-02-10 09:32:24 +00001833 return NULL;
1834 }
Peter Hinz56885f32011-03-02 22:03:47 +00001835#endif
Andy Green44eee682011-02-10 09:32:24 +00001836
Peter Hinz56885f32011-03-02 22:03:47 +00001837#ifdef LWS_OPENSSL_SUPPORT
1838 context->use_ssl = 0;
1839 context->ssl_ctx = NULL;
1840 context->ssl_client_ctx = NULL;
Andy Green2e24da02011-03-05 16:12:04 +00001841 openssl_websocket_private_data_index = 0;
Peter Hinz56885f32011-03-02 22:03:47 +00001842#endif
Andy Green2ac5a6f2011-01-28 10:00:18 +00001843 /* find canonical hostname */
1844
1845 hostname[(sizeof hostname) - 1] = '\0';
1846 gethostname(hostname, (sizeof hostname) - 1);
1847 he = gethostbyname(hostname);
Darin Willitsc19456f2011-02-14 17:52:39 +00001848 if (he) {
Peter Hinz56885f32011-03-02 22:03:47 +00001849 strncpy(context->canonical_hostname, he->h_name,
1850 sizeof context->canonical_hostname - 1);
1851 context->canonical_hostname[
1852 sizeof context->canonical_hostname - 1] = '\0';
Darin Willitsc19456f2011-02-14 17:52:39 +00001853 } else
Peter Hinz56885f32011-03-02 22:03:47 +00001854 strncpy(context->canonical_hostname, hostname,
1855 sizeof context->canonical_hostname - 1);
Andy Green2ac5a6f2011-01-28 10:00:18 +00001856
Andy Green9659f372011-01-27 22:01:43 +00001857 /* split the proxy ads:port if given */
1858
1859 p = getenv("http_proxy");
1860 if (p) {
Peter Hinz56885f32011-03-02 22:03:47 +00001861 strncpy(context->http_proxy_address, p,
1862 sizeof context->http_proxy_address - 1);
1863 context->http_proxy_address[
1864 sizeof context->http_proxy_address - 1] = '\0';
Andy Green9659f372011-01-27 22:01:43 +00001865
Peter Hinz56885f32011-03-02 22:03:47 +00001866 p = strchr(context->http_proxy_address, ':');
Andy Green9659f372011-01-27 22:01:43 +00001867 if (p == NULL) {
1868 fprintf(stderr, "http_proxy needs to be ads:port\n");
1869 return NULL;
1870 }
1871 *p = '\0';
Peter Hinz56885f32011-03-02 22:03:47 +00001872 context->http_proxy_port = atoi(p + 1);
Andy Green9659f372011-01-27 22:01:43 +00001873
1874 fprintf(stderr, "Using proxy %s:%u\n",
Peter Hinz56885f32011-03-02 22:03:47 +00001875 context->http_proxy_address,
1876 context->http_proxy_port);
Andy Green9659f372011-01-27 22:01:43 +00001877 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001878
1879 if (port) {
1880
Andy Green3faa9c72010-11-08 17:03:03 +00001881#ifdef LWS_OPENSSL_SUPPORT
Peter Hinz56885f32011-03-02 22:03:47 +00001882 context->use_ssl = ssl_cert_filepath != NULL &&
Andy Green90c7cbc2011-01-27 06:26:52 +00001883 ssl_private_key_filepath != NULL;
Peter Hinz56885f32011-03-02 22:03:47 +00001884 if (context->use_ssl)
Andy Green90c7cbc2011-01-27 06:26:52 +00001885 fprintf(stderr, " Compiled with SSL support, "
1886 "using it\n");
1887 else
1888 fprintf(stderr, " Compiled with SSL support, "
1889 "not using it\n");
Andy Green3faa9c72010-11-08 17:03:03 +00001890
Andy Green90c7cbc2011-01-27 06:26:52 +00001891#else
1892 if (ssl_cert_filepath != NULL &&
1893 ssl_private_key_filepath != NULL) {
1894 fprintf(stderr, " Not compiled for OpenSSl support!\n");
Andy Greene92cd172011-01-19 13:11:55 +00001895 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00001896 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001897 fprintf(stderr, " Compiled without SSL support, "
1898 "serving unencrypted\n");
1899#endif
1900 }
1901
1902 /* ignore SIGPIPE */
Peter Hinz56885f32011-03-02 22:03:47 +00001903#ifdef WIN32
1904#else
Andy Green90c7cbc2011-01-27 06:26:52 +00001905 signal(SIGPIPE, sigpipe_handler);
Peter Hinz56885f32011-03-02 22:03:47 +00001906#endif
Andy Green90c7cbc2011-01-27 06:26:52 +00001907
1908
1909#ifdef LWS_OPENSSL_SUPPORT
1910
1911 /* basic openssl init */
1912
1913 SSL_library_init();
1914
1915 OpenSSL_add_all_algorithms();
1916 SSL_load_error_strings();
1917
Andy Green2e24da02011-03-05 16:12:04 +00001918 openssl_websocket_private_data_index =
Andy Green6901cb32011-02-21 08:06:47 +00001919 SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);
1920
Andy Green90c7cbc2011-01-27 06:26:52 +00001921 /*
1922 * Firefox insists on SSLv23 not SSLv3
1923 * Konq disables SSLv2 by default now, SSLv23 works
1924 */
1925
1926 method = (SSL_METHOD *)SSLv23_server_method();
1927 if (!method) {
1928 fprintf(stderr, "problem creating ssl method: %s\n",
1929 ERR_error_string(ERR_get_error(), ssl_err_buf));
1930 return NULL;
1931 }
Peter Hinz56885f32011-03-02 22:03:47 +00001932 context->ssl_ctx = SSL_CTX_new(method); /* create context */
1933 if (!context->ssl_ctx) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001934 fprintf(stderr, "problem creating ssl context: %s\n",
1935 ERR_error_string(ERR_get_error(), ssl_err_buf));
1936 return NULL;
1937 }
1938
1939 /* client context */
Peter Hinz56885f32011-03-02 22:03:47 +00001940 if (port == CONTEXT_PORT_NO_LISTEN)
1941 {
1942 method = (SSL_METHOD *)SSLv23_client_method();
1943 if (!method) {
1944 fprintf(stderr, "problem creating ssl method: %s\n",
1945 ERR_error_string(ERR_get_error(), ssl_err_buf));
1946 return NULL;
1947 }
1948 /* create context */
1949 context->ssl_client_ctx = SSL_CTX_new(method);
1950 if (!context->ssl_client_ctx) {
1951 fprintf(stderr, "problem creating ssl context: %s\n",
1952 ERR_error_string(ERR_get_error(), ssl_err_buf));
1953 return NULL;
1954 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001955
Peter Hinz56885f32011-03-02 22:03:47 +00001956 /* openssl init for cert verification (for client sockets) */
Andy Green90c7cbc2011-01-27 06:26:52 +00001957
Peter Hinz56885f32011-03-02 22:03:47 +00001958 if (!SSL_CTX_load_verify_locations(
1959 context->ssl_client_ctx, NULL,
1960 LWS_OPENSSL_CLIENT_CERTS))
1961 fprintf(stderr,
1962 "Unable to load SSL Client certs from %s "
1963 "(set by --with-client-cert-dir= in configure) -- "
1964 " client ssl isn't going to work",
Andy Green90c7cbc2011-01-27 06:26:52 +00001965 LWS_OPENSSL_CLIENT_CERTS);
Peter Hinz56885f32011-03-02 22:03:47 +00001966
1967 /*
1968 * callback allowing user code to load extra verification certs
1969 * helping the client to verify server identity
1970 */
1971
1972 context->protocols[0].callback(context, NULL,
1973 LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
1974 context->ssl_client_ctx, NULL, 0);
Andy Green90c7cbc2011-01-27 06:26:52 +00001975 }
Andy Greenc6bf2c22011-02-20 11:10:47 +00001976 /* as a server, are we requiring clients to identify themselves? */
1977
1978 if (options & LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
1979
1980 /* absolutely require the client cert */
1981
Peter Hinz56885f32011-03-02 22:03:47 +00001982 SSL_CTX_set_verify(context->ssl_ctx,
Andy Green6901cb32011-02-21 08:06:47 +00001983 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1984 OpenSSL_verify_callback);
Andy Greenc6bf2c22011-02-20 11:10:47 +00001985
1986 /*
1987 * give user code a chance to load certs into the server
1988 * allowing it to verify incoming client certs
1989 */
1990
Peter Hinz56885f32011-03-02 22:03:47 +00001991 context->protocols[0].callback(context, NULL,
Andy Greenc6bf2c22011-02-20 11:10:47 +00001992 LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
Peter Hinz56885f32011-03-02 22:03:47 +00001993 context->ssl_ctx, NULL, 0);
Andy Greenc6bf2c22011-02-20 11:10:47 +00001994 }
1995
Peter Hinz56885f32011-03-02 22:03:47 +00001996 if (context->use_ssl) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001997
1998 /* openssl init for server sockets */
1999
Andy Green3faa9c72010-11-08 17:03:03 +00002000 /* set the local certificate from CertFile */
Peter Hinz56885f32011-03-02 22:03:47 +00002001 n = SSL_CTX_use_certificate_file(context->ssl_ctx,
Andy Green3faa9c72010-11-08 17:03:03 +00002002 ssl_cert_filepath, SSL_FILETYPE_PEM);
2003 if (n != 1) {
2004 fprintf(stderr, "problem getting cert '%s': %s\n",
2005 ssl_cert_filepath,
2006 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Greene92cd172011-01-19 13:11:55 +00002007 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002008 }
2009 /* set the private key from KeyFile */
Peter Hinz56885f32011-03-02 22:03:47 +00002010 if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx,
2011 ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) {
Andy Green018d8eb2010-11-08 21:04:23 +00002012 fprintf(stderr, "ssl problem getting key '%s': %s\n",
2013 ssl_private_key_filepath,
2014 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Greene92cd172011-01-19 13:11:55 +00002015 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002016 }
2017 /* verify private key */
Peter Hinz56885f32011-03-02 22:03:47 +00002018 if (!SSL_CTX_check_private_key(context->ssl_ctx)) {
Andy Green018d8eb2010-11-08 21:04:23 +00002019 fprintf(stderr, "Private SSL key doesn't match cert\n");
Andy Greene92cd172011-01-19 13:11:55 +00002020 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002021 }
2022
2023 /* SSL is happy and has a cert it's content with */
2024 }
2025#endif
Andy Greenb45993c2010-12-18 15:13:50 +00002026
Andy Greendf736162011-01-18 15:39:02 +00002027 /* selftest */
2028
2029 if (lws_b64_selftest())
Andy Greene92cd172011-01-19 13:11:55 +00002030 return NULL;
Andy Greendf736162011-01-18 15:39:02 +00002031
Andy Green0d338332011-02-12 11:57:43 +00002032 /* fd hashtable init */
2033
2034 for (n = 0; n < FD_HASHTABLE_MODULUS; n++)
Peter Hinz56885f32011-03-02 22:03:47 +00002035 context->fd_hashtable[n].length = 0;
Andy Green0d338332011-02-12 11:57:43 +00002036
Andy Greenb45993c2010-12-18 15:13:50 +00002037 /* set up our external listening socket we serve on */
Andy Green8f037e42010-12-19 22:13:26 +00002038
Andy Green4739e5c2011-01-22 12:51:57 +00002039 if (port) {
Andy Green8f037e42010-12-19 22:13:26 +00002040
Andy Green4739e5c2011-01-22 12:51:57 +00002041 sockfd = socket(AF_INET, SOCK_STREAM, 0);
2042 if (sockfd < 0) {
2043 fprintf(stderr, "ERROR opening socket");
2044 return NULL;
2045 }
Andy Green775c0dd2010-10-29 14:15:22 +01002046
Andy Green4739e5c2011-01-22 12:51:57 +00002047 /* allow us to restart even if old sockets in TIME_WAIT */
2048 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Andy Greene77ddd82010-11-13 10:03:47 +00002049
Andy Green4739e5c2011-01-22 12:51:57 +00002050 bzero((char *) &serv_addr, sizeof(serv_addr));
2051 serv_addr.sin_family = AF_INET;
Peter Hinz56885f32011-03-02 22:03:47 +00002052 if (interf == NULL)
Andy Green32375b72011-02-19 08:32:53 +00002053 serv_addr.sin_addr.s_addr = INADDR_ANY;
2054 else
Peter Hinz56885f32011-03-02 22:03:47 +00002055 interface_to_sa(interf, &serv_addr,
Andy Green32375b72011-02-19 08:32:53 +00002056 sizeof(serv_addr));
Andy Green4739e5c2011-01-22 12:51:57 +00002057 serv_addr.sin_port = htons(port);
2058
2059 n = bind(sockfd, (struct sockaddr *) &serv_addr,
2060 sizeof(serv_addr));
2061 if (n < 0) {
2062 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
Andy Green8f037e42010-12-19 22:13:26 +00002063 port, n, errno);
Andy Green4739e5c2011-01-22 12:51:57 +00002064 return NULL;
2065 }
Andy Green0d338332011-02-12 11:57:43 +00002066
2067 wsi = malloc(sizeof(struct libwebsocket));
2068 memset(wsi, 0, sizeof (struct libwebsocket));
2069 wsi->sock = sockfd;
2070 wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
Peter Hinz56885f32011-03-02 22:03:47 +00002071 insert_wsi(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00002072
2073 listen(sockfd, 5);
2074 fprintf(stderr, " Listening on port %d\n", port);
2075
2076 /* list in the internal poll array */
2077
Peter Hinz56885f32011-03-02 22:03:47 +00002078 context->fds[context->fds_count].fd = sockfd;
2079 context->fds[context->fds_count++].events = POLLIN;
Andy Green3221f922011-02-12 13:14:11 +00002080
2081 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00002082 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00002083 LWS_CALLBACK_ADD_POLL_FD,
2084 (void *)(long)sockfd, NULL, POLLIN);
2085
Andy Green8f037e42010-12-19 22:13:26 +00002086 }
Andy Greenb45993c2010-12-18 15:13:50 +00002087
Andy Greene77ddd82010-11-13 10:03:47 +00002088 /* drop any root privs for this process */
Peter Hinz56885f32011-03-02 22:03:47 +00002089#ifdef WIN32
2090#else
Andy Green3faa9c72010-11-08 17:03:03 +00002091 if (gid != -1)
2092 if (setgid(gid))
2093 fprintf(stderr, "setgid: %s\n", strerror(errno));
2094 if (uid != -1)
2095 if (setuid(uid))
2096 fprintf(stderr, "setuid: %s\n", strerror(errno));
Peter Hinz56885f32011-03-02 22:03:47 +00002097#endif
Andy Greenb45993c2010-12-18 15:13:50 +00002098
2099 /* set up our internal broadcast trigger sockets per-protocol */
2100
Peter Hinz56885f32011-03-02 22:03:47 +00002101 for (context->count_protocols = 0;
2102 protocols[context->count_protocols].callback;
2103 context->count_protocols++) {
2104 protocols[context->count_protocols].owning_server = context;
2105 protocols[context->count_protocols].protocol_index =
2106 context->count_protocols;
Andy Greenb45993c2010-12-18 15:13:50 +00002107
2108 fd = socket(AF_INET, SOCK_STREAM, 0);
2109 if (fd < 0) {
2110 fprintf(stderr, "ERROR opening socket");
Andy Greene92cd172011-01-19 13:11:55 +00002111 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002112 }
Andy Green8f037e42010-12-19 22:13:26 +00002113
Andy Greenb45993c2010-12-18 15:13:50 +00002114 /* allow us to restart even if old sockets in TIME_WAIT */
2115 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
2116
2117 bzero((char *) &serv_addr, sizeof(serv_addr));
2118 serv_addr.sin_family = AF_INET;
2119 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2120 serv_addr.sin_port = 0; /* pick the port for us */
2121
2122 n = bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
2123 if (n < 0) {
Andy Green8f037e42010-12-19 22:13:26 +00002124 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
Andy Greenb45993c2010-12-18 15:13:50 +00002125 port, n, errno);
Andy Greene92cd172011-01-19 13:11:55 +00002126 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002127 }
2128
2129 slen = sizeof cli_addr;
2130 n = getsockname(fd, (struct sockaddr *)&cli_addr, &slen);
2131 if (n < 0) {
2132 fprintf(stderr, "getsockname failed\n");
Andy Greene92cd172011-01-19 13:11:55 +00002133 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002134 }
Peter Hinz56885f32011-03-02 22:03:47 +00002135 protocols[context->count_protocols].broadcast_socket_port =
Andy Greenb45993c2010-12-18 15:13:50 +00002136 ntohs(cli_addr.sin_port);
2137 listen(fd, 5);
2138
2139 debug(" Protocol %s broadcast socket %d\n",
Peter Hinz56885f32011-03-02 22:03:47 +00002140 protocols[context->count_protocols].name,
Andy Greenb45993c2010-12-18 15:13:50 +00002141 ntohs(cli_addr.sin_port));
2142
Andy Green0d338332011-02-12 11:57:43 +00002143 /* dummy wsi per broadcast proxy socket */
2144
2145 wsi = malloc(sizeof(struct libwebsocket));
2146 memset(wsi, 0, sizeof (struct libwebsocket));
2147 wsi->sock = fd;
2148 wsi->mode = LWS_CONNMODE_BROADCAST_PROXY_LISTENER;
2149 /* note which protocol we are proxying */
Peter Hinz56885f32011-03-02 22:03:47 +00002150 wsi->protocol_index_for_broadcast_proxy =
2151 context->count_protocols;
2152 insert_wsi(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00002153
2154 /* list in internal poll array */
2155
Peter Hinz56885f32011-03-02 22:03:47 +00002156 context->fds[context->fds_count].fd = fd;
2157 context->fds[context->fds_count].events = POLLIN;
2158 context->fds[context->fds_count].revents = 0;
2159 context->fds_count++;
Andy Green3221f922011-02-12 13:14:11 +00002160
2161 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00002162 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00002163 LWS_CALLBACK_ADD_POLL_FD,
2164 (void *)(long)fd, NULL, POLLIN);
Andy Greenb45993c2010-12-18 15:13:50 +00002165 }
2166
Peter Hinz56885f32011-03-02 22:03:47 +00002167 return context;
Andy Greene92cd172011-01-19 13:11:55 +00002168}
Andy Greenb45993c2010-12-18 15:13:50 +00002169
Andy Green4739e5c2011-01-22 12:51:57 +00002170
Andy Greened11a022011-01-20 10:23:50 +00002171#ifndef LWS_NO_FORK
2172
Andy Greene92cd172011-01-19 13:11:55 +00002173/**
2174 * libwebsockets_fork_service_loop() - Optional helper function forks off
2175 * a process for the websocket server loop.
Andy Green6964bb52011-01-23 16:50:33 +00002176 * You don't have to use this but if not, you
2177 * have to make sure you are calling
2178 * libwebsocket_service periodically to service
2179 * the websocket traffic
Peter Hinz56885f32011-03-02 22:03:47 +00002180 * @context: server context returned by creation function
Andy Greene92cd172011-01-19 13:11:55 +00002181 */
Andy Greenb45993c2010-12-18 15:13:50 +00002182
Andy Greene92cd172011-01-19 13:11:55 +00002183int
Peter Hinz56885f32011-03-02 22:03:47 +00002184libwebsockets_fork_service_loop(struct libwebsocket_context *context)
Andy Greene92cd172011-01-19 13:11:55 +00002185{
Andy Greene92cd172011-01-19 13:11:55 +00002186 int fd;
2187 struct sockaddr_in cli_addr;
2188 int n;
Andy Green3221f922011-02-12 13:14:11 +00002189 int p;
Andy Greenb45993c2010-12-18 15:13:50 +00002190
Andy Greened11a022011-01-20 10:23:50 +00002191 n = fork();
2192 if (n < 0)
2193 return n;
2194
2195 if (!n) {
2196
2197 /* main process context */
2198
Andy Green3221f922011-02-12 13:14:11 +00002199 /*
2200 * set up the proxy sockets to allow broadcast from
2201 * service process context
2202 */
2203
Peter Hinz56885f32011-03-02 22:03:47 +00002204 for (p = 0; p < context->count_protocols; p++) {
Andy Greened11a022011-01-20 10:23:50 +00002205 fd = socket(AF_INET, SOCK_STREAM, 0);
2206 if (fd < 0) {
2207 fprintf(stderr, "Unable to create socket\n");
2208 return -1;
2209 }
2210 cli_addr.sin_family = AF_INET;
2211 cli_addr.sin_port = htons(
Peter Hinz56885f32011-03-02 22:03:47 +00002212 context->protocols[p].broadcast_socket_port);
Andy Greened11a022011-01-20 10:23:50 +00002213 cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2214 n = connect(fd, (struct sockaddr *)&cli_addr,
2215 sizeof cli_addr);
2216 if (n < 0) {
2217 fprintf(stderr, "Unable to connect to "
2218 "broadcast socket %d, %s\n",
Andy Green3221f922011-02-12 13:14:11 +00002219 n, strerror(errno));
Andy Greened11a022011-01-20 10:23:50 +00002220 return -1;
2221 }
2222
Peter Hinz56885f32011-03-02 22:03:47 +00002223 context->protocols[p].broadcast_socket_user_fd = fd;
Andy Greened11a022011-01-20 10:23:50 +00002224 }
2225
Andy Greene92cd172011-01-19 13:11:55 +00002226 return 0;
Andy Greenb45993c2010-12-18 15:13:50 +00002227 }
2228
2229 /* we want a SIGHUP when our parent goes down */
2230 prctl(PR_SET_PDEATHSIG, SIGHUP);
2231
2232 /* in this forked process, sit and service websocket connections */
Andy Green8f037e42010-12-19 22:13:26 +00002233
Andy Greene92cd172011-01-19 13:11:55 +00002234 while (1)
Peter Hinz56885f32011-03-02 22:03:47 +00002235 if (libwebsocket_service(context, 1000))
Andy Greene92cd172011-01-19 13:11:55 +00002236 return -1;
Andy Green8f037e42010-12-19 22:13:26 +00002237
Andy Green251f6fa2010-11-03 11:13:06 +00002238 return 0;
Andy Greenff95d7a2010-10-28 22:36:01 +01002239}
2240
Andy Greened11a022011-01-20 10:23:50 +00002241#endif
2242
Andy Greenb45993c2010-12-18 15:13:50 +00002243/**
2244 * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket
Andy Green8f037e42010-12-19 22:13:26 +00002245 * connection.
Andy Greenb45993c2010-12-18 15:13:50 +00002246 * @wsi: pointer to struct websocket you want to know the protocol of
2247 *
Andy Green8f037e42010-12-19 22:13:26 +00002248 *
2249 * This is useful to get the protocol to broadcast back to from inside
Andy Greenb45993c2010-12-18 15:13:50 +00002250 * the callback.
2251 */
Andy Greenab990e42010-10-31 12:42:52 +00002252
Andy Greenb45993c2010-12-18 15:13:50 +00002253const struct libwebsocket_protocols *
2254libwebsockets_get_protocol(struct libwebsocket *wsi)
2255{
2256 return wsi->protocol;
2257}
2258
2259/**
Andy Greene92cd172011-01-19 13:11:55 +00002260 * libwebsockets_broadcast() - Sends a buffer to the callback for all active
Andy Green8f037e42010-12-19 22:13:26 +00002261 * connections of the given protocol.
Andy Greenb45993c2010-12-18 15:13:50 +00002262 * @protocol: pointer to the protocol you will broadcast to all members of
2263 * @buf: buffer containing the data to be broadcase. NOTE: this has to be
Andy Green8f037e42010-12-19 22:13:26 +00002264 * allocated with LWS_SEND_BUFFER_PRE_PADDING valid bytes before
2265 * the pointer and LWS_SEND_BUFFER_POST_PADDING afterwards in the
2266 * case you are calling this function from callback context.
Andy Greenb45993c2010-12-18 15:13:50 +00002267 * @len: length of payload data in buf, starting from buf.
Andy Green8f037e42010-12-19 22:13:26 +00002268 *
2269 * This function allows bulk sending of a packet to every connection using
Andy Greenb45993c2010-12-18 15:13:50 +00002270 * the given protocol. It does not send the data directly; instead it calls
2271 * the callback with a reason type of LWS_CALLBACK_BROADCAST. If the callback
2272 * wants to actually send the data for that connection, the callback itself
2273 * should call libwebsocket_write().
2274 *
2275 * libwebsockets_broadcast() can be called from another fork context without
2276 * having to take any care about data visibility between the processes, it'll
2277 * "just work".
2278 */
2279
2280
2281int
Andy Green8f037e42010-12-19 22:13:26 +00002282libwebsockets_broadcast(const struct libwebsocket_protocols *protocol,
Andy Greenb45993c2010-12-18 15:13:50 +00002283 unsigned char *buf, size_t len)
2284{
Peter Hinz56885f32011-03-02 22:03:47 +00002285 struct libwebsocket_context *context = protocol->owning_server;
Andy Greenb45993c2010-12-18 15:13:50 +00002286 int n;
Andy Green0d338332011-02-12 11:57:43 +00002287 int m;
2288 struct libwebsocket * wsi;
Andy Greenb45993c2010-12-18 15:13:50 +00002289
2290 if (!protocol->broadcast_socket_user_fd) {
2291 /*
Andy Greene92cd172011-01-19 13:11:55 +00002292 * We are either running unforked / flat, or we are being
2293 * called from poll thread context
Andy Greenb45993c2010-12-18 15:13:50 +00002294 * eg, from a callback. In that case don't use sockets for
2295 * broadcast IPC (since we can't open a socket connection to
2296 * a socket listening on our own thread) but directly do the
2297 * send action.
2298 *
2299 * Locking is not needed because we are by definition being
2300 * called in the poll thread context and are serialized.
2301 */
2302
Andy Green0d338332011-02-12 11:57:43 +00002303 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
Andy Greenb45993c2010-12-18 15:13:50 +00002304
Peter Hinz56885f32011-03-02 22:03:47 +00002305 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Greenb45993c2010-12-18 15:13:50 +00002306
Peter Hinz56885f32011-03-02 22:03:47 +00002307 wsi = context->fd_hashtable[n].wsi[m];
Andy Greenb45993c2010-12-18 15:13:50 +00002308
Andy Green0d338332011-02-12 11:57:43 +00002309 if (wsi->mode != LWS_CONNMODE_WS_SERVING)
2310 continue;
Andy Greenb45993c2010-12-18 15:13:50 +00002311
Andy Green0d338332011-02-12 11:57:43 +00002312 /*
2313 * never broadcast to
2314 * non-established connections
2315 */
2316 if (wsi->state != WSI_STATE_ESTABLISHED)
2317 continue;
2318
2319 /* only broadcast to guys using
2320 * requested protocol
2321 */
2322 if (wsi->protocol != protocol)
2323 continue;
2324
Peter Hinz56885f32011-03-02 22:03:47 +00002325 wsi->protocol->callback(context, wsi,
Andy Green8f037e42010-12-19 22:13:26 +00002326 LWS_CALLBACK_BROADCAST,
Andy Green0d338332011-02-12 11:57:43 +00002327 wsi->user_space,
Andy Greenb45993c2010-12-18 15:13:50 +00002328 buf, len);
Andy Green0d338332011-02-12 11:57:43 +00002329 }
Andy Greenb45993c2010-12-18 15:13:50 +00002330 }
2331
2332 return 0;
2333 }
2334
Andy Green0ca6a172010-12-19 20:50:01 +00002335 /*
2336 * We're being called from a different process context than the server
2337 * loop. Instead of broadcasting directly, we send our
2338 * payload on a socket to do the IPC; the server process will serialize
2339 * the broadcast action in its main poll() loop.
2340 *
2341 * There's one broadcast socket listening for each protocol supported
2342 * set up when the websocket server initializes
2343 */
2344
Andy Green6964bb52011-01-23 16:50:33 +00002345 n = send(protocol->broadcast_socket_user_fd, buf, len, MSG_NOSIGNAL);
Andy Greenb45993c2010-12-18 15:13:50 +00002346
2347 return n;
2348}