add-enable-nofork-config-option.patch
[profile/ivi/libwebsockets.git] / lib / libwebsockets.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * 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
20  */
21
22 #include "private-libwebsockets.h"
23
24 #ifdef LWS_OPENSSL_SUPPORT
25 SSL_CTX *ssl_ctx;
26 int use_ssl;
27 #endif
28
29 void
30 libwebsocket_close_and_free_session(struct libwebsocket *wsi)
31 {
32         int n;
33
34         if ((unsigned long)wsi < LWS_MAX_PROTOCOLS)
35                 return;
36
37         n = wsi->state;
38
39         wsi->state = WSI_STATE_DEAD_SOCKET;
40
41         if (wsi->protocol->callback && n == WSI_STATE_ESTABLISHED)
42                 wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED,
43                                                       wsi->user_space, NULL, 0);
44
45         for (n = 0; n < WSI_TOKEN_COUNT; n++)
46                 if (wsi->utf8_token[n].token)
47                         free(wsi->utf8_token[n].token);
48
49 /*      fprintf(stderr, "closing fd=%d\n", wsi->sock); */
50
51 #ifdef LWS_OPENSSL_SUPPORT
52         if (use_ssl) {
53                 n = SSL_get_fd(wsi->ssl);
54                 SSL_shutdown(wsi->ssl);
55                 close(n);
56                 SSL_free(wsi->ssl);
57         } else {
58 #endif
59                 shutdown(wsi->sock, SHUT_RDWR);
60                 close(wsi->sock);
61 #ifdef LWS_OPENSSL_SUPPORT
62         }
63 #endif
64         if (wsi->user_space)
65                 free(wsi->user_space);
66
67         free(wsi);
68 }
69
70 static int
71 libwebsocket_poll_connections(struct libwebsocket_context *this)
72 {
73         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BROADCAST_PAYLOAD +
74                                                   LWS_SEND_BUFFER_POST_PADDING];
75         int client = this->count_protocols + 1;
76         struct libwebsocket *wsi;
77         int n;
78         size_t len;
79
80         /* check for activity on client sockets */
81
82         for (; client < this->fds_count; client++) {
83
84                 /* handle session socket closed */
85
86                 if (this->fds[client].revents & (POLLERR | POLLHUP)) {
87
88                         debug("Session Socket %d %p (fd=%d) dead\n",
89                                   client, this->wsi[client], this->fds[client]);
90
91                         libwebsocket_close_and_free_session(this->wsi[client]);
92                         goto nuke_this;
93                 }
94
95                 /* any incoming data ready? */
96
97                 if (!(this->fds[client].revents & POLLIN))
98                         continue;
99
100                 /* broadcast? */
101
102                 if ((unsigned long)this->wsi[client] < LWS_MAX_PROTOCOLS) {
103
104                         /* get the issued broadcast payload from the socket */
105
106                         len = read(this->fds[client].fd,
107                                    buf + LWS_SEND_BUFFER_PRE_PADDING,
108                                    MAX_BROADCAST_PAYLOAD);
109
110                         if (len < 0) {
111                                 fprintf(stderr,
112                                            "Error reading broadcast payload\n");
113                                 continue;
114                         }
115
116                         /* broadcast it to all guys with this protocol index */
117
118                         for (n = this->count_protocols + 1;
119                                                      n < this->fds_count; n++) {
120
121                                 wsi = this->wsi[n];
122
123                                 if ((unsigned long)wsi < LWS_MAX_PROTOCOLS)
124                                         continue;
125
126                                 /*
127                                  * never broadcast to non-established
128                                  * connection
129                                  */
130
131                                 if (wsi->state != WSI_STATE_ESTABLISHED)
132                                         continue;
133
134                                 /*
135                                  * only broadcast to connections using
136                                  * the requested protocol
137                                  */
138
139                                 if (wsi->protocol->protocol_index !=
140                                           (int)(unsigned long)this->wsi[client])
141                                         continue;
142
143                                 /* broadcast it to this connection */
144
145                                 wsi->protocol->callback(wsi,
146                                         LWS_CALLBACK_BROADCAST,
147                                         wsi->user_space,
148                                         buf + LWS_SEND_BUFFER_PRE_PADDING, len);
149                         }
150
151                         continue;
152                 }
153
154 #ifdef LWS_OPENSSL_SUPPORT
155                 if (this->use_ssl)
156                         n = SSL_read(this->wsi[client]->ssl, buf, sizeof buf);
157                 else
158 #endif
159                         n = recv(this->fds[client].fd, buf, sizeof buf, 0);
160
161                 if (n < 0) {
162                         fprintf(stderr, "Socket read returned %d\n", n);
163                         continue;
164                 }
165                 if (!n) {
166                         libwebsocket_close_and_free_session(this->wsi[client]);
167                         goto nuke_this;
168                 }
169
170                 /* service incoming data */
171
172                 if (libwebsocket_read(this->wsi[client], buf, n) >= 0)
173                         continue;
174
175                 /*
176                  * it closed and nuked wsi[client], so remove the
177                  * socket handle and wsi from our service list
178                  */
179 nuke_this:
180
181                 debug("nuking wsi %p, fsd_count = %d\n",
182                                         this->wsi[client], this->fds_count - 1);
183
184                 this->fds_count--;
185                 for (n = client; n < this->fds_count; n++) {
186                         this->fds[n] = this->fds[n + 1];
187                         this->wsi[n] = this->wsi[n + 1];
188                 }
189                 break;
190         }
191
192         return 0;
193 }
194
195
196 int
197 libwebsocket_service(struct libwebsocket_context *this, int timeout_ms)
198 {
199         int n;
200         int client;
201         unsigned int clilen;
202         struct sockaddr_in cli_addr;
203         int fd;
204
205         /* stay dead once we are dead */
206
207         if (this == NULL)
208                 return 1;
209
210         n = poll(this->fds, this->fds_count, timeout_ms);
211
212         if (n < 0 || this->fds[0].revents & (POLLERR | POLLHUP)) {
213                 fprintf(stderr, "Listen Socket dead\n");
214                 goto fatal;
215         }
216         if (n == 0) /* poll timeout */
217                 return 0;
218
219         /* handle accept on listening socket? */
220
221         for (client = 0; client < this->count_protocols + 1; client++) {
222
223                 if (!this->fds[client].revents & POLLIN)
224                         continue;
225
226                 /* listen socket got an unencrypted connection... */
227
228                 clilen = sizeof(cli_addr);
229                 fd  = accept(this->fds[client].fd,
230                              (struct sockaddr *)&cli_addr, &clilen);
231                 if (fd < 0) {
232                         fprintf(stderr, "ERROR on accept");
233                         continue;
234                 }
235
236                 if (this->fds_count >= MAX_CLIENTS) {
237                         fprintf(stderr, "too busy");
238                         close(fd);
239                         continue;
240                 }
241
242                 if (client) {
243                         /*
244                          * accepting a connection to broadcast socket
245                          * set wsi to be protocol index not pointer
246                          */
247
248                         this->wsi[this->fds_count] =
249                               (struct libwebsocket *)(long)(client - 1);
250
251                         goto fill_in_fds;
252                 }
253
254                 /* accepting connection to main listener */
255
256                 this->wsi[this->fds_count] =
257                                     malloc(sizeof(struct libwebsocket));
258                 if (!this->wsi[this->fds_count]) {
259                         fprintf(stderr, "Out of memory for new connection\n");
260                         continue;
261                 }
262
263 #ifdef LWS_OPENSSL_SUPPORT
264                 if (this->use_ssl) {
265
266                         this->wsi[this->fds_count]->ssl = SSL_new(ssl_ctx);
267                         if (this->wsi[this->fds_count]->ssl == NULL) {
268                                 fprintf(stderr, "SSL_new failed: %s\n",
269                                     ERR_error_string(SSL_get_error(
270                                     this->wsi[this->fds_count]->ssl, 0),
271                                                                  NULL));
272                                 free(this->wsi[this->fds_count]);
273                                 continue;
274                         }
275
276                         SSL_set_fd(this->wsi[this->fds_count]->ssl, fd);
277
278                         n = SSL_accept(this->wsi[this->fds_count]->ssl);
279                         if (n != 1) {
280                                 /*
281                                  * browsers seem to probe with various
282                                  * ssl params which fail then retry
283                                  * and succeed
284                                  */
285                                 debug("SSL_accept failed skt %u: %s\n",
286                                       fd,
287                                       ERR_error_string(SSL_get_error(
288                                       this->wsi[this->fds_count]->ssl,
289                                                              n), NULL));
290                                 SSL_free(
291                                        this->wsi[this->fds_count]->ssl);
292                                 free(this->wsi[this->fds_count]);
293                                 continue;
294                         }
295                         debug("accepted new SSL conn  "
296                               "port %u on fd=%d SSL ver %s\n",
297                                 ntohs(cli_addr.sin_port), fd,
298                                   SSL_get_version(this->wsi[
299                                                 this->fds_count]->ssl));
300
301                 } else
302 #endif
303                         debug("accepted new conn  port %u on fd=%d\n",
304                                           ntohs(cli_addr.sin_port), fd);
305
306                 /* intialize the instance struct */
307
308                 this->wsi[this->fds_count]->sock = fd;
309                 this->wsi[this->fds_count]->state = WSI_STATE_HTTP;
310                 this->wsi[this->fds_count]->name_buffer_pos = 0;
311
312                 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
313                         this->wsi[this->fds_count]->
314                                              utf8_token[n].token = NULL;
315                         this->wsi[this->fds_count]->
316                                             utf8_token[n].token_len = 0;
317                 }
318
319                 /*
320                  * these can only be set once the protocol is known
321                  * we set an unestablished connection's protocol pointer
322                  * to the start of the supported list, so it can look
323                  * for matching ones during the handshake
324                  */
325                 this->wsi[this->fds_count]->protocol = this->protocols;
326                 this->wsi[this->fds_count]->user_space = NULL;
327
328                 /*
329                  * Default protocol is 76 / 00
330                  * After 76, there's a header specified to inform which
331                  * draft the client wants, when that's seen we modify
332                  * the individual connection's spec revision accordingly
333                  */
334                 this->wsi[this->fds_count]->ietf_spec_revision = 0;
335
336 fill_in_fds:
337
338                 /*
339                  * make sure NO events are seen yet on this new socket
340                  * (otherwise we inherit old fds[client].revents from
341                  * previous socket there and die mysteriously! )
342                  */
343                 this->fds[this->fds_count].revents = 0;
344
345                 this->fds[this->fds_count].events = POLLIN;
346                 this->fds[this->fds_count++].fd = fd;
347
348         }
349
350         /* service anything incoming on websocket connection */
351
352         libwebsocket_poll_connections(this);
353
354         /* this round is done */
355
356         return 0;
357
358 fatal:
359
360         /* close listening skt and per-protocol broadcast sockets */
361         for (client = 0; client < this->fds_count; client++)
362                 close(this->fds[0].fd);
363
364 #ifdef LWS_OPENSSL_SUPPORT
365         SSL_CTX_free(ssl_ctx);
366 #endif
367         kill(0, SIGTERM);
368
369         if (this)
370                 free(this);
371
372         this = NULL;
373
374         /* inform caller we are dead */
375
376         return 1;
377 }
378
379
380 /**
381  * libwebsocket_create_server() - Create the listening websockets server
382  * @port:       Port to listen on
383  * @protocols:  Array of structures listing supported protocols and a protocol-
384  *              specific callback for each one.  The list is ended with an
385  *              entry that has a NULL callback pointer.
386  *              It's not const because we write the owning_server member
387  * @ssl_cert_filepath:  If libwebsockets was compiled to use ssl, and you want
388  *                      to listen using SSL, set to the filepath to fetch the
389  *                      server cert from, otherwise NULL for unencrypted
390  * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
391  *                      else ignored
392  * @gid:        group id to change to after setting listen socket, or -1.
393  * @uid:        user id to change to after setting listen socket, or -1.
394  *
395  *      This function creates the listening socket and takes care
396  *      of all initialization in one step.
397  *
398  *      After initialization, it returns a struct libwebsocket_context * that
399  *      represents this server.  After calling, user code needs to take care
400  *      of calling libwebsocket_service() with the context pointer to get the
401  *      server's sockets serviced.  This can be done in the same process context
402  *      or a forked process, or another thread,
403  *
404  *      The protocol callback functions are called for a handful of events
405  *      including http requests coming in, websocket connections becoming
406  *      established, and data arriving; it's also called periodically to allow
407  *      async transmission.
408  *
409  *      HTTP requests are sent always to the FIRST protocol in @protocol, since
410  *      at that time websocket protocol has not been negotiated.  Other
411  *      protocols after the first one never see any HTTP callack activity.
412  *
413  *      The server created is a simple http server by default; part of the
414  *      websocket standard is upgrading this http connection to a websocket one.
415  *
416  *      This allows the same server to provide files like scripts and favicon /
417  *      images or whatever over http and dynamic data over websockets all in
418  *      one place; they're all handled in the user callback.
419  */
420
421 struct libwebsocket_context *
422 libwebsocket_create_server(int port,
423                                struct libwebsocket_protocols *protocols,
424                                const char *ssl_cert_filepath,
425                                const char *ssl_private_key_filepath,
426                                int gid, int uid)
427 {
428         int n;
429         int sockfd;
430         int fd;
431         struct sockaddr_in serv_addr, cli_addr;
432         int opt = 1;
433         struct libwebsocket_context *this = NULL;
434         unsigned int slen;
435
436 #ifdef LWS_OPENSSL_SUPPORT
437         SSL_METHOD *method;
438         char ssl_err_buf[512];
439
440         use_ssl = ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL;
441         if (use_ssl)
442                 fprintf(stderr, " Compiled with SSL support, using it\n");
443         else
444                 fprintf(stderr, " Compiled with SSL support, not using it\n");
445
446 #else
447         if (ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL) {
448                 fprintf(stderr, " Not compiled for OpenSSl support!\n");
449                 return NULL;
450         }
451         fprintf(stderr, " Compiled without SSL support, serving unencrypted\n");
452 #endif
453
454 #ifdef LWS_OPENSSL_SUPPORT
455         if (use_ssl) {
456                 SSL_library_init();
457
458                 OpenSSL_add_all_algorithms();
459                 SSL_load_error_strings();
460
461                 /*
462                  * Firefox insists on SSLv23 not SSLv3
463                  * Konq disables SSLv2 by default now, SSLv23 works
464                  */
465
466                 method = (SSL_METHOD *)SSLv23_server_method();
467                 if (!method) {
468                         fprintf(stderr, "problem creating ssl method: %s\n",
469                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
470                         return NULL;
471                 }
472                 ssl_ctx = SSL_CTX_new(method);  /* create context */
473                 if (!ssl_ctx) {
474                         printf("problem creating ssl context: %s\n",
475                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
476                         return NULL;
477                 }
478                 /* set the local certificate from CertFile */
479                 n = SSL_CTX_use_certificate_file(ssl_ctx,
480                                         ssl_cert_filepath, SSL_FILETYPE_PEM);
481                 if (n != 1) {
482                         fprintf(stderr, "problem getting cert '%s': %s\n",
483                                 ssl_cert_filepath,
484                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
485                         return NULL;
486                 }
487                 /* set the private key from KeyFile */
488                 if (SSL_CTX_use_PrivateKey_file(ssl_ctx,
489                                                 ssl_private_key_filepath,
490                                                 SSL_FILETYPE_PEM) != 1) {
491                         fprintf(stderr, "ssl problem getting key '%s': %s\n",
492                                                 ssl_private_key_filepath,
493                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
494                         return NULL;
495                 }
496                 /* verify private key */
497                 if (!SSL_CTX_check_private_key(ssl_ctx)) {
498                         fprintf(stderr, "Private SSL key doesn't match cert\n");
499                         return NULL;
500                 }
501
502                 /* SSL is happy and has a cert it's content with */
503         }
504 #endif
505
506         /* selftest */
507
508         if (lws_b64_selftest())
509                 return NULL;
510
511
512         this = malloc(sizeof(struct libwebsocket_context));
513
514         this->protocols = protocols;
515
516         /* set up our external listening socket we serve on */
517
518         sockfd = socket(AF_INET, SOCK_STREAM, 0);
519         if (sockfd < 0) {
520                 fprintf(stderr, "ERROR opening socket");
521                 return NULL;
522         }
523
524         /* allow us to restart even if old sockets in TIME_WAIT */
525         setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
526
527         bzero((char *) &serv_addr, sizeof(serv_addr));
528         serv_addr.sin_family = AF_INET;
529         serv_addr.sin_addr.s_addr = INADDR_ANY;
530         serv_addr.sin_port = htons(port);
531
532         n = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
533         if (n < 0) {
534                 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
535                                                                 port, n, errno);
536                 return NULL;
537         }
538
539         /* drop any root privs for this process */
540
541         if (gid != -1)
542                 if (setgid(gid))
543                         fprintf(stderr, "setgid: %s\n", strerror(errno));
544         if (uid != -1)
545                 if (setuid(uid))
546                         fprintf(stderr, "setuid: %s\n", strerror(errno));
547
548         /*
549          * prepare the poll() fd array... it's like this
550          *
551          * [0] = external listening socket
552          * [1 .. this->count_protocols] = per-protocol broadcast sockets
553          * [this->count_protocols + 1 ... this->fds_count-1] = connection skts
554          */
555
556         this->fds_count = 1;
557         this->fds[0].fd = sockfd;
558         this->fds[0].events = POLLIN;
559         this->count_protocols = 0;
560 #ifdef LWS_OPENSSL_SUPPORT
561         this->use_ssl = use_ssl;
562 #endif
563
564         listen(sockfd, 5);
565         fprintf(stderr, " Listening on port %d\n", port);
566
567         /* set up our internal broadcast trigger sockets per-protocol */
568
569         for (; protocols[this->count_protocols].callback;
570                                                       this->count_protocols++) {
571                 protocols[this->count_protocols].owning_server = this;
572                 protocols[this->count_protocols].protocol_index =
573                                                           this->count_protocols;
574
575                 fd = socket(AF_INET, SOCK_STREAM, 0);
576                 if (fd < 0) {
577                         fprintf(stderr, "ERROR opening socket");
578                         return NULL;
579                 }
580
581                 /* allow us to restart even if old sockets in TIME_WAIT */
582                 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
583
584                 bzero((char *) &serv_addr, sizeof(serv_addr));
585                 serv_addr.sin_family = AF_INET;
586                 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
587                 serv_addr.sin_port = 0; /* pick the port for us */
588
589                 n = bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
590                 if (n < 0) {
591                         fprintf(stderr, "ERROR on binding to port %d (%d %d)\n",
592                                                                 port, n, errno);
593                         return NULL;
594                 }
595
596                 slen = sizeof cli_addr;
597                 n = getsockname(fd, (struct sockaddr *)&cli_addr, &slen);
598                 if (n < 0) {
599                         fprintf(stderr, "getsockname failed\n");
600                         return NULL;
601                 }
602                 protocols[this->count_protocols].broadcast_socket_port =
603                                                        ntohs(cli_addr.sin_port);
604                 listen(fd, 5);
605
606                 debug("  Protocol %s broadcast socket %d\n",
607                                 protocols[this->count_protocols].name,
608                                                       ntohs(cli_addr.sin_port));
609
610                 this->fds[this->fds_count].fd = fd;
611                 this->fds[this->fds_count].events = POLLIN;
612                 /* wsi only exists for connections, not broadcast listener */
613                 this->wsi[this->fds_count] = NULL;
614                 this->fds_count++;
615         }
616
617         return this;
618 }
619
620 #ifndef LWS_NO_FORK
621
622 /**
623  * libwebsockets_fork_service_loop() - Optional helper function forks off
624  *                                a process for the websocket server loop.
625  *                              You don't have to use this but if not, you
626  *                              have to make sure you are calling
627  *                              libwebsocket_service periodically to service
628  *                              the websocket traffic
629  * @this:       server context returned by creation function
630  */
631
632 int
633 libwebsockets_fork_service_loop(struct libwebsocket_context *this)
634 {
635         int client;
636         int fd;
637         struct sockaddr_in cli_addr;
638         int n;
639
640         n = fork();
641         if (n < 0)
642                 return n;
643
644         if (!n) {
645
646                 /* main process context */
647
648                 for (client = 1; client < this->count_protocols + 1; client++) {
649                         fd = socket(AF_INET, SOCK_STREAM, 0);
650                         if (fd < 0) {
651                                 fprintf(stderr, "Unable to create socket\n");
652                                 return -1;
653                         }
654                         cli_addr.sin_family = AF_INET;
655                         cli_addr.sin_port = htons(
656                                    this->protocols[client - 1].broadcast_socket_port);
657                         cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
658                         n = connect(fd, (struct sockaddr *)&cli_addr,
659                                                                sizeof cli_addr);
660                         if (n < 0) {
661                                 fprintf(stderr, "Unable to connect to "
662                                                 "broadcast socket %d, %s\n",
663                                                 client, strerror(errno));
664                                 return -1;
665                         }
666
667                         this->protocols[client - 1].broadcast_socket_user_fd = fd;
668                 }
669
670
671                 return 0;
672         }
673
674         /* we want a SIGHUP when our parent goes down */
675         prctl(PR_SET_PDEATHSIG, SIGHUP);
676
677         /* in this forked process, sit and service websocket connections */
678
679         while (1)
680                 if (libwebsocket_service(this, 1000))
681                         return -1;
682
683         return 0;
684 }
685
686 #endif
687
688 /**
689  * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket
690  *                                connection.
691  * @wsi:        pointer to struct websocket you want to know the protocol of
692  *
693  *
694  *      This is useful to get the protocol to broadcast back to from inside
695  * the callback.
696  */
697
698 const struct libwebsocket_protocols *
699 libwebsockets_get_protocol(struct libwebsocket *wsi)
700 {
701         return wsi->protocol;
702 }
703
704 /**
705  * libwebsockets_broadcast() - Sends a buffer to the callback for all active
706  *                                connections of the given protocol.
707  * @protocol:   pointer to the protocol you will broadcast to all members of
708  * @buf:  buffer containing the data to be broadcase.  NOTE: this has to be
709  *              allocated with LWS_SEND_BUFFER_PRE_PADDING valid bytes before
710  *              the pointer and LWS_SEND_BUFFER_POST_PADDING afterwards in the
711  *              case you are calling this function from callback context.
712  * @len:        length of payload data in buf, starting from buf.
713  *
714  *      This function allows bulk sending of a packet to every connection using
715  * the given protocol.  It does not send the data directly; instead it calls
716  * the callback with a reason type of LWS_CALLBACK_BROADCAST.  If the callback
717  * wants to actually send the data for that connection, the callback itself
718  * should call libwebsocket_write().
719  *
720  * libwebsockets_broadcast() can be called from another fork context without
721  * having to take any care about data visibility between the processes, it'll
722  * "just work".
723  */
724
725
726 int
727 libwebsockets_broadcast(const struct libwebsocket_protocols *protocol,
728                                                  unsigned char *buf, size_t len)
729 {
730         struct libwebsocket_context *this = protocol->owning_server;
731         int n;
732
733         if (!protocol->broadcast_socket_user_fd) {
734                 /*
735                  * We are either running unforked / flat, or we are being
736                  * called from poll thread context
737                  * eg, from a callback.  In that case don't use sockets for
738                  * broadcast IPC (since we can't open a socket connection to
739                  * a socket listening on our own thread) but directly do the
740                  * send action.
741                  *
742                  * Locking is not needed because we are by definition being
743                  * called in the poll thread context and are serialized.
744                  */
745
746                 for (n = this->count_protocols + 1; n < this->fds_count; n++) {
747
748                         if ((unsigned long)this->wsi[n] < LWS_MAX_PROTOCOLS)
749                                 continue;
750
751                         /* never broadcast to non-established connection */
752
753                         if (this->wsi[n]->state != WSI_STATE_ESTABLISHED)
754                                 continue;
755
756                         /* only broadcast to guys using requested protocol */
757
758                         if (this->wsi[n]->protocol != protocol)
759                                 continue;
760
761                         this->wsi[n]->protocol->callback(this->wsi[n],
762                                          LWS_CALLBACK_BROADCAST,
763                                          this->wsi[n]->user_space,
764                                          buf, len);
765                 }
766
767                 return 0;
768         }
769
770         /*
771          * We're being called from a different process context than the server
772          * loop.  Instead of broadcasting directly, we send our
773          * payload on a socket to do the IPC; the server process will serialize
774          * the broadcast action in its main poll() loop.
775          *
776          * There's one broadcast socket listening for each protocol supported
777          * set up when the websocket server initializes
778          */
779
780         n = send(protocol->broadcast_socket_user_fd, buf, len, 0);
781
782         return n;
783 }