blob: c59bbdd90facbfc43261c4cec83493f424ed8756 [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 Greend6e09112011-03-05 16:12:15 +0000519 new_wsi->count_active_extensions = 0;
Andy Greena71eafc2011-02-14 17:59:43 +0000520 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Green0d338332011-02-12 11:57:43 +0000521
522#ifdef LWS_OPENSSL_SUPPORT
523 new_wsi->ssl = NULL;
Andy Green0d338332011-02-12 11:57:43 +0000524
Peter Hinz56885f32011-03-02 22:03:47 +0000525 if (context->use_ssl) {
Andy Green0d338332011-02-12 11:57:43 +0000526
Peter Hinz56885f32011-03-02 22:03:47 +0000527 new_wsi->ssl = SSL_new(context->ssl_ctx);
Andy Green0d338332011-02-12 11:57:43 +0000528 if (new_wsi->ssl == NULL) {
529 fprintf(stderr, "SSL_new failed: %s\n",
530 ERR_error_string(SSL_get_error(
531 new_wsi->ssl, 0), NULL));
Andy Green1f9bf522011-02-14 21:14:37 +0000532 libwebsockets_decode_ssl_error();
Andy Green0d338332011-02-12 11:57:43 +0000533 free(new_wsi);
534 break;
535 }
536
537 SSL_set_fd(new_wsi->ssl, accept_fd);
538
539 n = SSL_accept(new_wsi->ssl);
540 if (n != 1) {
541 /*
542 * browsers seem to probe with various
543 * ssl params which fail then retry
544 * and succeed
545 */
546 debug("SSL_accept failed skt %u: %s\n",
547 pollfd->fd,
548 ERR_error_string(SSL_get_error(
549 new_wsi->ssl, n), NULL));
550 SSL_free(
551 new_wsi->ssl);
552 free(new_wsi);
553 break;
554 }
Andy Greenc6bf2c22011-02-20 11:10:47 +0000555
Andy Green0d338332011-02-12 11:57:43 +0000556 debug("accepted new SSL conn "
557 "port %u on fd=%d SSL ver %s\n",
558 ntohs(cli_addr.sin_port), accept_fd,
559 SSL_get_version(new_wsi->ssl));
560
561 } else
562#endif
563 debug("accepted new conn port %u on fd=%d\n",
564 ntohs(cli_addr.sin_port), accept_fd);
565
566 /* intialize the instance struct */
567
568 new_wsi->state = WSI_STATE_HTTP;
569 new_wsi->name_buffer_pos = 0;
570 new_wsi->mode = LWS_CONNMODE_WS_SERVING;
571
572 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
573 new_wsi->utf8_token[n].token = NULL;
574 new_wsi->utf8_token[n].token_len = 0;
575 }
576
577 /*
578 * these can only be set once the protocol is known
579 * we set an unestablished connection's protocol pointer
580 * to the start of the supported list, so it can look
581 * for matching ones during the handshake
582 */
Peter Hinz56885f32011-03-02 22:03:47 +0000583 new_wsi->protocol = context->protocols;
Andy Green0d338332011-02-12 11:57:43 +0000584 new_wsi->user_space = NULL;
585
586 /*
587 * Default protocol is 76 / 00
588 * After 76, there's a header specified to inform which
589 * draft the client wants, when that's seen we modify
590 * the individual connection's spec revision accordingly
591 */
592 new_wsi->ietf_spec_revision = 0;
593
Peter Hinz56885f32011-03-02 22:03:47 +0000594 insert_wsi(context, new_wsi);
Andy Green0d338332011-02-12 11:57:43 +0000595
Andy Green0d338332011-02-12 11:57:43 +0000596 /*
597 * make sure NO events are seen yet on this new socket
598 * (otherwise we inherit old fds[client].revents from
599 * previous socket there and die mysteriously! )
600 */
Peter Hinz56885f32011-03-02 22:03:47 +0000601 context->fds[context->fds_count].revents = 0;
Andy Green0d338332011-02-12 11:57:43 +0000602
Peter Hinz56885f32011-03-02 22:03:47 +0000603 context->fds[context->fds_count].events = POLLIN;
604 context->fds[context->fds_count++].fd = accept_fd;
Andy Green0d338332011-02-12 11:57:43 +0000605
Andy Green3221f922011-02-12 13:14:11 +0000606 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000607 context->protocols[0].callback(context, new_wsi,
Andy Green3221f922011-02-12 13:14:11 +0000608 LWS_CALLBACK_ADD_POLL_FD,
609 (void *)(long)accept_fd, NULL, POLLIN);
610
Andy Green0d338332011-02-12 11:57:43 +0000611 break;
612
613 case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
614
615 /* as we are listening, POLLIN means accept() is needed */
616
617 if (!pollfd->revents & POLLIN)
618 break;
619
620 /* listen socket got an unencrypted connection... */
621
622 clilen = sizeof(cli_addr);
623 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
624 &clilen);
625 if (accept_fd < 0) {
626 fprintf(stderr, "ERROR on accept");
627 break;
628 }
629
Peter Hinz56885f32011-03-02 22:03:47 +0000630 if (context->fds_count >= MAX_CLIENTS) {
Andy Green3221f922011-02-12 13:14:11 +0000631 fprintf(stderr, "too busy to accept new broadcast "
632 "proxy client\n");
Peter Hinz56885f32011-03-02 22:03:47 +0000633#ifdef WIN32
634 closesocket(accept_fd);
635#else
Andy Green0d338332011-02-12 11:57:43 +0000636 close(accept_fd);
Peter Hinz56885f32011-03-02 22:03:47 +0000637#endif
Andy Green0d338332011-02-12 11:57:43 +0000638 break;
639 }
640
641 /* create a dummy wsi for the connection and add it */
642
643 new_wsi = malloc(sizeof(struct libwebsocket));
644 memset(new_wsi, 0, sizeof (struct libwebsocket));
645 new_wsi->sock = accept_fd;
646 new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY;
647 new_wsi->state = WSI_STATE_ESTABLISHED;
Andy Greend6e09112011-03-05 16:12:15 +0000648 new_wsi->count_active_extensions = 0;
Andy Green0d338332011-02-12 11:57:43 +0000649 /* note which protocol we are proxying */
650 new_wsi->protocol_index_for_broadcast_proxy =
651 wsi->protocol_index_for_broadcast_proxy;
Peter Hinz56885f32011-03-02 22:03:47 +0000652 insert_wsi(context, new_wsi);
Andy Green0d338332011-02-12 11:57:43 +0000653
654 /* add connected socket to internal poll array */
655
Peter Hinz56885f32011-03-02 22:03:47 +0000656 context->fds[context->fds_count].revents = 0;
657 context->fds[context->fds_count].events = POLLIN;
658 context->fds[context->fds_count++].fd = accept_fd;
Andy Green0d338332011-02-12 11:57:43 +0000659
Andy Green3221f922011-02-12 13:14:11 +0000660 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000661 context->protocols[0].callback(context, new_wsi,
Andy Green3221f922011-02-12 13:14:11 +0000662 LWS_CALLBACK_ADD_POLL_FD,
663 (void *)(long)accept_fd, NULL, POLLIN);
664
Andy Green0d338332011-02-12 11:57:43 +0000665 break;
666
667 case LWS_CONNMODE_BROADCAST_PROXY:
Andy Green8f037e42010-12-19 22:13:26 +0000668
Andy Greenb45993c2010-12-18 15:13:50 +0000669 /* handle session socket closed */
Andy Green8f037e42010-12-19 22:13:26 +0000670
Andy Green0d338332011-02-12 11:57:43 +0000671 if (pollfd->revents & (POLLERR | POLLHUP)) {
Andy Green8f037e42010-12-19 22:13:26 +0000672
Andy Green0d338332011-02-12 11:57:43 +0000673 debug("Session Socket %p (fd=%d) dead\n",
Timothy J Fontaineb86d64e2011-02-14 17:55:27 +0000674 (void *)wsi, pollfd->fd);
Andy Greenb45993c2010-12-18 15:13:50 +0000675
Peter Hinz56885f32011-03-02 22:03:47 +0000676 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000677 LWS_CLOSE_STATUS_NORMAL);
Andy Green4b6fbe12011-02-14 08:03:48 +0000678 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +0000679 }
Andy Green8f037e42010-12-19 22:13:26 +0000680
Andy Green90c7cbc2011-01-27 06:26:52 +0000681 /* the guy requested a callback when it was OK to write */
682
Andy Green0d338332011-02-12 11:57:43 +0000683 if (pollfd->revents & POLLOUT) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000684
Andy Green0d338332011-02-12 11:57:43 +0000685 /* one shot */
Andy Green90c7cbc2011-01-27 06:26:52 +0000686
Andy Green0d338332011-02-12 11:57:43 +0000687 pollfd->events &= ~POLLOUT;
688
Andy Green3221f922011-02-12 13:14:11 +0000689 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +0000690 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +0000691 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
692 (void *)(long)wsi->sock, NULL, POLLOUT);
693
Peter Hinz56885f32011-03-02 22:03:47 +0000694 wsi->protocol->callback(context, wsi,
Andy Green90c7cbc2011-01-27 06:26:52 +0000695 LWS_CALLBACK_CLIENT_WRITEABLE,
Andy Green0d338332011-02-12 11:57:43 +0000696 wsi->user_space,
Andy Green90c7cbc2011-01-27 06:26:52 +0000697 NULL, 0);
698 }
699
Andy Greenb45993c2010-12-18 15:13:50 +0000700 /* any incoming data ready? */
701
Andy Green0d338332011-02-12 11:57:43 +0000702 if (!(pollfd->revents & POLLIN))
703 break;
Andy Greenb45993c2010-12-18 15:13:50 +0000704
Andy Green0d338332011-02-12 11:57:43 +0000705 /* get the issued broadcast payload from the socket */
Andy Greenb45993c2010-12-18 15:13:50 +0000706
Andy Green0d338332011-02-12 11:57:43 +0000707 len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING,
708 MAX_BROADCAST_PAYLOAD);
709 if (len < 0) {
710 fprintf(stderr, "Error reading broadcast payload\n");
Andy Green4b6fbe12011-02-14 08:03:48 +0000711 break;
Andy Green0d338332011-02-12 11:57:43 +0000712 }
Andy Greenb45993c2010-12-18 15:13:50 +0000713
Andy Green0d338332011-02-12 11:57:43 +0000714 /* broadcast it to all guys with this protocol index */
Andy Green8f037e42010-12-19 22:13:26 +0000715
Andy Green0d338332011-02-12 11:57:43 +0000716 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
Andy Green8f037e42010-12-19 22:13:26 +0000717
Peter Hinz56885f32011-03-02 22:03:47 +0000718 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Greenb45993c2010-12-18 15:13:50 +0000719
Peter Hinz56885f32011-03-02 22:03:47 +0000720 new_wsi = context->fd_hashtable[n].wsi[m];
Andy Greenb45993c2010-12-18 15:13:50 +0000721
Andy Green0d338332011-02-12 11:57:43 +0000722 /* only to clients we are serving to */
Andy Greenb45993c2010-12-18 15:13:50 +0000723
Andy Green0d338332011-02-12 11:57:43 +0000724 if (new_wsi->mode != LWS_CONNMODE_WS_SERVING)
Andy Greenb45993c2010-12-18 15:13:50 +0000725 continue;
726
727 /*
728 * never broadcast to non-established
729 * connection
730 */
731
Andy Green0d338332011-02-12 11:57:43 +0000732 if (new_wsi->state != WSI_STATE_ESTABLISHED)
Andy Green4739e5c2011-01-22 12:51:57 +0000733 continue;
734
Andy Greenb45993c2010-12-18 15:13:50 +0000735 /*
736 * only broadcast to connections using
737 * the requested protocol
738 */
739
Andy Green0d338332011-02-12 11:57:43 +0000740 if (new_wsi->protocol->protocol_index !=
741 wsi->protocol_index_for_broadcast_proxy)
Andy Greenb45993c2010-12-18 15:13:50 +0000742 continue;
743
Andy Green8f037e42010-12-19 22:13:26 +0000744 /* broadcast it to this connection */
745
Peter Hinz56885f32011-03-02 22:03:47 +0000746 new_wsi->protocol->callback(context, new_wsi,
Andy Green8f037e42010-12-19 22:13:26 +0000747 LWS_CALLBACK_BROADCAST,
Andy Green0d338332011-02-12 11:57:43 +0000748 new_wsi->user_space,
Andy Green0ca6a172010-12-19 20:50:01 +0000749 buf + LWS_SEND_BUFFER_PRE_PADDING, len);
Andy Greenb45993c2010-12-18 15:13:50 +0000750 }
Andy Green0d338332011-02-12 11:57:43 +0000751 }
752 break;
Andy Greenb45993c2010-12-18 15:13:50 +0000753
Andy Greenbe93fef2011-02-14 20:25:43 +0000754 case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
755
756 /* handle proxy hung up on us */
757
758 if (pollfd->revents & (POLLERR | POLLHUP)) {
759
760 fprintf(stderr, "Proxy connection %p (fd=%d) dead\n",
761 (void *)wsi, pollfd->fd);
762
Peter Hinz56885f32011-03-02 22:03:47 +0000763 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000764 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000765 return 1;
766 }
767
768 n = recv(wsi->sock, pkt, sizeof pkt, 0);
769 if (n < 0) {
Peter Hinz56885f32011-03-02 22:03:47 +0000770 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000771 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000772 fprintf(stderr, "ERROR reading from proxy socket\n");
773 return 1;
774 }
775
776 pkt[13] = '\0';
777 if (strcmp(pkt, "HTTP/1.0 200 ") != 0) {
Peter Hinz56885f32011-03-02 22:03:47 +0000778 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000779 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000780 fprintf(stderr, "ERROR from proxy: %s\n", pkt);
781 return 1;
782 }
783
784 /* clear his proxy connection timeout */
785
786 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
787
788 /* fallthru */
789
790 case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
791
792 #ifdef LWS_OPENSSL_SUPPORT
793 if (wsi->use_ssl) {
794
Peter Hinz56885f32011-03-02 22:03:47 +0000795 wsi->ssl = SSL_new(context->ssl_client_ctx);
796 wsi->client_bio = BIO_new_socket(wsi->sock,
797 BIO_NOCLOSE);
Andy Greenbe93fef2011-02-14 20:25:43 +0000798 SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
799
Andy Green6901cb32011-02-21 08:06:47 +0000800 SSL_set_ex_data(wsi->ssl,
Andy Green2e24da02011-03-05 16:12:04 +0000801 openssl_websocket_private_data_index,
Peter Hinz56885f32011-03-02 22:03:47 +0000802 context);
Andy Green6901cb32011-02-21 08:06:47 +0000803
Andy Greenbe93fef2011-02-14 20:25:43 +0000804 if (SSL_connect(wsi->ssl) <= 0) {
805 fprintf(stderr, "SSL connect error %s\n",
Andy Green687b0182011-02-26 11:04:01 +0000806 ERR_error_string(ERR_get_error(),
807 ssl_err_buf));
Peter Hinz56885f32011-03-02 22:03:47 +0000808 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000809 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000810 return 1;
811 }
812
813 n = SSL_get_verify_result(wsi->ssl);
Andy Green2e24da02011-03-05 16:12:04 +0000814 if ((n != X509_V_OK) && (
Andy Green687b0182011-02-26 11:04:01 +0000815 n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
816 wsi->use_ssl != 2)) {
Andy Greenbe93fef2011-02-14 20:25:43 +0000817
Andy Green687b0182011-02-26 11:04:01 +0000818 fprintf(stderr, "server's cert didn't "
819 "look good %d\n", n);
Peter Hinz56885f32011-03-02 22:03:47 +0000820 libwebsocket_close_and_free_session(context,
821 wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Green687b0182011-02-26 11:04:01 +0000822 return 1;
Andy Greenbe93fef2011-02-14 20:25:43 +0000823 }
824 } else {
825 wsi->ssl = NULL;
826 #endif
827
828
829 #ifdef LWS_OPENSSL_SUPPORT
830 }
831 #endif
832
833 /*
834 * create the random key
835 */
836
Peter Hinz56885f32011-03-02 22:03:47 +0000837 n = libwebsockets_get_random(context, hash, 16);
Andy Greenbe93fef2011-02-14 20:25:43 +0000838 if (n != 16) {
839 fprintf(stderr, "Unable to read from random dev %s\n",
840 SYSTEM_RANDOM_FILEPATH);
841 free(wsi->c_path);
842 free(wsi->c_host);
Andy Green08d33922011-02-26 10:22:49 +0000843 if (wsi->c_origin)
844 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000845 if (wsi->c_protocol)
846 free(wsi->c_protocol);
Peter Hinz56885f32011-03-02 22:03:47 +0000847 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +0000848 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +0000849 return 1;
850 }
851
852 lws_b64_encode_string(hash, 16, wsi->key_b64,
853 sizeof wsi->key_b64);
854
855 /*
Andy Greeneeaacb32011-03-01 20:44:24 +0000856 * 00 example client handshake
857 *
858 * GET /socket.io/websocket HTTP/1.1
859 * Upgrade: WebSocket
860 * Connection: Upgrade
861 * Host: 127.0.0.1:9999
862 * Origin: http://127.0.0.1
863 * Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^
864 * Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
865 * Cookie: socketio=websocket
866 *
867 * (Á®Ä0¶†≥
868 *
Andy Greenbe93fef2011-02-14 20:25:43 +0000869 * 04 example client handshake
870 *
871 * GET /chat HTTP/1.1
872 * Host: server.example.com
873 * Upgrade: websocket
874 * Connection: Upgrade
875 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
876 * Sec-WebSocket-Origin: http://example.com
877 * Sec-WebSocket-Protocol: chat, superchat
878 * Sec-WebSocket-Version: 4
879 */
880
Andy Green08d33922011-02-26 10:22:49 +0000881 p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", wsi->c_path);
Andy Greeneeaacb32011-03-01 20:44:24 +0000882
883 if (wsi->ietf_spec_revision == 0) {
884 unsigned char spaces_1, spaces_2;
885 unsigned int max_1, max_2;
886 unsigned int num_1, num_2;
887 unsigned long product_1, product_2;
888 char key_1[40];
889 char key_2[40];
890 unsigned int seed;
891 unsigned int count;
892 char challenge[16];
893
Peter Hinz56885f32011-03-02 22:03:47 +0000894 libwebsockets_get_random(context, &spaces_1,
895 sizeof(char));
896 libwebsockets_get_random(context, &spaces_2,
897 sizeof(char));
898
Andy Greeneeaacb32011-03-01 20:44:24 +0000899 spaces_1 = (spaces_1 % 12) + 1;
900 spaces_2 = (spaces_2 % 12) + 1;
Peter Hinz56885f32011-03-02 22:03:47 +0000901
Andy Greeneeaacb32011-03-01 20:44:24 +0000902 max_1 = 4294967295 / spaces_1;
903 max_2 = 4294967295 / spaces_2;
904
Peter Hinz56885f32011-03-02 22:03:47 +0000905 libwebsockets_get_random(context, &num_1, sizeof(int));
906 libwebsockets_get_random(context, &num_2, sizeof(int));
907
Andy Greeneeaacb32011-03-01 20:44:24 +0000908 num_1 = (num_1 % max_1);
909 num_2 = (num_2 % max_2);
Peter Hinz56885f32011-03-02 22:03:47 +0000910
Andy Greeneeaacb32011-03-01 20:44:24 +0000911 challenge[0] = num_1 >> 24;
912 challenge[1] = num_1 >> 16;
913 challenge[2] = num_1 >> 8;
914 challenge[3] = num_1;
915 challenge[4] = num_2 >> 24;
916 challenge[5] = num_2 >> 16;
917 challenge[6] = num_2 >> 8;
918 challenge[7] = num_2;
Peter Hinz56885f32011-03-02 22:03:47 +0000919
Andy Greeneeaacb32011-03-01 20:44:24 +0000920 product_1 = num_1 * spaces_1;
921 product_2 = num_2 * spaces_2;
Peter Hinz56885f32011-03-02 22:03:47 +0000922
Andy Greeneeaacb32011-03-01 20:44:24 +0000923 sprintf(key_1, "%lu", product_1);
924 sprintf(key_2, "%lu", product_2);
925
Peter Hinz56885f32011-03-02 22:03:47 +0000926 libwebsockets_get_random(context, &seed, sizeof(int));
927 libwebsockets_get_random(context, &count, sizeof(int));
928
Andy Greeneeaacb32011-03-01 20:44:24 +0000929 libwebsockets_00_spam(key_1, (count % 12) + 1, seed);
Peter Hinz56885f32011-03-02 22:03:47 +0000930
931 libwebsockets_get_random(context, &seed, sizeof(int));
932 libwebsockets_get_random(context, &count, sizeof(int));
933
Andy Greeneeaacb32011-03-01 20:44:24 +0000934 libwebsockets_00_spam(key_2, (count % 12) + 1, seed);
Peter Hinz56885f32011-03-02 22:03:47 +0000935
936 libwebsockets_get_random(context, &seed, sizeof(int));
937
Andy Greeneeaacb32011-03-01 20:44:24 +0000938 libwebsockets_00_spaceout(key_1, spaces_1, seed);
939 libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16);
Peter Hinz56885f32011-03-02 22:03:47 +0000940
Andy Greeneeaacb32011-03-01 20:44:24 +0000941 p += sprintf(p, "Upgrade: websocket\x0d\x0a"
942 "Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000943 wsi->c_host);
Andy Greeneeaacb32011-03-01 20:44:24 +0000944 if (wsi->c_origin)
945 p += sprintf(p, "Origin: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000946 wsi->c_origin);
947
Andy Greeneeaacb32011-03-01 20:44:24 +0000948 if (wsi->c_protocol)
Peter Hinz56885f32011-03-02 22:03:47 +0000949 p += sprintf(p, "Sec-WebSocket-Protocol: %s"
950 "\x0d\x0a", wsi->c_protocol);
951
Andy Greeneeaacb32011-03-01 20:44:24 +0000952 p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000953 key_1);
Andy Greeneeaacb32011-03-01 20:44:24 +0000954 p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000955 key_2);
Andy Greeneeaacb32011-03-01 20:44:24 +0000956
Andy Green385e7ad2011-03-01 21:06:02 +0000957 /* give userland a chance to append, eg, cookies */
Peter Hinz56885f32011-03-02 22:03:47 +0000958
959 context->protocols[0].callback(context, wsi,
960 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
Andy Green385e7ad2011-03-01 21:06:02 +0000961 NULL, &p, (pkt + sizeof(pkt)) - p - 12);
962
Andy Greeneeaacb32011-03-01 20:44:24 +0000963 p += sprintf(p, "\x0d\x0a");
Peter Hinz56885f32011-03-02 22:03:47 +0000964
965 read(context->fd_random, p, 8);
Andy Greeneeaacb32011-03-01 20:44:24 +0000966 memcpy(&challenge[8], p, 8);
967 p += 8;
Peter Hinz56885f32011-03-02 22:03:47 +0000968
Andy Greeneeaacb32011-03-01 20:44:24 +0000969 /* precompute what we want to see from the server */
Peter Hinz56885f32011-03-02 22:03:47 +0000970
Andy Greeneeaacb32011-03-01 20:44:24 +0000971 MD5((unsigned char *)challenge, 16,
972 (unsigned char *)wsi->initial_handshake_hash_base64);
Peter Hinz56885f32011-03-02 22:03:47 +0000973
Andy Greeneeaacb32011-03-01 20:44:24 +0000974 goto issue_hdr;
975 }
976
Andy Green08d33922011-02-26 10:22:49 +0000977 p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host);
978 p += sprintf(p, "Upgrade: websocket\x0d\x0a");
979 p += sprintf(p, "Connection: Upgrade\x0d\x0a"
Andy Greenbe93fef2011-02-14 20:25:43 +0000980 "Sec-WebSocket-Key: ");
Andy Green08d33922011-02-26 10:22:49 +0000981 strcpy(p, wsi->key_b64);
982 p += strlen(wsi->key_b64);
983 p += sprintf(p, "\x0d\x0a");
984 if (wsi->c_origin)
985 p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a",
Andy Greenbe93fef2011-02-14 20:25:43 +0000986 wsi->c_origin);
Andy Green08d33922011-02-26 10:22:49 +0000987 if (wsi->c_protocol)
Andy Greenbe93fef2011-02-14 20:25:43 +0000988 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
989 wsi->c_protocol);
Andy Green385e7ad2011-03-01 21:06:02 +0000990 p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
Peter Hinz56885f32011-03-02 22:03:47 +0000991 wsi->ietf_spec_revision);
Andy Green385e7ad2011-03-01 21:06:02 +0000992 /* give userland a chance to append, eg, cookies */
Peter Hinz56885f32011-03-02 22:03:47 +0000993
994 context->protocols[0].callback(context, wsi,
995 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
996 NULL, &p, (pkt + sizeof(pkt)) - p - 12);
997
Andy Green385e7ad2011-03-01 21:06:02 +0000998 p += sprintf(p, "\x0d\x0a");
999
Andy Greenbe93fef2011-02-14 20:25:43 +00001000 /* prepare the expected server accept response */
1001
1002 strcpy((char *)buf, wsi->key_b64);
1003 strcpy((char *)&buf[strlen((char *)buf)], magic_websocket_guid);
1004
1005 SHA1(buf, strlen((char *)buf), (unsigned char *)hash);
1006
1007 lws_b64_encode_string(hash, 20,
1008 wsi->initial_handshake_hash_base64,
1009 sizeof wsi->initial_handshake_hash_base64);
Peter Hinz56885f32011-03-02 22:03:47 +00001010
Andy Greeneeaacb32011-03-01 20:44:24 +00001011issue_hdr:
Peter Hinz56885f32011-03-02 22:03:47 +00001012
Andy Greeneeaacb32011-03-01 20:44:24 +00001013 /* done with these now */
Peter Hinz56885f32011-03-02 22:03:47 +00001014
Andy Greeneeaacb32011-03-01 20:44:24 +00001015 free(wsi->c_path);
1016 free(wsi->c_host);
1017 if (wsi->c_origin)
1018 free(wsi->c_origin);
1019
Andy Greenbe93fef2011-02-14 20:25:43 +00001020 /* send our request to the server */
1021
1022 #ifdef LWS_OPENSSL_SUPPORT
1023 if (wsi->use_ssl)
1024 n = SSL_write(wsi->ssl, pkt, p - pkt);
1025 else
1026 #endif
1027 n = send(wsi->sock, pkt, p - pkt, 0);
1028
1029 if (n < 0) {
1030 fprintf(stderr, "ERROR writing to client socket\n");
Peter Hinz56885f32011-03-02 22:03:47 +00001031 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001032 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +00001033 return 1;
1034 }
1035
1036 wsi->parser_state = WSI_TOKEN_NAME_PART;
1037 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY;
1038 libwebsocket_set_timeout(wsi,
1039 PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, 5);
1040
1041 break;
1042
1043 case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
1044
1045 /* handle server hung up on us */
1046
1047 if (pollfd->revents & (POLLERR | POLLHUP)) {
1048
1049 fprintf(stderr, "Server connection %p (fd=%d) dead\n",
1050 (void *)wsi, pollfd->fd);
1051
1052 goto bail3;
1053 }
1054
1055
1056 /* interpret the server response */
1057
1058 /*
1059 * HTTP/1.1 101 Switching Protocols
1060 * Upgrade: websocket
1061 * Connection: Upgrade
1062 * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
1063 * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
1064 * Sec-WebSocket-Protocol: chat
1065 */
1066
1067 #ifdef LWS_OPENSSL_SUPPORT
1068 if (wsi->use_ssl)
1069 len = SSL_read(wsi->ssl, pkt, sizeof pkt);
1070 else
1071 #endif
1072 len = recv(wsi->sock, pkt, sizeof pkt, 0);
1073
1074 if (len < 0) {
1075 fprintf(stderr,
1076 "libwebsocket_client_handshake read error\n");
1077 goto bail3;
1078 }
1079
1080 p = pkt;
1081 for (n = 0; n < len; n++)
1082 libwebsocket_parse(wsi, *p++);
1083
1084 if (wsi->parser_state != WSI_PARSING_COMPLETE) {
1085 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001086 "server response failed parsing\n");
Andy Greenbe93fef2011-02-14 20:25:43 +00001087 goto bail3;
1088 }
1089
1090 /*
Andy Greeneeaacb32011-03-01 20:44:24 +00001091 * 00 / 76 -->
1092 *
1093 * HTTP/1.1 101 WebSocket Protocol Handshake
1094 * Upgrade: WebSocket
1095 * Connection: Upgrade
1096 * Sec-WebSocket-Origin: http://127.0.0.1
1097 * Sec-WebSocket-Location: ws://127.0.0.1:9999/socket.io/websocket
1098 *
1099 * xxxxxxxxxxxxxxxx
1100 */
Peter Hinz56885f32011-03-02 22:03:47 +00001101
Andy Greeneeaacb32011-03-01 20:44:24 +00001102 if (wsi->ietf_spec_revision == 0) {
1103 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
Peter Hinz56885f32011-03-02 22:03:47 +00001104 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
1105 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
1106 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
1107 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
1108 wsi->c_protocol != NULL)) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001109 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001110 "missing required header(s)\n");
Andy Greeneeaacb32011-03-01 20:44:24 +00001111 pkt[len] = '\0';
1112 fprintf(stderr, "%s", pkt);
1113 goto bail3;
1114 }
Andy Greeneeaacb32011-03-01 20:44:24 +00001115
Peter Hinz56885f32011-03-02 22:03:47 +00001116 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
1117 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
1118 "101 websocket protocol handshake")) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001119 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001120 "server sent bad HTTP response '%s'\n",
1121 wsi->utf8_token[WSI_TOKEN_HTTP].token);
1122 goto bail3;
1123 }
1124
1125 if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len <
1126 16) {
1127 fprintf(stderr, "libwebsocket_client_handshake "
1128 "challenge reply too short %d\n",
1129 wsi->utf8_token[
1130 WSI_TOKEN_CHALLENGE].token_len);
Andy Greeneeaacb32011-03-01 20:44:24 +00001131 pkt[len] = '\0';
1132 fprintf(stderr, "%s", pkt);
1133 goto bail3;
Peter Hinz56885f32011-03-02 22:03:47 +00001134
Andy Greeneeaacb32011-03-01 20:44:24 +00001135 }
Peter Hinz56885f32011-03-02 22:03:47 +00001136
Andy Greeneeaacb32011-03-01 20:44:24 +00001137 goto select_protocol;
1138 }
Peter Hinz56885f32011-03-02 22:03:47 +00001139
Andy Greeneeaacb32011-03-01 20:44:24 +00001140 /*
Andy Greenbe93fef2011-02-14 20:25:43 +00001141 * well, what the server sent looked reasonable for syntax.
1142 * Now let's confirm it sent all the necessary headers
1143 */
1144
1145 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
1146 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
1147 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
1148 !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len ||
Andy Green4eaa86b2011-02-26 11:17:48 +00001149 (!wsi->utf8_token[WSI_TOKEN_NONCE].token_len &&
1150 wsi->ietf_spec_revision == 4) ||
Andy Greenbe93fef2011-02-14 20:25:43 +00001151 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
1152 wsi->c_protocol != NULL)) {
1153 fprintf(stderr, "libwebsocket_client_handshake "
Andy Green687b0182011-02-26 11:04:01 +00001154 "missing required header(s)\n");
Andy Greenbe93fef2011-02-14 20:25:43 +00001155 pkt[len] = '\0';
1156 fprintf(stderr, "%s", pkt);
1157 goto bail3;
1158 }
1159
1160 /*
1161 * Everything seems to be there, now take a closer look at what
1162 * is in each header
1163 */
1164
1165 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
1166 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
1167 "101 switching protocols")) {
1168 fprintf(stderr, "libwebsocket_client_handshake "
1169 "server sent bad HTTP response '%s'\n",
1170 wsi->utf8_token[WSI_TOKEN_HTTP].token);
1171 goto bail3;
1172 }
1173
1174 strtolower(wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
1175 if (strcmp(wsi->utf8_token[WSI_TOKEN_UPGRADE].token,
1176 "websocket")) {
1177 fprintf(stderr, "libwebsocket_client_handshake server "
1178 "sent bad Upgrade header '%s'\n",
1179 wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
1180 goto bail3;
1181 }
1182
1183 strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
1184 if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token,
1185 "upgrade")) {
1186 fprintf(stderr, "libwebsocket_client_handshake server "
1187 "sent bad Connection hdr '%s'\n",
1188 wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
1189 goto bail3;
1190 }
1191
Andy Greeneeaacb32011-03-01 20:44:24 +00001192select_protocol:
Andy Greenbe93fef2011-02-14 20:25:43 +00001193 pc = wsi->c_protocol;
1194
1195 /*
1196 * confirm the protocol the server wants to talk was in the list
1197 * of protocols we offered
1198 */
1199
1200 if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
1201
1202 /*
1203 * no protocol name to work from,
1204 * default to first protocol
1205 */
Peter Hinz56885f32011-03-02 22:03:47 +00001206 wsi->protocol = &context->protocols[0];
Andy Greenbe93fef2011-02-14 20:25:43 +00001207
1208 free(wsi->c_protocol);
1209
1210 goto check_accept;
1211 }
1212
1213 while (*pc && !okay) {
1214 if ((!strncmp(pc,
1215 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
1216 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len)) &&
1217 (pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == ',' ||
1218 pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == '\0')) {
1219 okay = 1;
1220 continue;
1221 }
1222 while (*pc && *pc != ',')
1223 pc++;
1224 while (*pc && *pc != ' ')
1225 pc++;
1226 }
1227
1228 /* done with him now */
1229
1230 if (wsi->c_protocol)
1231 free(wsi->c_protocol);
1232
1233
1234 if (!okay) {
1235 fprintf(stderr, "libwebsocket_client_handshake server "
1236 "sent bad protocol '%s'\n",
1237 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
1238 goto bail2;
1239 }
1240
1241 /*
1242 * identify the selected protocol struct and set it
1243 */
1244 n = 0;
1245 wsi->protocol = NULL;
Peter Hinz56885f32011-03-02 22:03:47 +00001246 while (context->protocols[n].callback) {
Andy Greenbe93fef2011-02-14 20:25:43 +00001247 if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
Peter Hinz56885f32011-03-02 22:03:47 +00001248 context->protocols[n].name) == 0)
1249 wsi->protocol = &context->protocols[n];
Andy Greenbe93fef2011-02-14 20:25:43 +00001250 n++;
1251 }
1252
1253 if (wsi->protocol == NULL) {
1254 fprintf(stderr, "libwebsocket_client_handshake server "
1255 "requested protocol '%s', which we "
1256 "said we supported but we don't!\n",
1257 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
1258 goto bail2;
1259 }
1260
1261 check_accept:
Andy Greeneeaacb32011-03-01 20:44:24 +00001262
1263 if (wsi->ietf_spec_revision == 0) {
Peter Hinz56885f32011-03-02 22:03:47 +00001264
Andy Greeneeaacb32011-03-01 20:44:24 +00001265 if (memcmp(wsi->initial_handshake_hash_base64,
Peter Hinz56885f32011-03-02 22:03:47 +00001266 wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) {
Andy Greeneeaacb32011-03-01 20:44:24 +00001267 fprintf(stderr, "libwebsocket_client_handshake "
Peter Hinz56885f32011-03-02 22:03:47 +00001268 "failed 00 challenge compare\n");
1269 pkt[len] = '\0';
1270 fprintf(stderr, "%s", pkt);
1271 goto bail2;
Andy Greeneeaacb32011-03-01 20:44:24 +00001272 }
Peter Hinz56885f32011-03-02 22:03:47 +00001273
Andy Greeneeaacb32011-03-01 20:44:24 +00001274 goto accept_ok;
1275 }
Peter Hinz56885f32011-03-02 22:03:47 +00001276
Andy Greenbe93fef2011-02-14 20:25:43 +00001277 /*
1278 * Confirm his accept token is the one we precomputed
1279 */
1280
1281 if (strcmp(wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
1282 wsi->initial_handshake_hash_base64)) {
1283 fprintf(stderr, "libwebsocket_client_handshake server "
1284 "sent bad ACCEPT '%s' vs computed '%s'\n",
1285 wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
1286 wsi->initial_handshake_hash_base64);
1287 goto bail2;
1288 }
1289
Andy Green4eaa86b2011-02-26 11:17:48 +00001290 if (wsi->ietf_spec_revision == 4) {
1291 /*
1292 * Calculate the 04 masking key to use when
1293 * sending data to server
1294 */
Andy Greenbe93fef2011-02-14 20:25:43 +00001295
Andy Green4eaa86b2011-02-26 11:17:48 +00001296 strcpy((char *)buf, wsi->key_b64);
1297 p = (char *)buf + strlen(wsi->key_b64);
1298 strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token);
1299 p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len;
1300 strcpy(p, magic_websocket_04_masking_guid);
1301 SHA1(buf, strlen((char *)buf), wsi->masking_key_04);
1302 }
Andy Greeneeaacb32011-03-01 20:44:24 +00001303accept_ok:
1304
Andy Greenbe93fef2011-02-14 20:25:43 +00001305 /* allocate the per-connection user memory (if any) */
1306
1307 if (wsi->protocol->per_session_data_size) {
1308 wsi->user_space = malloc(
1309 wsi->protocol->per_session_data_size);
1310 if (wsi->user_space == NULL) {
1311 fprintf(stderr, "Out of memory for "
1312 "conn user space\n");
1313 goto bail2;
1314 }
1315 } else
1316 wsi->user_space = NULL;
1317
1318 /* clear his proxy connection timeout */
1319
1320 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1321
1322 /* mark him as being alive */
1323
1324 wsi->state = WSI_STATE_ESTABLISHED;
1325 wsi->mode = LWS_CONNMODE_WS_CLIENT;
1326
1327 fprintf(stderr, "handshake OK for protocol %s\n",
1328 wsi->protocol->name);
1329
1330 /* call him back to inform him he is up */
1331
Peter Hinz56885f32011-03-02 22:03:47 +00001332 wsi->protocol->callback(context, wsi,
Andy Greenbe93fef2011-02-14 20:25:43 +00001333 LWS_CALLBACK_CLIENT_ESTABLISHED,
1334 wsi->user_space,
1335 NULL, 0);
1336
1337 break;
1338
1339bail3:
1340 if (wsi->c_protocol)
1341 free(wsi->c_protocol);
1342
1343bail2:
Peter Hinz56885f32011-03-02 22:03:47 +00001344 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001345 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenbe93fef2011-02-14 20:25:43 +00001346 return 1;
1347
1348
Andy Green0d338332011-02-12 11:57:43 +00001349 case LWS_CONNMODE_WS_SERVING:
1350 case LWS_CONNMODE_WS_CLIENT:
1351
1352 /* handle session socket closed */
1353
1354 if (pollfd->revents & (POLLERR | POLLHUP)) {
1355
Andy Green62c54d22011-02-14 09:14:25 +00001356 fprintf(stderr, "Session Socket %p (fd=%d) dead\n",
Andy Green0d338332011-02-12 11:57:43 +00001357 (void *)wsi, pollfd->fd);
1358
Peter Hinz56885f32011-03-02 22:03:47 +00001359 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001360 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green4b6fbe12011-02-14 08:03:48 +00001361 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001362 }
1363
Andy Green0d338332011-02-12 11:57:43 +00001364 /* the guy requested a callback when it was OK to write */
1365
1366 if (pollfd->revents & POLLOUT) {
1367
1368 pollfd->events &= ~POLLOUT;
1369
Andy Green3221f922011-02-12 13:14:11 +00001370 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001371 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001372 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
1373 (void *)(long)wsi->sock, NULL, POLLOUT);
1374
Peter Hinz56885f32011-03-02 22:03:47 +00001375 wsi->protocol->callback(context, wsi,
Andy Green0d338332011-02-12 11:57:43 +00001376 LWS_CALLBACK_CLIENT_WRITEABLE,
1377 wsi->user_space,
1378 NULL, 0);
1379 }
1380
1381 /* any incoming data ready? */
1382
1383 if (!(pollfd->revents & POLLIN))
1384 break;
1385
Andy Greenb45993c2010-12-18 15:13:50 +00001386#ifdef LWS_OPENSSL_SUPPORT
Andy Green0d338332011-02-12 11:57:43 +00001387 if (wsi->ssl)
1388 n = SSL_read(wsi->ssl, buf, sizeof buf);
Andy Greenb45993c2010-12-18 15:13:50 +00001389 else
1390#endif
Andy Green0d338332011-02-12 11:57:43 +00001391 n = recv(pollfd->fd, buf, sizeof buf, 0);
Andy Greenb45993c2010-12-18 15:13:50 +00001392
1393 if (n < 0) {
1394 fprintf(stderr, "Socket read returned %d\n", n);
Andy Green4b6fbe12011-02-14 08:03:48 +00001395 break;
Andy Greenb45993c2010-12-18 15:13:50 +00001396 }
1397 if (!n) {
Peter Hinz56885f32011-03-02 22:03:47 +00001398 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001399 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green4b6fbe12011-02-14 08:03:48 +00001400 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001401 }
1402
Andy Greenb45993c2010-12-18 15:13:50 +00001403 /* service incoming data */
1404
Peter Hinz56885f32011-03-02 22:03:47 +00001405 n = libwebsocket_read(context, wsi, buf, n);
Andy Green6964bb52011-01-23 16:50:33 +00001406 if (n >= 0)
Andy Green4b6fbe12011-02-14 08:03:48 +00001407 break;
Andy Greenb45993c2010-12-18 15:13:50 +00001408
Andy Green4b6fbe12011-02-14 08:03:48 +00001409 /* we closed wsi */
Andy Green0d338332011-02-12 11:57:43 +00001410
Andy Green4b6fbe12011-02-14 08:03:48 +00001411 return 1;
Andy Greenb45993c2010-12-18 15:13:50 +00001412 }
1413
1414 return 0;
1415}
1416
Andy Green0d338332011-02-12 11:57:43 +00001417
Andy Green6964bb52011-01-23 16:50:33 +00001418/**
1419 * libwebsocket_context_destroy() - Destroy the websocket context
Peter Hinz56885f32011-03-02 22:03:47 +00001420 * @context: Websocket context
Andy Green6964bb52011-01-23 16:50:33 +00001421 *
1422 * This function closes any active connections and then frees the
1423 * context. After calling this, any further use of the context is
1424 * undefined.
1425 */
1426void
Peter Hinz56885f32011-03-02 22:03:47 +00001427libwebsocket_context_destroy(struct libwebsocket_context *context)
Andy Green6964bb52011-01-23 16:50:33 +00001428{
Andy Green0d338332011-02-12 11:57:43 +00001429 int n;
1430 int m;
1431 struct libwebsocket *wsi;
Andy Green6964bb52011-01-23 16:50:33 +00001432
Andy Green4b6fbe12011-02-14 08:03:48 +00001433 for (n = 0; n < FD_HASHTABLE_MODULUS; n++)
Peter Hinz56885f32011-03-02 22:03:47 +00001434 for (m = 0; m < context->fd_hashtable[n].length; m++) {
1435 wsi = context->fd_hashtable[n].wsi[m];
1436 libwebsocket_close_and_free_session(context, wsi,
Andy Green687b0182011-02-26 11:04:01 +00001437 LWS_CLOSE_STATUS_GOINGAWAY);
Andy Greenf3d3b402011-02-09 07:16:34 +00001438 }
Andy Green6964bb52011-01-23 16:50:33 +00001439
Peter Hinz56885f32011-03-02 22:03:47 +00001440#ifdef WIN32
1441#else
1442 close(context->fd_random);
Andy Green6964bb52011-01-23 16:50:33 +00001443#endif
1444
Peter Hinz56885f32011-03-02 22:03:47 +00001445#ifdef LWS_OPENSSL_SUPPORT
1446 if (context->ssl_ctx)
1447 SSL_CTX_free(context->ssl_ctx);
1448 if (context->ssl_client_ctx)
1449 SSL_CTX_free(context->ssl_client_ctx);
1450#endif
1451
1452 free(context);
1453
1454#ifdef WIN32
1455 WSACleanup();
1456#endif
Andy Green6964bb52011-01-23 16:50:33 +00001457}
1458
1459/**
1460 * libwebsocket_service() - Service any pending websocket activity
Peter Hinz56885f32011-03-02 22:03:47 +00001461 * @context: Websocket context
Andy Green6964bb52011-01-23 16:50:33 +00001462 * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed
1463 * service otherwise block and service immediately, returning
1464 * after the timeout if nothing needed service.
1465 *
1466 * This function deals with any pending websocket traffic, for three
1467 * kinds of event. It handles these events on both server and client
1468 * types of connection the same.
1469 *
1470 * 1) Accept new connections to our context's server
1471 *
1472 * 2) Perform pending broadcast writes initiated from other forked
1473 * processes (effectively serializing asynchronous broadcasts)
1474 *
1475 * 3) Call the receive callback for incoming frame data received by
1476 * server or client connections.
1477 *
1478 * You need to call this service function periodically to all the above
1479 * functions to happen; if your application is single-threaded you can
1480 * just call it in your main event loop.
1481 *
1482 * Alternatively you can fork a new process that asynchronously handles
1483 * calling this service in a loop. In that case you are happy if this
1484 * call blocks your thread until it needs to take care of something and
1485 * would call it with a large nonzero timeout. Your loop then takes no
1486 * CPU while there is nothing happening.
1487 *
1488 * If you are calling it in a single-threaded app, you don't want it to
1489 * wait around blocking other things in your loop from happening, so you
1490 * would call it with a timeout_ms of 0, so it returns immediately if
1491 * nothing is pending, or as soon as it services whatever was pending.
1492 */
1493
Andy Greenb45993c2010-12-18 15:13:50 +00001494
Andy Greene92cd172011-01-19 13:11:55 +00001495int
Peter Hinz56885f32011-03-02 22:03:47 +00001496libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
Andy Greene92cd172011-01-19 13:11:55 +00001497{
1498 int n;
Andy Greene92cd172011-01-19 13:11:55 +00001499
1500 /* stay dead once we are dead */
1501
Peter Hinz56885f32011-03-02 22:03:47 +00001502 if (context == NULL)
Andy Greene92cd172011-01-19 13:11:55 +00001503 return 1;
1504
Andy Green0d338332011-02-12 11:57:43 +00001505 /* wait for something to need service */
Andy Green4739e5c2011-01-22 12:51:57 +00001506
Peter Hinz56885f32011-03-02 22:03:47 +00001507 n = poll(context->fds, context->fds_count, timeout_ms);
Andy Green3221f922011-02-12 13:14:11 +00001508 if (n == 0) /* poll timeout */
1509 return 0;
Andy Greene92cd172011-01-19 13:11:55 +00001510
Andy Green62c54d22011-02-14 09:14:25 +00001511 if (n < 0) {
Andy Green5e1fa172011-02-10 09:07:05 +00001512 /*
Andy Greene92cd172011-01-19 13:11:55 +00001513 fprintf(stderr, "Listen Socket dead\n");
Andy Green5e1fa172011-02-10 09:07:05 +00001514 */
Andy Green0d338332011-02-12 11:57:43 +00001515 return 1;
Andy Greene92cd172011-01-19 13:11:55 +00001516 }
Andy Greene92cd172011-01-19 13:11:55 +00001517
1518 /* handle accept on listening socket? */
1519
Peter Hinz56885f32011-03-02 22:03:47 +00001520 for (n = 0; n < context->fds_count; n++)
1521 if (context->fds[n].revents)
1522 libwebsocket_service_fd(context, &context->fds[n]);
Andy Greene92cd172011-01-19 13:11:55 +00001523
1524 return 0;
Andy Greene92cd172011-01-19 13:11:55 +00001525}
1526
Andy Green90c7cbc2011-01-27 06:26:52 +00001527/**
1528 * libwebsocket_callback_on_writable() - Request a callback when this socket
1529 * becomes able to be written to without
1530 * blocking
Andy Green32375b72011-02-19 08:32:53 +00001531 *
Peter Hinz56885f32011-03-02 22:03:47 +00001532 * @context: libwebsockets context
Andy Green90c7cbc2011-01-27 06:26:52 +00001533 * @wsi: Websocket connection instance to get callback for
1534 */
1535
1536int
Peter Hinz56885f32011-03-02 22:03:47 +00001537libwebsocket_callback_on_writable(struct libwebsocket_context *context,
Andy Green62c54d22011-02-14 09:14:25 +00001538 struct libwebsocket *wsi)
Andy Green90c7cbc2011-01-27 06:26:52 +00001539{
Andy Green90c7cbc2011-01-27 06:26:52 +00001540 int n;
1541
Peter Hinz56885f32011-03-02 22:03:47 +00001542 for (n = 0; n < context->fds_count; n++)
1543 if (context->fds[n].fd == wsi->sock) {
1544 context->fds[n].events |= POLLOUT;
1545 n = context->fds_count;
Andy Green90c7cbc2011-01-27 06:26:52 +00001546 }
1547
Andy Green3221f922011-02-12 13:14:11 +00001548 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001549 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001550 LWS_CALLBACK_SET_MODE_POLL_FD,
1551 (void *)(long)wsi->sock, NULL, POLLOUT);
1552
Andy Green90c7cbc2011-01-27 06:26:52 +00001553 return 1;
1554}
1555
1556/**
1557 * libwebsocket_callback_on_writable_all_protocol() - Request a callback for
1558 * all connections using the given protocol when it
1559 * becomes possible to write to each socket without
1560 * blocking in turn.
1561 *
1562 * @protocol: Protocol whose connections will get callbacks
1563 */
1564
1565int
1566libwebsocket_callback_on_writable_all_protocol(
1567 const struct libwebsocket_protocols *protocol)
1568{
Peter Hinz56885f32011-03-02 22:03:47 +00001569 struct libwebsocket_context *context = protocol->owning_server;
Andy Green90c7cbc2011-01-27 06:26:52 +00001570 int n;
Andy Green0d338332011-02-12 11:57:43 +00001571 int m;
1572 struct libwebsocket *wsi;
Andy Green90c7cbc2011-01-27 06:26:52 +00001573
Andy Green0d338332011-02-12 11:57:43 +00001574 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
1575
Peter Hinz56885f32011-03-02 22:03:47 +00001576 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Green0d338332011-02-12 11:57:43 +00001577
Peter Hinz56885f32011-03-02 22:03:47 +00001578 wsi = context->fd_hashtable[n].wsi[m];
Andy Green0d338332011-02-12 11:57:43 +00001579
1580 if (wsi->protocol == protocol)
Peter Hinz56885f32011-03-02 22:03:47 +00001581 libwebsocket_callback_on_writable(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00001582 }
1583 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001584
1585 return 0;
1586}
1587
Andy Greenbe93fef2011-02-14 20:25:43 +00001588/**
1589 * libwebsocket_set_timeout() - marks the wsi as subject to a timeout
1590 *
1591 * You will not need this unless you are doing something special
1592 *
1593 * @wsi: Websocket connection instance
1594 * @reason: timeout reason
1595 * @secs: how many seconds
1596 */
1597
1598void
1599libwebsocket_set_timeout(struct libwebsocket *wsi,
1600 enum pending_timeout reason, int secs)
1601{
1602 struct timeval tv;
1603
1604 gettimeofday(&tv, NULL);
1605
1606 wsi->pending_timeout_limit = tv.tv_sec + secs;
1607 wsi->pending_timeout = reason;
1608}
1609
Andy Greena6cbece2011-01-27 20:06:03 +00001610
1611/**
1612 * libwebsocket_get_socket_fd() - returns the socket file descriptor
1613 *
1614 * You will not need this unless you are doing something special
1615 *
1616 * @wsi: Websocket connection instance
1617 */
1618
1619int
1620libwebsocket_get_socket_fd(struct libwebsocket *wsi)
1621{
1622 return wsi->sock;
1623}
1624
Andy Green90c7cbc2011-01-27 06:26:52 +00001625/**
1626 * libwebsocket_rx_flow_control() - Enable and disable socket servicing for
1627 * receieved packets.
1628 *
1629 * If the output side of a server process becomes choked, this allows flow
1630 * control for the input side.
1631 *
1632 * @wsi: Websocket connection instance to get callback for
1633 * @enable: 0 = disable read servicing for this connection, 1 = enable
1634 */
1635
1636int
1637libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
1638{
Peter Hinz56885f32011-03-02 22:03:47 +00001639 struct libwebsocket_context *context = wsi->protocol->owning_server;
Andy Green90c7cbc2011-01-27 06:26:52 +00001640 int n;
1641
Peter Hinz56885f32011-03-02 22:03:47 +00001642 for (n = 0; n < context->fds_count; n++)
1643 if (context->fds[n].fd == wsi->sock) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001644 if (enable)
Peter Hinz56885f32011-03-02 22:03:47 +00001645 context->fds[n].events |= POLLIN;
Andy Green90c7cbc2011-01-27 06:26:52 +00001646 else
Peter Hinz56885f32011-03-02 22:03:47 +00001647 context->fds[n].events &= ~POLLIN;
Andy Green90c7cbc2011-01-27 06:26:52 +00001648
1649 return 0;
1650 }
1651
Andy Green3221f922011-02-12 13:14:11 +00001652 if (enable)
1653 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001654 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001655 LWS_CALLBACK_SET_MODE_POLL_FD,
1656 (void *)(long)wsi->sock, NULL, POLLIN);
1657 else
1658 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00001659 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00001660 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
1661 (void *)(long)wsi->sock, NULL, POLLIN);
1662
1663
Andy Green90c7cbc2011-01-27 06:26:52 +00001664 fprintf(stderr, "libwebsocket_callback_on_writable "
1665 "unable to find socket\n");
1666 return 1;
1667}
1668
Andy Green2ac5a6f2011-01-28 10:00:18 +00001669/**
1670 * libwebsocket_canonical_hostname() - returns this host's hostname
1671 *
1672 * This is typically used by client code to fill in the host parameter
1673 * when making a client connection. You can only call it after the context
1674 * has been created.
1675 *
Peter Hinz56885f32011-03-02 22:03:47 +00001676 * @context: Websocket context
Andy Green2ac5a6f2011-01-28 10:00:18 +00001677 */
1678
1679
1680extern const char *
Peter Hinz56885f32011-03-02 22:03:47 +00001681libwebsocket_canonical_hostname(struct libwebsocket_context *context)
Andy Green2ac5a6f2011-01-28 10:00:18 +00001682{
Peter Hinz56885f32011-03-02 22:03:47 +00001683 return (const char *)context->canonical_hostname;
Andy Green2ac5a6f2011-01-28 10:00:18 +00001684}
1685
1686
Andy Green90c7cbc2011-01-27 06:26:52 +00001687static void sigpipe_handler(int x)
1688{
1689}
1690
Andy Green6901cb32011-02-21 08:06:47 +00001691#ifdef LWS_OPENSSL_SUPPORT
1692static int
1693OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
1694{
1695
1696 SSL *ssl;
1697 int n;
Andy Green2e24da02011-03-05 16:12:04 +00001698 struct libwebsocket_context *context;
Andy Green6901cb32011-02-21 08:06:47 +00001699
1700 ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
1701 SSL_get_ex_data_X509_STORE_CTX_idx());
1702
1703 /*
Andy Green2e24da02011-03-05 16:12:04 +00001704 * !!! nasty openssl requires the index to come as a library-scope
1705 * static
Andy Green6901cb32011-02-21 08:06:47 +00001706 */
Andy Green2e24da02011-03-05 16:12:04 +00001707 context = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
Andy Green6901cb32011-02-21 08:06:47 +00001708
Peter Hinz56885f32011-03-02 22:03:47 +00001709 n = context->protocols[0].callback(NULL, NULL,
Andy Green6901cb32011-02-21 08:06:47 +00001710 LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
1711 x509_ctx, ssl, preverify_ok);
1712
1713 /* convert return code from 0 = OK to 1 = OK */
1714
1715 if (!n)
1716 n = 1;
1717 else
1718 n = 0;
1719
1720 return n;
1721}
1722#endif
1723
Andy Greenb45993c2010-12-18 15:13:50 +00001724
Andy Greenab990e42010-10-31 12:42:52 +00001725/**
Andy Green4739e5c2011-01-22 12:51:57 +00001726 * libwebsocket_create_context() - Create the websocket handler
1727 * @port: Port to listen on... you can use 0 to suppress listening on
Andy Green6964bb52011-01-23 16:50:33 +00001728 * any port, that's what you want if you are not running a
1729 * websocket server at all but just using it as a client
Peter Hinz56885f32011-03-02 22:03:47 +00001730 * @interf: NULL to bind the listen socket to all interfaces, or the
Andy Green32375b72011-02-19 08:32:53 +00001731 * interface name, eg, "eth2"
Andy Green4f3943a2010-11-12 10:44:16 +00001732 * @protocols: Array of structures listing supported protocols and a protocol-
Andy Green8f037e42010-12-19 22:13:26 +00001733 * specific callback for each one. The list is ended with an
1734 * entry that has a NULL callback pointer.
Andy Green6964bb52011-01-23 16:50:33 +00001735 * It's not const because we write the owning_server member
Andy Green3faa9c72010-11-08 17:03:03 +00001736 * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want
Andy Green8f037e42010-12-19 22:13:26 +00001737 * to listen using SSL, set to the filepath to fetch the
1738 * server cert from, otherwise NULL for unencrypted
Andy Green3faa9c72010-11-08 17:03:03 +00001739 * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
Andy Green8f037e42010-12-19 22:13:26 +00001740 * else ignored
Andy Green3faa9c72010-11-08 17:03:03 +00001741 * @gid: group id to change to after setting listen socket, or -1.
1742 * @uid: user id to change to after setting listen socket, or -1.
Andy Greenbfb051f2011-02-09 08:49:14 +00001743 * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK
Andy Green05464c62010-11-12 10:44:18 +00001744 *
Andy Green8f037e42010-12-19 22:13:26 +00001745 * This function creates the listening socket and takes care
1746 * of all initialization in one step.
1747 *
Andy Greene92cd172011-01-19 13:11:55 +00001748 * After initialization, it returns a struct libwebsocket_context * that
1749 * represents this server. After calling, user code needs to take care
1750 * of calling libwebsocket_service() with the context pointer to get the
1751 * server's sockets serviced. This can be done in the same process context
1752 * or a forked process, or another thread,
Andy Green05464c62010-11-12 10:44:18 +00001753 *
Andy Green8f037e42010-12-19 22:13:26 +00001754 * The protocol callback functions are called for a handful of events
1755 * including http requests coming in, websocket connections becoming
1756 * established, and data arriving; it's also called periodically to allow
1757 * async transmission.
1758 *
1759 * HTTP requests are sent always to the FIRST protocol in @protocol, since
1760 * at that time websocket protocol has not been negotiated. Other
1761 * protocols after the first one never see any HTTP callack activity.
1762 *
1763 * The server created is a simple http server by default; part of the
1764 * websocket standard is upgrading this http connection to a websocket one.
1765 *
1766 * This allows the same server to provide files like scripts and favicon /
1767 * images or whatever over http and dynamic data over websockets all in
1768 * one place; they're all handled in the user callback.
Andy Greenab990e42010-10-31 12:42:52 +00001769 */
Andy Green4ea60062010-10-30 12:15:07 +01001770
Andy Greene92cd172011-01-19 13:11:55 +00001771struct libwebsocket_context *
Peter Hinz56885f32011-03-02 22:03:47 +00001772libwebsocket_create_context(int port, const char *interf,
Andy Greenb45993c2010-12-18 15:13:50 +00001773 struct libwebsocket_protocols *protocols,
Andy Greend6e09112011-03-05 16:12:15 +00001774 struct libwebsocket_extension *extensions,
Andy Green8f037e42010-12-19 22:13:26 +00001775 const char *ssl_cert_filepath,
1776 const char *ssl_private_key_filepath,
Andy Green8014b292011-01-30 20:57:25 +00001777 int gid, int uid, unsigned int options)
Andy Greenff95d7a2010-10-28 22:36:01 +01001778{
1779 int n;
Andy Green4739e5c2011-01-22 12:51:57 +00001780 int sockfd = 0;
Andy Green251f6fa2010-11-03 11:13:06 +00001781 int fd;
Andy Greenff95d7a2010-10-28 22:36:01 +01001782 struct sockaddr_in serv_addr, cli_addr;
Andy Green251f6fa2010-11-03 11:13:06 +00001783 int opt = 1;
Peter Hinz56885f32011-03-02 22:03:47 +00001784 struct libwebsocket_context *context = NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00001785 unsigned int slen;
Andy Green9659f372011-01-27 22:01:43 +00001786 char *p;
Andy Green2ac5a6f2011-01-28 10:00:18 +00001787 char hostname[1024];
Andy Green42f69142011-01-30 08:10:02 +00001788 struct hostent *he;
Andy Green0d338332011-02-12 11:57:43 +00001789 struct libwebsocket *wsi;
Andy Greenff95d7a2010-10-28 22:36:01 +01001790
Andy Green3faa9c72010-11-08 17:03:03 +00001791#ifdef LWS_OPENSSL_SUPPORT
Andy Greenf2f54d52010-11-15 22:08:00 +00001792 SSL_METHOD *method;
Andy Green3faa9c72010-11-08 17:03:03 +00001793 char ssl_err_buf[512];
Andy Green3faa9c72010-11-08 17:03:03 +00001794#endif
1795
Peter Hinz56885f32011-03-02 22:03:47 +00001796#ifdef _WIN32
1797 {
1798 WORD wVersionRequested;
1799 WSADATA wsaData;
1800 int err;
1801
1802 /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
1803 wVersionRequested = MAKEWORD(2, 2);
1804
1805 err = WSAStartup(wVersionRequested, &wsaData);
1806 if (err != 0) {
1807 /* Tell the user that we could not find a usable */
1808 /* Winsock DLL. */
1809 fprintf(stderr, "WSAStartup failed with error: %d\n",
1810 err);
1811 return NULL;
1812 }
1813 }
1814#endif
1815
1816
1817 context = malloc(sizeof(struct libwebsocket_context));
1818 if (!context) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001819 fprintf(stderr, "No memory for websocket context\n");
1820 return NULL;
1821 }
Peter Hinz56885f32011-03-02 22:03:47 +00001822 context->protocols = protocols;
1823 context->listen_port = port;
1824 context->http_proxy_port = 0;
1825 context->http_proxy_address[0] = '\0';
1826 context->options = options;
1827 context->fds_count = 0;
Andy Greend6e09112011-03-05 16:12:15 +00001828 context->extensions = extensions;
Andy Green9659f372011-01-27 22:01:43 +00001829
Peter Hinz56885f32011-03-02 22:03:47 +00001830#ifdef WIN32
1831 context->fd_random = 0;
1832#else
1833 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
1834 if (context->fd_random < 0) {
Andy Green44eee682011-02-10 09:32:24 +00001835 fprintf(stderr, "Unable to open random device %s %d\n",
Peter Hinz56885f32011-03-02 22:03:47 +00001836 SYSTEM_RANDOM_FILEPATH, context->fd_random);
Andy Green44eee682011-02-10 09:32:24 +00001837 return NULL;
1838 }
Peter Hinz56885f32011-03-02 22:03:47 +00001839#endif
Andy Green44eee682011-02-10 09:32:24 +00001840
Peter Hinz56885f32011-03-02 22:03:47 +00001841#ifdef LWS_OPENSSL_SUPPORT
1842 context->use_ssl = 0;
1843 context->ssl_ctx = NULL;
1844 context->ssl_client_ctx = NULL;
Andy Green2e24da02011-03-05 16:12:04 +00001845 openssl_websocket_private_data_index = 0;
Peter Hinz56885f32011-03-02 22:03:47 +00001846#endif
Andy Green2ac5a6f2011-01-28 10:00:18 +00001847 /* find canonical hostname */
1848
1849 hostname[(sizeof hostname) - 1] = '\0';
1850 gethostname(hostname, (sizeof hostname) - 1);
1851 he = gethostbyname(hostname);
Darin Willitsc19456f2011-02-14 17:52:39 +00001852 if (he) {
Peter Hinz56885f32011-03-02 22:03:47 +00001853 strncpy(context->canonical_hostname, he->h_name,
1854 sizeof context->canonical_hostname - 1);
1855 context->canonical_hostname[
1856 sizeof context->canonical_hostname - 1] = '\0';
Darin Willitsc19456f2011-02-14 17:52:39 +00001857 } else
Peter Hinz56885f32011-03-02 22:03:47 +00001858 strncpy(context->canonical_hostname, hostname,
1859 sizeof context->canonical_hostname - 1);
Andy Green2ac5a6f2011-01-28 10:00:18 +00001860
Andy Green9659f372011-01-27 22:01:43 +00001861 /* split the proxy ads:port if given */
1862
1863 p = getenv("http_proxy");
1864 if (p) {
Peter Hinz56885f32011-03-02 22:03:47 +00001865 strncpy(context->http_proxy_address, p,
1866 sizeof context->http_proxy_address - 1);
1867 context->http_proxy_address[
1868 sizeof context->http_proxy_address - 1] = '\0';
Andy Green9659f372011-01-27 22:01:43 +00001869
Peter Hinz56885f32011-03-02 22:03:47 +00001870 p = strchr(context->http_proxy_address, ':');
Andy Green9659f372011-01-27 22:01:43 +00001871 if (p == NULL) {
1872 fprintf(stderr, "http_proxy needs to be ads:port\n");
1873 return NULL;
1874 }
1875 *p = '\0';
Peter Hinz56885f32011-03-02 22:03:47 +00001876 context->http_proxy_port = atoi(p + 1);
Andy Green9659f372011-01-27 22:01:43 +00001877
1878 fprintf(stderr, "Using proxy %s:%u\n",
Peter Hinz56885f32011-03-02 22:03:47 +00001879 context->http_proxy_address,
1880 context->http_proxy_port);
Andy Green9659f372011-01-27 22:01:43 +00001881 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001882
1883 if (port) {
1884
Andy Green3faa9c72010-11-08 17:03:03 +00001885#ifdef LWS_OPENSSL_SUPPORT
Peter Hinz56885f32011-03-02 22:03:47 +00001886 context->use_ssl = ssl_cert_filepath != NULL &&
Andy Green90c7cbc2011-01-27 06:26:52 +00001887 ssl_private_key_filepath != NULL;
Peter Hinz56885f32011-03-02 22:03:47 +00001888 if (context->use_ssl)
Andy Green90c7cbc2011-01-27 06:26:52 +00001889 fprintf(stderr, " Compiled with SSL support, "
1890 "using it\n");
1891 else
1892 fprintf(stderr, " Compiled with SSL support, "
1893 "not using it\n");
Andy Green3faa9c72010-11-08 17:03:03 +00001894
Andy Green90c7cbc2011-01-27 06:26:52 +00001895#else
1896 if (ssl_cert_filepath != NULL &&
1897 ssl_private_key_filepath != NULL) {
1898 fprintf(stderr, " Not compiled for OpenSSl support!\n");
Andy Greene92cd172011-01-19 13:11:55 +00001899 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00001900 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001901 fprintf(stderr, " Compiled without SSL support, "
1902 "serving unencrypted\n");
1903#endif
1904 }
1905
1906 /* ignore SIGPIPE */
Peter Hinz56885f32011-03-02 22:03:47 +00001907#ifdef WIN32
1908#else
Andy Green90c7cbc2011-01-27 06:26:52 +00001909 signal(SIGPIPE, sigpipe_handler);
Peter Hinz56885f32011-03-02 22:03:47 +00001910#endif
Andy Green90c7cbc2011-01-27 06:26:52 +00001911
1912
1913#ifdef LWS_OPENSSL_SUPPORT
1914
1915 /* basic openssl init */
1916
1917 SSL_library_init();
1918
1919 OpenSSL_add_all_algorithms();
1920 SSL_load_error_strings();
1921
Andy Green2e24da02011-03-05 16:12:04 +00001922 openssl_websocket_private_data_index =
Andy Green6901cb32011-02-21 08:06:47 +00001923 SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);
1924
Andy Green90c7cbc2011-01-27 06:26:52 +00001925 /*
1926 * Firefox insists on SSLv23 not SSLv3
1927 * Konq disables SSLv2 by default now, SSLv23 works
1928 */
1929
1930 method = (SSL_METHOD *)SSLv23_server_method();
1931 if (!method) {
1932 fprintf(stderr, "problem creating ssl method: %s\n",
1933 ERR_error_string(ERR_get_error(), ssl_err_buf));
1934 return NULL;
1935 }
Peter Hinz56885f32011-03-02 22:03:47 +00001936 context->ssl_ctx = SSL_CTX_new(method); /* create context */
1937 if (!context->ssl_ctx) {
Andy Green90c7cbc2011-01-27 06:26:52 +00001938 fprintf(stderr, "problem creating ssl context: %s\n",
1939 ERR_error_string(ERR_get_error(), ssl_err_buf));
1940 return NULL;
1941 }
1942
1943 /* client context */
Peter Hinz56885f32011-03-02 22:03:47 +00001944 if (port == CONTEXT_PORT_NO_LISTEN)
1945 {
1946 method = (SSL_METHOD *)SSLv23_client_method();
1947 if (!method) {
1948 fprintf(stderr, "problem creating ssl method: %s\n",
1949 ERR_error_string(ERR_get_error(), ssl_err_buf));
1950 return NULL;
1951 }
1952 /* create context */
1953 context->ssl_client_ctx = SSL_CTX_new(method);
1954 if (!context->ssl_client_ctx) {
1955 fprintf(stderr, "problem creating ssl context: %s\n",
1956 ERR_error_string(ERR_get_error(), ssl_err_buf));
1957 return NULL;
1958 }
Andy Green90c7cbc2011-01-27 06:26:52 +00001959
Peter Hinz56885f32011-03-02 22:03:47 +00001960 /* openssl init for cert verification (for client sockets) */
Andy Green90c7cbc2011-01-27 06:26:52 +00001961
Peter Hinz56885f32011-03-02 22:03:47 +00001962 if (!SSL_CTX_load_verify_locations(
1963 context->ssl_client_ctx, NULL,
1964 LWS_OPENSSL_CLIENT_CERTS))
1965 fprintf(stderr,
1966 "Unable to load SSL Client certs from %s "
1967 "(set by --with-client-cert-dir= in configure) -- "
1968 " client ssl isn't going to work",
Andy Green90c7cbc2011-01-27 06:26:52 +00001969 LWS_OPENSSL_CLIENT_CERTS);
Peter Hinz56885f32011-03-02 22:03:47 +00001970
1971 /*
1972 * callback allowing user code to load extra verification certs
1973 * helping the client to verify server identity
1974 */
1975
1976 context->protocols[0].callback(context, NULL,
1977 LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
1978 context->ssl_client_ctx, NULL, 0);
Andy Green90c7cbc2011-01-27 06:26:52 +00001979 }
Andy Greenc6bf2c22011-02-20 11:10:47 +00001980 /* as a server, are we requiring clients to identify themselves? */
1981
1982 if (options & LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
1983
1984 /* absolutely require the client cert */
1985
Peter Hinz56885f32011-03-02 22:03:47 +00001986 SSL_CTX_set_verify(context->ssl_ctx,
Andy Green6901cb32011-02-21 08:06:47 +00001987 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1988 OpenSSL_verify_callback);
Andy Greenc6bf2c22011-02-20 11:10:47 +00001989
1990 /*
1991 * give user code a chance to load certs into the server
1992 * allowing it to verify incoming client certs
1993 */
1994
Peter Hinz56885f32011-03-02 22:03:47 +00001995 context->protocols[0].callback(context, NULL,
Andy Greenc6bf2c22011-02-20 11:10:47 +00001996 LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
Peter Hinz56885f32011-03-02 22:03:47 +00001997 context->ssl_ctx, NULL, 0);
Andy Greenc6bf2c22011-02-20 11:10:47 +00001998 }
1999
Peter Hinz56885f32011-03-02 22:03:47 +00002000 if (context->use_ssl) {
Andy Green90c7cbc2011-01-27 06:26:52 +00002001
2002 /* openssl init for server sockets */
2003
Andy Green3faa9c72010-11-08 17:03:03 +00002004 /* set the local certificate from CertFile */
Peter Hinz56885f32011-03-02 22:03:47 +00002005 n = SSL_CTX_use_certificate_file(context->ssl_ctx,
Andy Green3faa9c72010-11-08 17:03:03 +00002006 ssl_cert_filepath, SSL_FILETYPE_PEM);
2007 if (n != 1) {
2008 fprintf(stderr, "problem getting cert '%s': %s\n",
2009 ssl_cert_filepath,
2010 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Greene92cd172011-01-19 13:11:55 +00002011 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002012 }
2013 /* set the private key from KeyFile */
Peter Hinz56885f32011-03-02 22:03:47 +00002014 if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx,
2015 ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) {
Andy Green018d8eb2010-11-08 21:04:23 +00002016 fprintf(stderr, "ssl problem getting key '%s': %s\n",
2017 ssl_private_key_filepath,
2018 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Greene92cd172011-01-19 13:11:55 +00002019 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002020 }
2021 /* verify private key */
Peter Hinz56885f32011-03-02 22:03:47 +00002022 if (!SSL_CTX_check_private_key(context->ssl_ctx)) {
Andy Green018d8eb2010-11-08 21:04:23 +00002023 fprintf(stderr, "Private SSL key doesn't match cert\n");
Andy Greene92cd172011-01-19 13:11:55 +00002024 return NULL;
Andy Green3faa9c72010-11-08 17:03:03 +00002025 }
2026
2027 /* SSL is happy and has a cert it's content with */
2028 }
2029#endif
Andy Greenb45993c2010-12-18 15:13:50 +00002030
Andy Greendf736162011-01-18 15:39:02 +00002031 /* selftest */
2032
2033 if (lws_b64_selftest())
Andy Greene92cd172011-01-19 13:11:55 +00002034 return NULL;
Andy Greendf736162011-01-18 15:39:02 +00002035
Andy Green0d338332011-02-12 11:57:43 +00002036 /* fd hashtable init */
2037
2038 for (n = 0; n < FD_HASHTABLE_MODULUS; n++)
Peter Hinz56885f32011-03-02 22:03:47 +00002039 context->fd_hashtable[n].length = 0;
Andy Green0d338332011-02-12 11:57:43 +00002040
Andy Greenb45993c2010-12-18 15:13:50 +00002041 /* set up our external listening socket we serve on */
Andy Green8f037e42010-12-19 22:13:26 +00002042
Andy Green4739e5c2011-01-22 12:51:57 +00002043 if (port) {
Andy Green8f037e42010-12-19 22:13:26 +00002044
Andy Green4739e5c2011-01-22 12:51:57 +00002045 sockfd = socket(AF_INET, SOCK_STREAM, 0);
2046 if (sockfd < 0) {
2047 fprintf(stderr, "ERROR opening socket");
2048 return NULL;
2049 }
Andy Green775c0dd2010-10-29 14:15:22 +01002050
Andy Green4739e5c2011-01-22 12:51:57 +00002051 /* allow us to restart even if old sockets in TIME_WAIT */
2052 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Andy Greene77ddd82010-11-13 10:03:47 +00002053
Andy Green4739e5c2011-01-22 12:51:57 +00002054 bzero((char *) &serv_addr, sizeof(serv_addr));
2055 serv_addr.sin_family = AF_INET;
Peter Hinz56885f32011-03-02 22:03:47 +00002056 if (interf == NULL)
Andy Green32375b72011-02-19 08:32:53 +00002057 serv_addr.sin_addr.s_addr = INADDR_ANY;
2058 else
Peter Hinz56885f32011-03-02 22:03:47 +00002059 interface_to_sa(interf, &serv_addr,
Andy Green32375b72011-02-19 08:32:53 +00002060 sizeof(serv_addr));
Andy Green4739e5c2011-01-22 12:51:57 +00002061 serv_addr.sin_port = htons(port);
2062
2063 n = bind(sockfd, (struct sockaddr *) &serv_addr,
2064 sizeof(serv_addr));
2065 if (n < 0) {
2066 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
Andy Green8f037e42010-12-19 22:13:26 +00002067 port, n, errno);
Andy Green4739e5c2011-01-22 12:51:57 +00002068 return NULL;
2069 }
Andy Green0d338332011-02-12 11:57:43 +00002070
2071 wsi = malloc(sizeof(struct libwebsocket));
2072 memset(wsi, 0, sizeof (struct libwebsocket));
2073 wsi->sock = sockfd;
Andy Greend6e09112011-03-05 16:12:15 +00002074 wsi->count_active_extensions = 0;
Andy Green0d338332011-02-12 11:57:43 +00002075 wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
Peter Hinz56885f32011-03-02 22:03:47 +00002076 insert_wsi(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00002077
2078 listen(sockfd, 5);
2079 fprintf(stderr, " Listening on port %d\n", port);
2080
2081 /* list in the internal poll array */
2082
Peter Hinz56885f32011-03-02 22:03:47 +00002083 context->fds[context->fds_count].fd = sockfd;
2084 context->fds[context->fds_count++].events = POLLIN;
Andy Green3221f922011-02-12 13:14:11 +00002085
2086 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00002087 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00002088 LWS_CALLBACK_ADD_POLL_FD,
2089 (void *)(long)sockfd, NULL, POLLIN);
2090
Andy Green8f037e42010-12-19 22:13:26 +00002091 }
Andy Greenb45993c2010-12-18 15:13:50 +00002092
Andy Greene77ddd82010-11-13 10:03:47 +00002093 /* drop any root privs for this process */
Peter Hinz56885f32011-03-02 22:03:47 +00002094#ifdef WIN32
2095#else
Andy Green3faa9c72010-11-08 17:03:03 +00002096 if (gid != -1)
2097 if (setgid(gid))
2098 fprintf(stderr, "setgid: %s\n", strerror(errno));
2099 if (uid != -1)
2100 if (setuid(uid))
2101 fprintf(stderr, "setuid: %s\n", strerror(errno));
Peter Hinz56885f32011-03-02 22:03:47 +00002102#endif
Andy Greenb45993c2010-12-18 15:13:50 +00002103
2104 /* set up our internal broadcast trigger sockets per-protocol */
2105
Peter Hinz56885f32011-03-02 22:03:47 +00002106 for (context->count_protocols = 0;
2107 protocols[context->count_protocols].callback;
2108 context->count_protocols++) {
2109 protocols[context->count_protocols].owning_server = context;
2110 protocols[context->count_protocols].protocol_index =
2111 context->count_protocols;
Andy Greenb45993c2010-12-18 15:13:50 +00002112
2113 fd = socket(AF_INET, SOCK_STREAM, 0);
2114 if (fd < 0) {
2115 fprintf(stderr, "ERROR opening socket");
Andy Greene92cd172011-01-19 13:11:55 +00002116 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002117 }
Andy Green8f037e42010-12-19 22:13:26 +00002118
Andy Greenb45993c2010-12-18 15:13:50 +00002119 /* allow us to restart even if old sockets in TIME_WAIT */
2120 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
2121
2122 bzero((char *) &serv_addr, sizeof(serv_addr));
2123 serv_addr.sin_family = AF_INET;
2124 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2125 serv_addr.sin_port = 0; /* pick the port for us */
2126
2127 n = bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
2128 if (n < 0) {
Andy Green8f037e42010-12-19 22:13:26 +00002129 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
Andy Greenb45993c2010-12-18 15:13:50 +00002130 port, n, errno);
Andy Greene92cd172011-01-19 13:11:55 +00002131 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002132 }
2133
2134 slen = sizeof cli_addr;
2135 n = getsockname(fd, (struct sockaddr *)&cli_addr, &slen);
2136 if (n < 0) {
2137 fprintf(stderr, "getsockname failed\n");
Andy Greene92cd172011-01-19 13:11:55 +00002138 return NULL;
Andy Greenb45993c2010-12-18 15:13:50 +00002139 }
Peter Hinz56885f32011-03-02 22:03:47 +00002140 protocols[context->count_protocols].broadcast_socket_port =
Andy Greenb45993c2010-12-18 15:13:50 +00002141 ntohs(cli_addr.sin_port);
2142 listen(fd, 5);
2143
2144 debug(" Protocol %s broadcast socket %d\n",
Peter Hinz56885f32011-03-02 22:03:47 +00002145 protocols[context->count_protocols].name,
Andy Greenb45993c2010-12-18 15:13:50 +00002146 ntohs(cli_addr.sin_port));
2147
Andy Green0d338332011-02-12 11:57:43 +00002148 /* dummy wsi per broadcast proxy socket */
2149
2150 wsi = malloc(sizeof(struct libwebsocket));
2151 memset(wsi, 0, sizeof (struct libwebsocket));
2152 wsi->sock = fd;
2153 wsi->mode = LWS_CONNMODE_BROADCAST_PROXY_LISTENER;
Andy Greend6e09112011-03-05 16:12:15 +00002154 wsi->count_active_extensions = 0;
Andy Green0d338332011-02-12 11:57:43 +00002155 /* note which protocol we are proxying */
Peter Hinz56885f32011-03-02 22:03:47 +00002156 wsi->protocol_index_for_broadcast_proxy =
2157 context->count_protocols;
2158 insert_wsi(context, wsi);
Andy Green0d338332011-02-12 11:57:43 +00002159
2160 /* list in internal poll array */
2161
Peter Hinz56885f32011-03-02 22:03:47 +00002162 context->fds[context->fds_count].fd = fd;
2163 context->fds[context->fds_count].events = POLLIN;
2164 context->fds[context->fds_count].revents = 0;
2165 context->fds_count++;
Andy Green3221f922011-02-12 13:14:11 +00002166
2167 /* external POLL support via protocol 0 */
Peter Hinz56885f32011-03-02 22:03:47 +00002168 context->protocols[0].callback(context, wsi,
Andy Green3221f922011-02-12 13:14:11 +00002169 LWS_CALLBACK_ADD_POLL_FD,
2170 (void *)(long)fd, NULL, POLLIN);
Andy Greenb45993c2010-12-18 15:13:50 +00002171 }
2172
Peter Hinz56885f32011-03-02 22:03:47 +00002173 return context;
Andy Greene92cd172011-01-19 13:11:55 +00002174}
Andy Greenb45993c2010-12-18 15:13:50 +00002175
Andy Green4739e5c2011-01-22 12:51:57 +00002176
Andy Greened11a022011-01-20 10:23:50 +00002177#ifndef LWS_NO_FORK
2178
Andy Greene92cd172011-01-19 13:11:55 +00002179/**
2180 * libwebsockets_fork_service_loop() - Optional helper function forks off
2181 * a process for the websocket server loop.
Andy Green6964bb52011-01-23 16:50:33 +00002182 * You don't have to use this but if not, you
2183 * have to make sure you are calling
2184 * libwebsocket_service periodically to service
2185 * the websocket traffic
Peter Hinz56885f32011-03-02 22:03:47 +00002186 * @context: server context returned by creation function
Andy Greene92cd172011-01-19 13:11:55 +00002187 */
Andy Greenb45993c2010-12-18 15:13:50 +00002188
Andy Greene92cd172011-01-19 13:11:55 +00002189int
Peter Hinz56885f32011-03-02 22:03:47 +00002190libwebsockets_fork_service_loop(struct libwebsocket_context *context)
Andy Greene92cd172011-01-19 13:11:55 +00002191{
Andy Greene92cd172011-01-19 13:11:55 +00002192 int fd;
2193 struct sockaddr_in cli_addr;
2194 int n;
Andy Green3221f922011-02-12 13:14:11 +00002195 int p;
Andy Greenb45993c2010-12-18 15:13:50 +00002196
Andy Greened11a022011-01-20 10:23:50 +00002197 n = fork();
2198 if (n < 0)
2199 return n;
2200
2201 if (!n) {
2202
2203 /* main process context */
2204
Andy Green3221f922011-02-12 13:14:11 +00002205 /*
2206 * set up the proxy sockets to allow broadcast from
2207 * service process context
2208 */
2209
Peter Hinz56885f32011-03-02 22:03:47 +00002210 for (p = 0; p < context->count_protocols; p++) {
Andy Greened11a022011-01-20 10:23:50 +00002211 fd = socket(AF_INET, SOCK_STREAM, 0);
2212 if (fd < 0) {
2213 fprintf(stderr, "Unable to create socket\n");
2214 return -1;
2215 }
2216 cli_addr.sin_family = AF_INET;
2217 cli_addr.sin_port = htons(
Peter Hinz56885f32011-03-02 22:03:47 +00002218 context->protocols[p].broadcast_socket_port);
Andy Greened11a022011-01-20 10:23:50 +00002219 cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2220 n = connect(fd, (struct sockaddr *)&cli_addr,
2221 sizeof cli_addr);
2222 if (n < 0) {
2223 fprintf(stderr, "Unable to connect to "
2224 "broadcast socket %d, %s\n",
Andy Green3221f922011-02-12 13:14:11 +00002225 n, strerror(errno));
Andy Greened11a022011-01-20 10:23:50 +00002226 return -1;
2227 }
2228
Peter Hinz56885f32011-03-02 22:03:47 +00002229 context->protocols[p].broadcast_socket_user_fd = fd;
Andy Greened11a022011-01-20 10:23:50 +00002230 }
2231
Andy Greene92cd172011-01-19 13:11:55 +00002232 return 0;
Andy Greenb45993c2010-12-18 15:13:50 +00002233 }
2234
2235 /* we want a SIGHUP when our parent goes down */
2236 prctl(PR_SET_PDEATHSIG, SIGHUP);
2237
2238 /* in this forked process, sit and service websocket connections */
Andy Green8f037e42010-12-19 22:13:26 +00002239
Andy Greene92cd172011-01-19 13:11:55 +00002240 while (1)
Peter Hinz56885f32011-03-02 22:03:47 +00002241 if (libwebsocket_service(context, 1000))
Andy Greene92cd172011-01-19 13:11:55 +00002242 return -1;
Andy Green8f037e42010-12-19 22:13:26 +00002243
Andy Green251f6fa2010-11-03 11:13:06 +00002244 return 0;
Andy Greenff95d7a2010-10-28 22:36:01 +01002245}
2246
Andy Greened11a022011-01-20 10:23:50 +00002247#endif
2248
Andy Greenb45993c2010-12-18 15:13:50 +00002249/**
2250 * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket
Andy Green8f037e42010-12-19 22:13:26 +00002251 * connection.
Andy Greenb45993c2010-12-18 15:13:50 +00002252 * @wsi: pointer to struct websocket you want to know the protocol of
2253 *
Andy Green8f037e42010-12-19 22:13:26 +00002254 *
2255 * This is useful to get the protocol to broadcast back to from inside
Andy Greenb45993c2010-12-18 15:13:50 +00002256 * the callback.
2257 */
Andy Greenab990e42010-10-31 12:42:52 +00002258
Andy Greenb45993c2010-12-18 15:13:50 +00002259const struct libwebsocket_protocols *
2260libwebsockets_get_protocol(struct libwebsocket *wsi)
2261{
2262 return wsi->protocol;
2263}
2264
2265/**
Andy Greene92cd172011-01-19 13:11:55 +00002266 * libwebsockets_broadcast() - Sends a buffer to the callback for all active
Andy Green8f037e42010-12-19 22:13:26 +00002267 * connections of the given protocol.
Andy Greenb45993c2010-12-18 15:13:50 +00002268 * @protocol: pointer to the protocol you will broadcast to all members of
2269 * @buf: buffer containing the data to be broadcase. NOTE: this has to be
Andy Green8f037e42010-12-19 22:13:26 +00002270 * allocated with LWS_SEND_BUFFER_PRE_PADDING valid bytes before
2271 * the pointer and LWS_SEND_BUFFER_POST_PADDING afterwards in the
2272 * case you are calling this function from callback context.
Andy Greenb45993c2010-12-18 15:13:50 +00002273 * @len: length of payload data in buf, starting from buf.
Andy Green8f037e42010-12-19 22:13:26 +00002274 *
2275 * This function allows bulk sending of a packet to every connection using
Andy Greenb45993c2010-12-18 15:13:50 +00002276 * the given protocol. It does not send the data directly; instead it calls
2277 * the callback with a reason type of LWS_CALLBACK_BROADCAST. If the callback
2278 * wants to actually send the data for that connection, the callback itself
2279 * should call libwebsocket_write().
2280 *
2281 * libwebsockets_broadcast() can be called from another fork context without
2282 * having to take any care about data visibility between the processes, it'll
2283 * "just work".
2284 */
2285
2286
2287int
Andy Green8f037e42010-12-19 22:13:26 +00002288libwebsockets_broadcast(const struct libwebsocket_protocols *protocol,
Andy Greenb45993c2010-12-18 15:13:50 +00002289 unsigned char *buf, size_t len)
2290{
Peter Hinz56885f32011-03-02 22:03:47 +00002291 struct libwebsocket_context *context = protocol->owning_server;
Andy Greenb45993c2010-12-18 15:13:50 +00002292 int n;
Andy Green0d338332011-02-12 11:57:43 +00002293 int m;
2294 struct libwebsocket * wsi;
Andy Greenb45993c2010-12-18 15:13:50 +00002295
2296 if (!protocol->broadcast_socket_user_fd) {
2297 /*
Andy Greene92cd172011-01-19 13:11:55 +00002298 * We are either running unforked / flat, or we are being
2299 * called from poll thread context
Andy Greenb45993c2010-12-18 15:13:50 +00002300 * eg, from a callback. In that case don't use sockets for
2301 * broadcast IPC (since we can't open a socket connection to
2302 * a socket listening on our own thread) but directly do the
2303 * send action.
2304 *
2305 * Locking is not needed because we are by definition being
2306 * called in the poll thread context and are serialized.
2307 */
2308
Andy Green0d338332011-02-12 11:57:43 +00002309 for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
Andy Greenb45993c2010-12-18 15:13:50 +00002310
Peter Hinz56885f32011-03-02 22:03:47 +00002311 for (m = 0; m < context->fd_hashtable[n].length; m++) {
Andy Greenb45993c2010-12-18 15:13:50 +00002312
Peter Hinz56885f32011-03-02 22:03:47 +00002313 wsi = context->fd_hashtable[n].wsi[m];
Andy Greenb45993c2010-12-18 15:13:50 +00002314
Andy Green0d338332011-02-12 11:57:43 +00002315 if (wsi->mode != LWS_CONNMODE_WS_SERVING)
2316 continue;
Andy Greenb45993c2010-12-18 15:13:50 +00002317
Andy Green0d338332011-02-12 11:57:43 +00002318 /*
2319 * never broadcast to
2320 * non-established connections
2321 */
2322 if (wsi->state != WSI_STATE_ESTABLISHED)
2323 continue;
2324
2325 /* only broadcast to guys using
2326 * requested protocol
2327 */
2328 if (wsi->protocol != protocol)
2329 continue;
2330
Peter Hinz56885f32011-03-02 22:03:47 +00002331 wsi->protocol->callback(context, wsi,
Andy Green8f037e42010-12-19 22:13:26 +00002332 LWS_CALLBACK_BROADCAST,
Andy Green0d338332011-02-12 11:57:43 +00002333 wsi->user_space,
Andy Greenb45993c2010-12-18 15:13:50 +00002334 buf, len);
Andy Green0d338332011-02-12 11:57:43 +00002335 }
Andy Greenb45993c2010-12-18 15:13:50 +00002336 }
2337
2338 return 0;
2339 }
2340
Andy Green0ca6a172010-12-19 20:50:01 +00002341 /*
2342 * We're being called from a different process context than the server
2343 * loop. Instead of broadcasting directly, we send our
2344 * payload on a socket to do the IPC; the server process will serialize
2345 * the broadcast action in its main poll() loop.
2346 *
2347 * There's one broadcast socket listening for each protocol supported
2348 * set up when the websocket server initializes
2349 */
2350
Andy Green6964bb52011-01-23 16:50:33 +00002351 n = send(protocol->broadcast_socket_user_fd, buf, len, MSG_NOSIGNAL);
Andy Greenb45993c2010-12-18 15:13:50 +00002352
2353 return n;
2354}