private.h: rename to contain dir
[platform/upstream/libwebsockets.git] / lib / core-net / wsi.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2019 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-lib-core.h"
23
24 #if defined (_DEBUG)
25 void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
26 {
27         wsi->wsistate = (wsi->wsistate & (~LWSI_ROLE_MASK)) | role;
28
29         lwsl_debug("lwsi_set_role(%p, 0x%lx)\n", wsi,
30                                         (unsigned long)wsi->wsistate);
31 }
32
33 void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs)
34 {
35         wsi->wsistate = (wsi->wsistate & (~LRS_MASK)) | lrs;
36
37         lwsl_debug("lwsi_set_state(%p, 0x%lx)\n", wsi,
38                                         (unsigned long)wsi->wsistate);
39 }
40 #endif
41
42
43 void
44 lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
45 {
46         if (wsi->vhost == vh)
47                 return;
48         lws_context_lock(vh->context, __func__); /* ---------- context { */
49         wsi->vhost = vh;
50         vh->count_bound_wsi++;
51         lws_context_unlock(vh->context); /* } context ---------- */
52         lwsl_info("%s: vh %s: count_bound_wsi %d\n",
53                     __func__, vh->name, vh->count_bound_wsi);
54         assert(wsi->vhost->count_bound_wsi > 0);
55 }
56
57 void
58 lws_vhost_unbind_wsi(struct lws *wsi)
59 {
60         if (!wsi->vhost)
61                 return;
62
63         lws_context_lock(wsi->context, __func__); /* ---------- context { */
64
65         assert(wsi->vhost->count_bound_wsi > 0);
66         wsi->vhost->count_bound_wsi--;
67         lwsl_info("%s: vh %s: count_bound_wsi %d\n", __func__,
68                   wsi->vhost->name, wsi->vhost->count_bound_wsi);
69
70         if (!wsi->vhost->count_bound_wsi &&
71             wsi->vhost->being_destroyed) {
72                 /*
73                  * We have closed all wsi that were bound to this vhost
74                  * by any pt: nothing can be servicing any wsi belonging
75                  * to it any more.
76                  *
77                  * Finalize the vh destruction
78                  */
79                 __lws_vhost_destroy2(wsi->vhost);
80         }
81         wsi->vhost = NULL;
82
83         lws_context_unlock(wsi->context); /* } context ---------- */
84 }
85
86 LWS_VISIBLE struct lws *
87 lws_get_network_wsi(struct lws *wsi)
88 {
89         if (!wsi)
90                 return NULL;
91
92 #if defined(LWS_WITH_HTTP2)
93         if (!wsi->http2_substream
94 #if !defined(LWS_NO_CLIENT)
95                         && !wsi->client_h2_substream
96 #endif
97         )
98                 return wsi;
99
100         while (wsi->h2.parent_wsi)
101                 wsi = wsi->h2.parent_wsi;
102 #endif
103
104         return wsi;
105 }
106
107
108 LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
109 lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
110 {
111         int n;
112
113         for (n = 0; n < vh->count_protocols; n++)
114                 if (vh->protocols[n].name && !strcmp(name, vh->protocols[n].name))
115                         return &vh->protocols[n];
116
117         return NULL;
118 }
119
120 LWS_VISIBLE int
121 lws_callback_all_protocol(struct lws_context *context,
122                           const struct lws_protocols *protocol, int reason)
123 {
124         struct lws_context_per_thread *pt = &context->pt[0];
125         unsigned int n, m = context->count_threads;
126         struct lws *wsi;
127
128         while (m--) {
129                 for (n = 0; n < pt->fds_count; n++) {
130                         wsi = wsi_from_fd(context, pt->fds[n].fd);
131                         if (!wsi)
132                                 continue;
133                         if (wsi->protocol == protocol)
134                                 protocol->callback(wsi, reason, wsi->user_space,
135                                                    NULL, 0);
136                 }
137                 pt++;
138         }
139
140         return 0;
141 }
142
143 LWS_VISIBLE int
144 lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
145                           const struct lws_protocols *protocol, int reason,
146                           void *argp, size_t len)
147 {
148         struct lws_context *context = vh->context;
149         struct lws_context_per_thread *pt = &context->pt[0];
150         unsigned int n, m = context->count_threads;
151         struct lws *wsi;
152
153         while (m--) {
154                 for (n = 0; n < pt->fds_count; n++) {
155                         wsi = wsi_from_fd(context, pt->fds[n].fd);
156                         if (!wsi)
157                                 continue;
158                         if (wsi->vhost == vh && (wsi->protocol == protocol ||
159                                                  !protocol))
160                                 wsi->protocol->callback(wsi, reason,
161                                                 wsi->user_space, argp, len);
162                 }
163                 pt++;
164         }
165
166         return 0;
167 }
168
169 LWS_VISIBLE int
170 lws_callback_all_protocol_vhost(struct lws_vhost *vh,
171                           const struct lws_protocols *protocol, int reason)
172 {
173         return lws_callback_all_protocol_vhost_args(vh, protocol, reason, NULL, 0);
174 }
175
176 LWS_VISIBLE LWS_EXTERN int
177 lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
178 {
179         int n;
180
181         for (n = 0; n < wsi->vhost->count_protocols; n++)
182                 if (wsi->vhost->protocols[n].callback(wsi, reason, NULL, in, len))
183                         return 1;
184
185         return 0;
186 }
187
188 LWS_VISIBLE LWS_EXTERN int
189 lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
190                                    size_t len)
191 {
192         int n;
193         struct lws *wsi = lws_zalloc(sizeof(*wsi), "fake wsi");
194
195         if (!wsi)
196                 return 1;
197
198         wsi->context = vh->context;
199         lws_vhost_bind_wsi(vh, wsi);
200
201         for (n = 0; n < wsi->vhost->count_protocols; n++) {
202                 wsi->protocol = &vh->protocols[n];
203                 if (wsi->protocol->callback(wsi, reason, NULL, in, len)) {
204                         lws_free(wsi);
205                         return 1;
206                 }
207         }
208
209         lws_free(wsi);
210
211         return 0;
212 }
213
214
215 LWS_VISIBLE int
216 lws_rx_flow_control(struct lws *wsi, int _enable)
217 {
218         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
219         int en = _enable;
220
221         // h2 ignores rx flow control atm
222         if (lwsi_role_h2(wsi) || wsi->http2_substream ||
223             lwsi_role_h2_ENCAPSULATION(wsi))
224                 return 0; // !!!
225
226         lwsl_info("%s: %p 0x%x\n", __func__, wsi, _enable);
227
228         if (!(_enable & LWS_RXFLOW_REASON_APPLIES)) {
229                 /*
230                  * convert user bool style to bitmap style... in user simple
231                  * bool style _enable = 0 = flow control it, = 1 = allow rx
232                  */
233                 en = LWS_RXFLOW_REASON_APPLIES | LWS_RXFLOW_REASON_USER_BOOL;
234                 if (_enable & 1)
235                         en |= LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT;
236         }
237
238         lws_pt_lock(pt, __func__);
239
240         /* any bit set in rxflow_bitmap DISABLEs rxflow control */
241         if (en & LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT)
242                 wsi->rxflow_bitmap &= ~(en & 0xff);
243         else
244                 wsi->rxflow_bitmap |= en & 0xff;
245
246         if ((LWS_RXFLOW_PENDING_CHANGE | (!wsi->rxflow_bitmap)) ==
247             wsi->rxflow_change_to)
248                 goto skip;
249
250         wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE |
251                                 (!wsi->rxflow_bitmap);
252
253         lwsl_info("%s: %p: bitmap 0x%x: en 0x%x, ch 0x%x\n", __func__, wsi,
254                   wsi->rxflow_bitmap, en, wsi->rxflow_change_to);
255
256         if (_enable & LWS_RXFLOW_REASON_FLAG_PROCESS_NOW ||
257             !wsi->rxflow_will_be_applied) {
258                 en = __lws_rx_flow_control(wsi);
259                 lws_pt_unlock(pt);
260
261                 return en;
262         }
263
264 skip:
265         lws_pt_unlock(pt);
266
267         return 0;
268 }
269
270 LWS_VISIBLE void
271 lws_rx_flow_allow_all_protocol(const struct lws_context *context,
272                                const struct lws_protocols *protocol)
273 {
274         const struct lws_context_per_thread *pt = &context->pt[0];
275         struct lws *wsi;
276         unsigned int n, m = context->count_threads;
277
278         while (m--) {
279                 for (n = 0; n < pt->fds_count; n++) {
280                         wsi = wsi_from_fd(context, pt->fds[n].fd);
281                         if (!wsi)
282                                 continue;
283                         if (wsi->protocol == protocol)
284                                 lws_rx_flow_control(wsi, LWS_RXFLOW_ALLOW);
285                 }
286                 pt++;
287         }
288 }
289
290 int user_callback_handle_rxflow(lws_callback_function callback_function,
291                                 struct lws *wsi,
292                                 enum lws_callback_reasons reason, void *user,
293                                 void *in, size_t len)
294 {
295         int n;
296
297         wsi->rxflow_will_be_applied = 1;
298         n = callback_function(wsi, reason, user, in, len);
299         wsi->rxflow_will_be_applied = 0;
300         if (!n)
301                 n = __lws_rx_flow_control(wsi);
302
303         return n;
304 }
305
306 LWS_EXTERN int
307 __lws_rx_flow_control(struct lws *wsi)
308 {
309         struct lws *wsic = wsi->child_list;
310
311         // h2 ignores rx flow control atm
312         if (lwsi_role_h2(wsi) || wsi->http2_substream ||
313             lwsi_role_h2_ENCAPSULATION(wsi))
314                 return 0; // !!!
315
316         /* if he has children, do those if they were changed */
317         while (wsic) {
318                 if (wsic->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)
319                         __lws_rx_flow_control(wsic);
320
321                 wsic = wsic->sibling_list;
322         }
323
324         /* there is no pending change */
325         if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
326                 return 0;
327
328         /* stuff is still buffered, not ready to really accept new input */
329         if (lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
330                 /* get ourselves called back to deal with stashed buffer */
331                 lws_callback_on_writable(wsi);
332                 // return 0;
333         }
334
335         /* now the pending is cleared, we can change rxflow state */
336
337         wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
338
339         lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
340                   wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);
341
342         /* adjust the pollfd for this wsi */
343
344         if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) {
345                 lwsl_info("%s: reenable POLLIN\n", __func__);
346                 // lws_buflist_describe(&wsi->buflist, NULL);
347                 if (__lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
348                         lwsl_info("%s: fail\n", __func__);
349                         return -1;
350                 }
351         } else
352                 if (__lws_change_pollfd(wsi, LWS_POLLIN, 0))
353                         return -1;
354
355         return 0;
356 }
357
358
359 LWS_VISIBLE const struct lws_protocols *
360 lws_get_protocol(struct lws *wsi)
361 {
362         return wsi->protocol;
363 }
364
365
366 int
367 lws_ensure_user_space(struct lws *wsi)
368 {
369         if (!wsi->protocol)
370                 return 0;
371
372         /* allocate the per-connection user memory (if any) */
373
374         if (wsi->protocol->per_session_data_size && !wsi->user_space) {
375                 wsi->user_space = lws_zalloc(
376                             wsi->protocol->per_session_data_size, "user space");
377                 if (wsi->user_space == NULL) {
378                         lwsl_err("%s: OOM\n", __func__);
379                         return 1;
380                 }
381         } else
382                 lwsl_debug("%s: %p protocol pss %lu, user_space=%p\n", __func__,
383                            wsi, (long)wsi->protocol->per_session_data_size,
384                            wsi->user_space);
385         return 0;
386 }
387
388 LWS_VISIBLE void *
389 lws_adjust_protocol_psds(struct lws *wsi, size_t new_size)
390 {
391         ((struct lws_protocols *)lws_get_protocol(wsi))->per_session_data_size =
392                 new_size;
393
394         if (lws_ensure_user_space(wsi))
395                         return NULL;
396
397         return wsi->user_space;
398 }
399
400
401
402 LWS_VISIBLE int
403 lws_is_ssl(struct lws *wsi)
404 {
405 #if defined(LWS_WITH_TLS)
406         return wsi->tls.use_ssl & LCCSCF_USE_SSL;
407 #else
408         (void)wsi;
409         return 0;
410 #endif
411 }
412
413 #if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
414 LWS_VISIBLE lws_tls_conn*
415 lws_get_ssl(struct lws *wsi)
416 {
417         return wsi->tls.ssl;
418 }
419 #endif
420
421 LWS_VISIBLE int
422 lws_partial_buffered(struct lws *wsi)
423 {
424         return lws_has_buffered_out(wsi);
425 }
426
427 LWS_VISIBLE lws_fileofs_t
428 lws_get_peer_write_allowance(struct lws *wsi)
429 {
430         if (!wsi->role_ops->tx_credit)
431                 return -1;
432         return wsi->role_ops->tx_credit(wsi);
433 }
434
435 LWS_VISIBLE void
436 lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
437                     const struct lws_role_ops *ops)
438 {
439 #if defined(_DEBUG)
440         const char *name = "(unset)";
441 #endif
442         wsi->wsistate = role | state;
443         if (ops)
444                 wsi->role_ops = ops;
445 #if defined(_DEBUG)
446         if (wsi->role_ops)
447                 name = wsi->role_ops->name;
448         lwsl_debug("%s: %p: wsistate 0x%lx, ops %s\n", __func__, wsi,
449                    (unsigned long)wsi->wsistate, name);
450 #endif
451 }
452
453 LWS_VISIBLE LWS_EXTERN int
454 lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
455               const char **path)
456 {
457         const char *end;
458         char unix_skt = 0;
459
460         /* cut up the location into address, port and path */
461         *prot = p;
462         while (*p && (*p != ':' || p[1] != '/' || p[2] != '/'))
463                 p++;
464         if (!*p) {
465                 end = p;
466                 p = (char *)*prot;
467                 *prot = end;
468         } else {
469                 *p = '\0';
470                 p += 3;
471         }
472         if (*p == '+') /* unix skt */
473                 unix_skt = 1;
474
475         *ads = p;
476         if (!strcmp(*prot, "http") || !strcmp(*prot, "ws"))
477                 *port = 80;
478         else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss"))
479                 *port = 443;
480
481         if (*p == '[') {
482                 ++(*ads);
483                 while (*p && *p != ']')
484                         p++;
485                 if (*p)
486                         *p++ = '\0';
487         } else
488                 while (*p && *p != ':' && (unix_skt || *p != '/'))
489                         p++;
490
491         if (*p == ':') {
492                 *p++ = '\0';
493                 *port = atoi(p);
494                 while (*p && *p != '/')
495                         p++;
496         }
497         *path = "/";
498         if (*p) {
499                 *p++ = '\0';
500                 if (*p)
501                         *path = p;
502         }
503
504         return 0;
505 }
506
507 /* ... */
508
509 LWS_VISIBLE LWS_EXTERN const char *
510 lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
511 {
512         int n = 0, sl = (int)strlen(name);
513
514         while (lws_hdr_copy_fragment(wsi, buf, len,
515                           WSI_TOKEN_HTTP_URI_ARGS, n) >= 0) {
516
517                 if (!strncmp(buf, name, sl))
518                         return buf + sl;
519
520                 n++;
521         }
522
523         return NULL;
524 }
525
526
527 #if defined(LWS_WITHOUT_EXTENSIONS)
528
529 /* we need to provide dummy callbacks for internal exts
530  * so user code runs when faced with a lib compiled with
531  * extensions disabled.
532  */
533
534 LWS_VISIBLE int
535 lws_extension_callback_pm_deflate(struct lws_context *context,
536                                   const struct lws_extension *ext,
537                                   struct lws *wsi,
538                                   enum lws_extension_callback_reasons reason,
539                                   void *user, void *in, size_t len)
540 {
541         (void)context;
542         (void)ext;
543         (void)wsi;
544         (void)reason;
545         (void)user;
546         (void)in;
547         (void)len;
548
549         return 0;
550 }
551
552 LWS_EXTERN int
553 lws_set_extension_option(struct lws *wsi, const char *ext_name,
554                          const char *opt_name, const char *opt_val)
555 {
556         return -1;
557 }
558 #endif
559
560 LWS_VISIBLE LWS_EXTERN int
561 lws_is_cgi(struct lws *wsi) {
562 #ifdef LWS_WITH_CGI
563         return !!wsi->http.cgi;
564 #else
565         return 0;
566 #endif
567 }
568
569 const struct lws_protocol_vhost_options *
570 lws_pvo_search(const struct lws_protocol_vhost_options *pvo, const char *name)
571 {
572         while (pvo) {
573                 if (!strcmp(pvo->name, name))
574                         break;
575
576                 pvo = pvo->next;
577         }
578
579         return pvo;
580 }
581
582 int
583 lws_pvo_get_str(void *in, const char *name, const char **result)
584 {
585         const struct lws_protocol_vhost_options *pv =
586                 lws_pvo_search((const struct lws_protocol_vhost_options *)in,
587                                 name);
588
589         if (!pv)
590                 return 1;
591
592         *result = (const char *)pv->value;
593
594         return 0;
595 }
596
597 int
598 lws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len)
599 {
600         struct lws_vhost *v = pt->context->vhost_list;
601         int n, ret = 0;
602
603         pt->fake_wsi->context = pt->context;
604
605         while (v) {
606                 const struct lws_protocols *p = v->protocols;
607                 pt->fake_wsi->vhost = v; /* not a real bound wsi */
608
609                 for (n = 0; n < v->count_protocols; n++) {
610                         pt->fake_wsi->protocol = p;
611                         if (p->callback &&
612                             p->callback(pt->fake_wsi, reason, NULL, in, len))
613                                 ret |= 1;
614                         p++;
615                 }
616                 v = v->vhost_next;
617         }
618
619         return ret;
620 }
621
622 LWS_VISIBLE LWS_EXTERN void *
623 lws_wsi_user(struct lws *wsi)
624 {
625         return wsi->user_space;
626 }
627
628 LWS_VISIBLE LWS_EXTERN void
629 lws_set_wsi_user(struct lws *wsi, void *data)
630 {
631         if (wsi->user_space_externally_allocated)
632                 wsi->user_space = data;
633         else
634                 lwsl_err("%s: Cannot set internally-allocated user_space\n",
635                          __func__);
636 }
637
638 LWS_VISIBLE LWS_EXTERN struct lws *
639 lws_get_parent(const struct lws *wsi)
640 {
641         return wsi->parent;
642 }
643
644 LWS_VISIBLE LWS_EXTERN struct lws *
645 lws_get_child(const struct lws *wsi)
646 {
647         return wsi->child_list;
648 }
649
650 LWS_VISIBLE LWS_EXTERN void *
651 lws_get_opaque_parent_data(const struct lws *wsi)
652 {
653         return wsi->opaque_parent_data;
654 }
655
656 LWS_VISIBLE LWS_EXTERN void
657 lws_set_opaque_parent_data(struct lws *wsi, void *data)
658 {
659         wsi->opaque_parent_data = data;
660 }
661
662 LWS_VISIBLE LWS_EXTERN void *
663 lws_get_opaque_user_data(const struct lws *wsi)
664 {
665         return wsi->opaque_user_data;
666 }
667
668 LWS_VISIBLE LWS_EXTERN void
669 lws_set_opaque_user_data(struct lws *wsi, void *data)
670 {
671         wsi->opaque_user_data = data;
672 }
673
674 LWS_VISIBLE LWS_EXTERN int
675 lws_get_child_pending_on_writable(const struct lws *wsi)
676 {
677         return wsi->parent_pending_cb_on_writable;
678 }
679
680 LWS_VISIBLE LWS_EXTERN void
681 lws_clear_child_pending_on_writable(struct lws *wsi)
682 {
683         wsi->parent_pending_cb_on_writable = 0;
684 }
685
686
687
688 LWS_VISIBLE LWS_EXTERN const char *
689 lws_get_vhost_name(struct lws_vhost *vhost)
690 {
691         return vhost->name;
692 }
693
694 LWS_VISIBLE LWS_EXTERN int
695 lws_get_vhost_port(struct lws_vhost *vhost)
696 {
697         return vhost->listen_port;
698 }
699
700 LWS_VISIBLE LWS_EXTERN void *
701 lws_get_vhost_user(struct lws_vhost *vhost)
702 {
703         return vhost->user;
704 }
705
706 LWS_VISIBLE LWS_EXTERN const char *
707 lws_get_vhost_iface(struct lws_vhost *vhost)
708 {
709         return vhost->iface;
710 }
711
712 LWS_VISIBLE lws_sockfd_type
713 lws_get_socket_fd(struct lws *wsi)
714 {
715         if (!wsi)
716                 return -1;
717         return wsi->desc.sockfd;
718 }
719
720
721 LWS_VISIBLE struct lws_vhost *
722 lws_vhost_get(struct lws *wsi)
723 {
724         return wsi->vhost;
725 }
726
727 LWS_VISIBLE struct lws_vhost *
728 lws_get_vhost(struct lws *wsi)
729 {
730         return wsi->vhost;
731 }
732
733 LWS_VISIBLE const struct lws_protocols *
734 lws_protocol_get(struct lws *wsi)
735 {
736         return wsi->protocol;
737 }
738
739 LWS_VISIBLE const struct lws_udp *
740 lws_get_udp(const struct lws *wsi)
741 {
742         return wsi->udp;
743 }
744
745 LWS_VISIBLE LWS_EXTERN struct lws_context *
746 lws_get_context(const struct lws *wsi)
747 {
748         return wsi->context;
749 }
750
751 #ifdef LWS_LATENCY
752 void
753 lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
754             int ret, int completed)
755 {
756         unsigned long long u;
757         char buf[256];
758
759         u = lws_now_usecs();
760
761         if (!action) {
762                 wsi->latency_start = u;
763                 if (!wsi->action_start)
764                         wsi->action_start = u;
765                 return;
766         }
767         if (completed) {
768                 if (wsi->action_start == wsi->latency_start)
769                         sprintf(buf,
770                           "Completion first try lat %lluus: %p: ret %d: %s\n",
771                                         u - wsi->latency_start,
772                                                       (void *)wsi, ret, action);
773                 else
774                         sprintf(buf,
775                           "Completion %lluus: lat %lluus: %p: ret %d: %s\n",
776                                 u - wsi->action_start,
777                                         u - wsi->latency_start,
778                                                       (void *)wsi, ret, action);
779                 wsi->action_start = 0;
780         } else
781                 sprintf(buf, "lat %lluus: %p: ret %d: %s\n",
782                               u - wsi->latency_start, (void *)wsi, ret, action);
783
784         if (u - wsi->latency_start > context->worst_latency) {
785                 context->worst_latency = u - wsi->latency_start;
786                 strcpy(context->worst_latency_info, buf);
787         }
788         lwsl_latency("%s", buf);
789 }
790 #endif
791
792 LWS_VISIBLE int LWS_WARN_UNUSED_RESULT
793 lws_raw_transaction_completed(struct lws *wsi)
794 {
795         if (lws_has_buffered_out(wsi)) {
796                 /*
797                  * ...so he tried to send something large, but it went out
798                  * as a partial, but he immediately called us to say he wants
799                  * to close the connection.
800                  *
801                  * Defer the close until the last part of the partial is sent.
802                  *
803                  */
804                 lwsl_debug("%s: %p: deferring due to partial\n", __func__, wsi);
805                 wsi->close_when_buffered_out_drained = 1;
806                 lws_callback_on_writable(wsi);
807
808                 return 0;
809         }
810
811         return -1;
812 }
813
814 int
815 lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
816                   const char *reason)
817 {
818 //      if (wsi->protocol == p)
819 //              return 0;
820         const struct lws_protocols *vp = wsi->vhost->protocols, *vpo;
821
822         if (wsi->protocol && wsi->protocol_bind_balance) {
823                 wsi->protocol->callback(wsi,
824                        wsi->role_ops->protocol_unbind_cb[!!lwsi_role_server(wsi)],
825                                         wsi->user_space, (void *)reason, 0);
826                 wsi->protocol_bind_balance = 0;
827         }
828         if (!wsi->user_space_externally_allocated)
829                 lws_free_set_NULL(wsi->user_space);
830
831         lws_same_vh_protocol_remove(wsi);
832
833         wsi->protocol = p;
834         if (!p)
835                 return 0;
836
837         if (lws_ensure_user_space(wsi))
838                 return 1;
839
840         if (p > vp && p < &vp[wsi->vhost->count_protocols])
841                 lws_same_vh_protocol_insert(wsi, (int)(p - vp));
842         else {
843                 int n = wsi->vhost->count_protocols;
844                 int hit = 0;
845
846                 vpo = vp;
847
848                 while (n--) {
849                         if (p->name && vp->name && !strcmp(p->name, vp->name)) {
850                                 hit = 1;
851                                 lws_same_vh_protocol_insert(wsi, (int)(vp - vpo));
852                                 break;
853                         }
854                         vp++;
855                 }
856                 if (!hit)
857                         lwsl_err("%s: %p is not in vhost '%s' protocols list\n",
858                                  __func__, p, wsi->vhost->name);
859         }
860
861         if (wsi->protocol->callback(wsi, wsi->role_ops->protocol_bind_cb[
862                                     !!lwsi_role_server(wsi)],
863                                     wsi->user_space, NULL, 0))
864                 return 1;
865
866         wsi->protocol_bind_balance = 1;
867
868         return 0;
869 }
870
871 int
872 lws_http_mark_sse(struct lws *wsi)
873 {
874         lws_http_headers_detach(wsi);
875         lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
876
877         if (wsi->http2_substream) {
878                 struct lws *nwsi = lws_get_network_wsi(wsi);
879
880                 wsi->h2_stream_carries_sse = 1;
881                 nwsi->immortal_substream_count++;
882                 if (nwsi->immortal_substream_count == 1)
883                         lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
884         }
885
886         return 0;
887 }