iodine 0.2.17 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +36 -3
  4. data/bin/config.ru +23 -2
  5. data/bin/http-hello +1 -1
  6. data/bin/ws-shootout +5 -0
  7. data/ext/iodine/defer.c +468 -0
  8. data/ext/iodine/defer.h +105 -0
  9. data/ext/iodine/evio.c +263 -0
  10. data/ext/iodine/evio.h +133 -0
  11. data/ext/iodine/extconf.rb +2 -1
  12. data/ext/iodine/facil.c +958 -0
  13. data/ext/iodine/facil.h +423 -0
  14. data/ext/iodine/http.c +90 -0
  15. data/ext/iodine/http.h +50 -12
  16. data/ext/iodine/http1.c +200 -267
  17. data/ext/iodine/http1.h +17 -26
  18. data/ext/iodine/http1_request.c +81 -0
  19. data/ext/iodine/http1_request.h +58 -0
  20. data/ext/iodine/http1_response.c +403 -0
  21. data/ext/iodine/http1_response.h +90 -0
  22. data/ext/iodine/http1_simple_parser.c +124 -108
  23. data/ext/iodine/http1_simple_parser.h +8 -3
  24. data/ext/iodine/http_request.c +104 -0
  25. data/ext/iodine/http_request.h +58 -102
  26. data/ext/iodine/http_response.c +212 -208
  27. data/ext/iodine/http_response.h +89 -252
  28. data/ext/iodine/iodine_core.c +57 -46
  29. data/ext/iodine/iodine_core.h +3 -1
  30. data/ext/iodine/iodine_http.c +105 -81
  31. data/ext/iodine/iodine_websocket.c +17 -13
  32. data/ext/iodine/iodine_websocket.h +1 -0
  33. data/ext/iodine/rb-call.c +9 -7
  34. data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
  35. data/ext/iodine/rb-rack-io.c +12 -6
  36. data/ext/iodine/rb-rack-io.h +1 -1
  37. data/ext/iodine/rb-registry.c +5 -2
  38. data/ext/iodine/sock.c +1159 -0
  39. data/ext/iodine/{libsock.h → sock.h} +138 -142
  40. data/ext/iodine/spnlock.inc +77 -0
  41. data/ext/iodine/websockets.c +101 -112
  42. data/ext/iodine/websockets.h +38 -19
  43. data/iodine.gemspec +3 -3
  44. data/lib/iodine/version.rb +1 -1
  45. data/lib/rack/handler/iodine.rb +6 -6
  46. metadata +23 -19
  47. data/ext/iodine/http_response_http1.h +0 -382
  48. data/ext/iodine/libasync.c +0 -570
  49. data/ext/iodine/libasync.h +0 -122
  50. data/ext/iodine/libreact.c +0 -350
  51. data/ext/iodine/libreact.h +0 -244
  52. data/ext/iodine/libserver.c +0 -957
  53. data/ext/iodine/libserver.h +0 -481
  54. data/ext/iodine/libsock.c +0 -1025
  55. data/ext/iodine/spnlock.h +0 -243
@@ -4,13 +4,16 @@ license: MIT
4
4
 
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
- #include "websockets.h"
7
+ #include "spnlock.inc"
8
+
8
9
  #include "bscrypt.h"
9
- #include "libserver.h"
10
+ #include "websockets.h"
10
11
  #include <arpa/inet.h>
12
+ #include <errno.h>
11
13
  #include <stdio.h>
12
14
  #include <stdlib.h>
13
15
  #include <string.h>
16
+ #include <strings.h>
14
17
 
15
18
  #if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
16
19
  #include <endian.h>
@@ -161,13 +164,8 @@ The Websocket Protocol implementation
161
164
 
162
165
  static void ws_ping(intptr_t fd, protocol_s *ws) {
163
166
  (void)(ws);
164
- sock_packet_s *packet;
165
- while ((packet = sock_checkout_packet()) == NULL)
166
- sock_flush_all();
167
- *packet = (sock_packet_s){
168
- .buffer = "\x89\x00", .length = 2, .metadata.urgent = 1,
169
- };
170
- sock_send_packet(fd, packet);
167
+ sock_write2(.uuid = fd, .buffer = "\x89\x00", .length = 2, .move = 1,
168
+ .dealloc = SOCK_DEALLOC_NOOP);
171
169
  }
172
170
 
173
171
  static void on_close(protocol_s *_ws) { destroy_ws((ws_s *)_ws); }
@@ -178,11 +176,11 @@ static void on_ready(intptr_t fduuid, protocol_s *ws) {
178
176
  ((ws_s *)ws)->on_ready((ws_s *)ws);
179
177
  }
180
178
 
181
- static void on_open(intptr_t fd, protocol_s *ws, void *callback) {
182
- (void)(fd);
183
- if (callback && ws && ws->service == WEBSOCKET_ID_STR)
184
- ((void (*)(void *))callback)(ws);
185
- }
179
+ // static void on_open(intptr_t fd, protocol_s *ws, void *callback) {
180
+ // (void)(fd);
181
+ // if (callback && ws && ws->service == WEBSOCKET_ID_STR)
182
+ // ((void (*)(void *))callback)(ws);
183
+ // }
186
184
 
187
185
  static void on_shutdown(intptr_t fd, protocol_s *ws) {
188
186
  (void)(fd);
@@ -579,21 +577,25 @@ static void websocket_write_impl(intptr_t fd, void *data, size_t len,
579
577
  char text, /* TODO: add client masking */
580
578
  char first, char last, char client) {
581
579
  if (len < 126) {
582
- char buff[len + (client ? 6 : 2)];
583
- len = websocket_encode(buff, data, len, text, first, last, client);
584
- sock_write(fd, buff, len);
580
+ sock_buffer_s *sbuff = sock_buffer_checkout();
581
+ sbuff->len =
582
+ websocket_encode(sbuff->buf, data, len, text, first, last, client);
583
+ sock_buffer_send(fd, sbuff);
584
+ // // was:
585
+ // char buff[len + (client ? 6 : 2)];
586
+ // len = websocket_encode(buff, data, len, text, first, last, client);
587
+ // sock_write(fd, buff, len);
585
588
  } else if (len <= WS_MAX_FRAME_SIZE) {
586
- if (len >= BUFFER_PACKET_SIZE) { // if len is larger then a single packet.
589
+ if (len >= BUFFER_PACKET_SIZE - 8) { // can't feet in sock buffer
587
590
  /* head MUST be 4 bytes */
588
591
  void *buff = malloc(len + 4);
589
592
  len = websocket_encode(buff, data, len, text, first, last, client);
590
- sock_write2(.fduuid = fd, .buffer = buff, .length = len, .move = 1);
593
+ sock_write2(.uuid = fd, .buffer = buff, .length = len, .move = 1);
591
594
  } else {
592
- sock_packet_s *packet = sock_checkout_packet();
593
- packet->length = websocket_encode(packet->buffer, data, len, text, first,
594
- last, client);
595
- packet->metadata.can_interrupt = 1;
596
- sock_send_packet(fd, packet);
595
+ sock_buffer_s *sbuff = sock_buffer_checkout();
596
+ sbuff->len =
597
+ websocket_encode(sbuff->buf, data, len, text, first, last, client);
598
+ sock_buffer_send(fd, sbuff);
597
599
  }
598
600
  } else {
599
601
  /* frame fragmentation is better for large data then large frames */
@@ -617,8 +619,6 @@ The API implementation
617
619
  ssize_t websocket_upgrade(websocket_settings_s settings) {
618
620
  // A static data used for all websocket connections.
619
621
  static char ws_key_accpt_str[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
620
- // a temporary response object, in case none is provided.
621
- http_response_s tmp_response;
622
622
  // require either a request or a response.
623
623
  if (((uintptr_t)settings.request | (uintptr_t)settings.response) ==
624
624
  (uintptr_t)NULL)
@@ -631,23 +631,21 @@ ssize_t websocket_upgrade(websocket_settings_s settings) {
631
631
  http_response_s *response = settings.response;
632
632
  if (response == NULL) {
633
633
  /* initialize a default upgrade response */
634
- tmp_response = http_response_init(settings.request);
635
- response = &tmp_response;
634
+ response = http_response_create(settings.request);
636
635
  } else
637
- settings.request = response->metadata.request;
636
+ settings.request = response->request;
638
637
  // allocate the protocol object (TODO: (maybe) pooling)
639
638
  ws_s *ws = new_websocket();
640
639
  if (!ws)
641
640
  goto refuse;
642
641
 
643
642
  // setup the socket-server data
644
- ws->fd = response->metadata.request->metadata.fd;
643
+ ws->fd = response->request->fd;
645
644
  // Setup ws callbacks
646
645
  ws->on_close = settings.on_close;
647
646
  ws->on_message = settings.on_message;
648
647
  ws->on_ready = settings.on_ready;
649
648
  ws->on_shutdown = settings.on_shutdown;
650
-
651
649
  // setup any user data
652
650
  ws->udata = settings.udata;
653
651
  // buffer limits
@@ -655,17 +653,15 @@ ssize_t websocket_upgrade(websocket_settings_s settings) {
655
653
  const char *recv_str;
656
654
 
657
655
  recv_str =
658
- http_request_find_header(settings.request, "sec-websocket-version", 21);
656
+ http_request_header_find(settings.request, "sec-websocket-version", 21)
657
+ .value;
659
658
  if (recv_str == NULL || recv_str[0] != '1' || recv_str[1] != '3')
660
659
  goto refuse;
661
660
 
662
- recv_str =
663
- http_request_find_header(settings.request, "sec-websocket-key", 17);
664
- if (recv_str == NULL)
661
+ http_header_s sec_h =
662
+ http_request_header_find(settings.request, "sec-websocket-key", 17);
663
+ if (sec_h.value == NULL)
665
664
  goto refuse;
666
- size_t recv_len =
667
- settings.request->headers[settings.request->metadata.headers_pos]
668
- .value_length;
669
665
 
670
666
  // websocket extentions (none)
671
667
 
@@ -674,7 +670,7 @@ ssize_t websocket_upgrade(websocket_settings_s settings) {
674
670
  // use the SHA1 methods provided to concat the client string and hash
675
671
  sha1_s sha1;
676
672
  sha1 = bscrypt_sha1_init();
677
- bscrypt_sha1_write(&sha1, recv_str, recv_len);
673
+ bscrypt_sha1_write(&sha1, sec_h.value, sec_h.value_len);
678
674
  bscrypt_sha1_write(&sha1, ws_key_accpt_str, sizeof(ws_key_accpt_str) - 1);
679
675
  // base encode the data
680
676
  char websockets_key[32];
@@ -686,20 +682,19 @@ ssize_t websocket_upgrade(websocket_settings_s settings) {
686
682
  // upgrade taking place, make sure the upgrade headers are valid for the
687
683
  // response.
688
684
  response->status = 101;
689
- http_response_write_header(response, .name = "Connection", .name_length = 10,
690
- .value = "Upgrade", .value_length = 7);
691
- http_response_write_header(response, .name = "Upgrade", .name_length = 7,
692
- .value = "websocket", .value_length = 9);
685
+ http_response_write_header(response, .name = "Connection", .name_len = 10,
686
+ .value = "Upgrade", .value_len = 7);
687
+ http_response_write_header(response, .name = "Upgrade", .name_len = 7,
688
+ .value = "websocket", .value_len = 9);
693
689
  http_response_write_header(response, .name = "sec-websocket-version",
694
- .name_length = 21, .value = "13",
695
- .value_length = 2);
690
+ .name_len = 21, .value = "13", .value_len = 2);
696
691
  // set the string's length and encoding
697
692
  http_response_write_header(response, .name = "Sec-WebSocket-Accept",
698
- .name_length = 20, .value = websockets_key,
699
- .value_length = len);
700
- // inform about 0 extension support
701
- recv_str = http_request_find_header(settings.request,
702
- "sec-websocket-extensions", 24);
693
+ .name_len = 20, .value = websockets_key,
694
+ .value_len = len);
695
+ // // inform about 0 extension support
696
+ // sec_h = http_request_header_find(settings.request,
697
+ // "sec-websocket-extensions", 24);
703
698
  // if (recv_str != NULL)
704
699
  // http_response_write_header(response, .name =
705
700
  // "Sec-Websocket-Extensions",
@@ -711,21 +706,19 @@ refuse:
711
706
  response->status = 400;
712
707
  cleanup:
713
708
  if (response->status == 101) {
714
- // set the protocol lock
715
- ws->protocol.callback_lock = SPN_LOCK_INIT;
716
- spn_lock(&ws->protocol.callback_lock);
717
709
  // send the response
718
710
  http_response_finish(response);
719
- // update the protocol object, cleanning up the old one
720
- server_switch_protocol(ws->fd, (void *)ws);
721
711
  // we have an active websocket connection - prep the connection buffer
722
712
  ws->buffer = create_ws_buffer(ws);
723
713
  // update the timeout
724
- server_set_timeout(ws->fd, settings.timeout);
714
+ facil_set_timeout(ws->fd, settings.timeout);
725
715
  // call the on_open callback
726
716
  if (settings.on_open)
727
- server_task(ws->fd, on_open, (void *)settings.on_open, NULL);
728
- spn_unlock(&ws->protocol.callback_lock);
717
+ settings.on_open(ws);
718
+ // facil_defer(.uuid = ws->fd, .task = on_open,
719
+ // .arg = (void *)settings.on_open);
720
+ // update the protocol object, cleanning up the old one
721
+ facil_attach(ws->fd, (protocol_s *)ws);
729
722
  return 0;
730
723
  }
731
724
  http_response_finish(response);
@@ -736,12 +729,12 @@ cleanup:
736
729
  websocket_upgrade((websocket_settings_s){__VA_ARGS__})
737
730
 
738
731
  /** Returns the opaque user data associated with the websocket. */
739
- void *websocket_get_udata(ws_s *ws) { return ws->udata; }
732
+ void *websocket_udata(ws_s *ws) { return ws->udata; }
740
733
  /** Returns the the process specific connection's UUID (see `libsock`). */
741
- intptr_t websocket_get_fduuid(ws_s *ws) { return ws->fd; }
734
+ intptr_t websocket_uuid(ws_s *ws) { return ws->fd; }
742
735
  /** Sets the opaque user data associated with the websocket.
743
736
  * Returns the old value, if any. */
744
- void *websocket_set_udata(ws_s *ws, void *udata) {
737
+ void *websocket_udata_set(ws_s *ws, void *udata) {
745
738
  void *old = ws->udata;
746
739
  ws->udata = udata;
747
740
  return old;
@@ -756,13 +749,8 @@ int websocket_write(ws_s *ws, void *data, size_t size, uint8_t is_text) {
756
749
  }
757
750
  /** Closes a websocket connection. */
758
751
  void websocket_close(ws_s *ws) {
759
- sock_packet_s *packet;
760
- while ((packet = sock_checkout_packet()) == NULL)
761
- sock_flush_all();
762
- *packet = (sock_packet_s){
763
- .buffer = "\x88\x00", .length = 2,
764
- };
765
- sock_send_packet(ws->fd, packet);
752
+ sock_write2(.uuid = ws->fd, .buffer = "\x88\x00", .length = 2, .move = 1,
753
+ .dealloc = SOCK_DEALLOC_NOOP);
766
754
  sock_close(ws->fd);
767
755
  return;
768
756
  }
@@ -770,10 +758,7 @@ void websocket_close(ws_s *ws) {
770
758
  /**
771
759
  Counts the number of websocket connections.
772
760
  */
773
- size_t websocket_count(ws_s *ws) {
774
- (void)(ws);
775
- return server_count(WEBSOCKET_ID_STR);
776
- }
761
+ size_t websocket_count(void) { return facil_count(WEBSOCKET_ID_STR); }
777
762
 
778
763
  /*******************************************************************************
779
764
  Each Implementation
@@ -787,17 +772,24 @@ struct WSTask {
787
772
  };
788
773
  /** Performs a task on each websocket connection that shares the same process
789
774
  */
790
- static void perform_ws_task(intptr_t fd, protocol_s *_ws, void *_arg) {
775
+ static void perform_ws_task(intptr_t fd, protocol_s *ws_, void *tsk_) {
791
776
  (void)(fd);
792
- struct WSTask *tsk = _arg;
793
- tsk->task((ws_s *)(_ws), tsk->arg);
777
+ struct WSTask *tsk = tsk_;
778
+ tsk->task((ws_s *)(ws_), tsk->arg);
794
779
  }
795
780
  /** clears away a wesbocket task. */
796
- static void finish_ws_task(intptr_t fd, protocol_s *_ws, void *_arg) {
797
- (void)(fd);
798
- struct WSTask *tsk = _arg;
799
- if (tsk->on_finish)
800
- tsk->on_finish((ws_s *)(_ws), tsk->arg);
781
+ static void finish_ws_task(intptr_t fd, void *arg) {
782
+ struct WSTask *tsk = arg;
783
+ if (tsk->on_finish) {
784
+ protocol_s *ws = facil_protocol_try_lock(fd, FIO_PR_LOCK_TASK);
785
+ if (!ws && errno != EBADF) {
786
+ defer((void (*)(void *, void *))finish_ws_task, (void *)fd, arg);
787
+ return;
788
+ }
789
+ tsk->on_finish((ws_s *)ws, tsk->arg);
790
+ if (ws)
791
+ facil_protocol_unlock(ws, FIO_PR_LOCK_TASK);
792
+ }
801
793
  free(tsk);
802
794
  }
803
795
 
@@ -805,15 +797,15 @@ static void finish_ws_task(intptr_t fd, protocol_s *_ws, void *_arg) {
805
797
  Performs a task on each websocket connection that shares the same process
806
798
  (except the originating `ws_s` connection which is allowed to be NULL).
807
799
  */
808
- void websocket_each(ws_s *ws_originator,
809
- void (*task)(ws_s *ws_target, void *arg), void *arg,
810
- void (*on_finish)(ws_s *ws_originator, void *arg)) {
800
+ #undef websocket_each
801
+ void websocket_each(struct websocket_each_args_s args) {
811
802
  struct WSTask *tsk = malloc(sizeof(*tsk));
812
- tsk->arg = arg;
813
- tsk->on_finish = on_finish;
814
- tsk->task = task;
815
- server_each((ws_originator ? ws_originator->fd : -1), WEBSOCKET_ID_STR,
816
- perform_ws_task, tsk, finish_ws_task);
803
+ tsk->arg = args.arg;
804
+ tsk->on_finish = args.on_finish;
805
+ tsk->task = args.task;
806
+ facil_each(.origin = (args.origin ? args.origin->fd : -1),
807
+ .service = WEBSOCKET_ID_STR, .task = perform_ws_task, .arg = tsk,
808
+ .on_complete = finish_ws_task);
817
809
  }
818
810
  /*******************************************************************************
819
811
  Multi-Write (direct broadcast) Implementation
@@ -835,14 +827,16 @@ struct websocket_multi_write {
835
827
  static void ws_mw_defered_on_finish_fb(intptr_t fd, void *arg) {
836
828
  (void)(fd);
837
829
  struct websocket_multi_write *fin = arg;
838
- fin->on_finished(NULL, fin->arg);
830
+ if (fin->on_finished)
831
+ fin->on_finished(NULL, fin->arg);
839
832
  free(fin);
840
833
  }
841
834
  static void ws_mw_defered_on_finish(intptr_t fd, protocol_s *ws, void *arg) {
842
- (void)(fd);
835
+ (void)fd;
843
836
  struct websocket_multi_write *fin = arg;
844
- fin->on_finished((ws->service == WEBSOCKET_ID_STR ? (ws_s *)ws : NULL),
845
- fin->arg);
837
+ if (fin->on_finished) {
838
+ fin->on_finished((ws_s *)ws, fin->arg);
839
+ }
846
840
  free(fin);
847
841
  }
848
842
 
@@ -853,18 +847,18 @@ static void ws_reduce_or_free_multi_write(void *buff) {
853
847
  if (!mw->count) {
854
848
  spn_unlock(&mw->lock);
855
849
  if (mw->on_finished) {
856
- server_task(mw->origin, ws_mw_defered_on_finish, mw,
857
- ws_mw_defered_on_finish_fb);
850
+ facil_defer(.uuid = mw->origin, .task = ws_mw_defered_on_finish,
851
+ .arg = mw, .fallback = ws_mw_defered_on_finish_fb,
852
+ .task_type = FIO_PR_LOCK_WRITE);
858
853
  } else
859
854
  free(mw);
860
855
  } else
861
856
  spn_unlock(&mw->lock);
862
857
  }
863
858
 
864
- static void ws_finish_multi_write(intptr_t fd, protocol_s *_ws, void *arg) {
859
+ static void ws_finish_multi_write(intptr_t fd, void *arg) {
865
860
  struct websocket_multi_write *multi = arg;
866
861
  (void)(fd);
867
- (void)(_ws);
868
862
  ws_reduce_or_free_multi_write(multi->buffer);
869
863
  }
870
864
 
@@ -872,21 +866,11 @@ static void ws_direct_multi_write(intptr_t fd, protocol_s *_ws, void *arg) {
872
866
  struct websocket_multi_write *multi = arg;
873
867
  if (((ws_s *)(_ws))->parser.client != multi->as_client)
874
868
  return;
875
-
876
- sock_packet_s *packet = sock_checkout_packet();
877
- *packet = (sock_packet_s){
878
- .buffer = multi->buffer,
879
- .length = multi->length,
880
- .metadata.can_interrupt = 1,
881
- .metadata.dealloc = ws_reduce_or_free_multi_write,
882
- .metadata.external = 1,
883
- };
884
-
885
869
  spn_lock(&multi->lock);
886
870
  multi->count += 1;
887
871
  spn_unlock(&multi->lock);
888
-
889
- sock_send_packet(fd, packet);
872
+ sock_write2(.uuid = fd, .buffer = multi->buffer, .length = multi->length,
873
+ .dealloc = ws_reduce_or_free_multi_write, .move = 1);
890
874
  }
891
875
 
892
876
  static void ws_check_multi_write(intptr_t fd, protocol_s *_ws, void *arg) {
@@ -903,8 +887,11 @@ int websocket_write_each(struct websocket_write_each_args_s args) {
903
887
  return -1;
904
888
  struct websocket_multi_write *multi =
905
889
  malloc(sizeof(*multi) + args.length + 16 /* max head size + 2 */);
906
- if (!multi)
890
+ if (!multi) {
891
+ if (args.on_finished)
892
+ defer((void (*)(void *, void *))args.on_finished, NULL, args.arg);
907
893
  return -1;
894
+ }
908
895
  *multi = (struct websocket_multi_write){
909
896
  .length = websocket_encode(multi->buffer, args.data, args.length,
910
897
  args.is_text, 1, 1, args.as_client),
@@ -917,8 +904,10 @@ int websocket_write_each(struct websocket_write_each_args_s args) {
917
904
  .count = 1,
918
905
  };
919
906
 
920
- server_each(multi->origin, WEBSOCKET_ID_STR,
921
- (args.filter ? ws_check_multi_write : ws_direct_multi_write),
922
- multi, ws_finish_multi_write);
907
+ facil_each(.origin = multi->origin, .service = WEBSOCKET_ID_STR,
908
+ .task_type = FIO_PR_LOCK_WRITE,
909
+ .task =
910
+ (args.filter ? ws_check_multi_write : ws_direct_multi_write),
911
+ .arg = multi, .on_complete = ws_finish_multi_write);
923
912
  return 0;
924
913
  }
@@ -7,8 +7,7 @@ Feel free to copy, use and enjoy according to the license provided.
7
7
  #ifndef WEBSOCKETS_H
8
8
  #define WEBSOCKETS_H
9
9
 
10
- #include "http_request.h"
11
- #include "http_response.h"
10
+ #include "http.h"
12
11
 
13
12
  /**
14
13
  The Websocket type is an opaque type used by the websocket API to provide
@@ -40,8 +39,8 @@ typedef struct {
40
39
  void (*on_message)(ws_s *ws, char *data, size_t size, uint8_t is_text);
41
40
  /**
42
41
  The (optional) on_open callback will be called once the websocket connection
43
- is
44
- established.
42
+ is established and before is is registered with `facil`, so no `on_message`
43
+ events are raised before `on_open` returns.
45
44
  */
46
45
  void (*on_open)(ws_s *ws);
47
46
  /**
@@ -111,23 +110,47 @@ ssize_t websocket_upgrade(websocket_settings_s settings);
111
110
  websocket_upgrade((websocket_settings_s){__VA_ARGS__})
112
111
 
113
112
  /** Returns the opaque user data associated with the websocket. */
114
- void *websocket_get_udata(ws_s *ws);
115
- /** Returns the the process specific connection's UUID (see `libsock`). */
116
- intptr_t websocket_get_fduuid(ws_s *ws);
117
- /** Sets the opaque user data associated with the websocket.
118
- * Returns the old value, if any. */
119
- void *websocket_set_udata(ws_s *ws, void *udata);
113
+ void *websocket_udata(ws_s *ws);
114
+ /**
115
+ Returns the underlying socket UUID.
116
+
117
+ This is only relevant for collecting the protocol object from outside of
118
+ websocket events, as the socket shouldn't be written to.
119
+ */
120
+ intptr_t websocket_uuid(ws_s *ws);
121
+ /**
122
+ Sets the opaque user data associated with the websocket.
123
+
124
+ Returns the old value, if any.
125
+ */
126
+ void *websocket_udata_set(ws_s *ws, void *udata);
120
127
  /** Writes data to the websocket. Returns -1 on failure (0 on success). */
121
128
  int websocket_write(ws_s *ws, void *data, size_t size, uint8_t is_text);
122
129
  /** Closes a websocket connection. */
123
130
  void websocket_close(ws_s *ws);
124
131
  /**
132
+ Counts the number of websocket connections.
133
+ */
134
+ size_t websocket_count(void);
135
+
136
+ /** The named arguments for `websocket_each` */
137
+ struct websocket_each_args_s {
138
+ /** The websocket originating the task. It will be excluded for the loop. */
139
+ ws_s *origin;
140
+ /** The task (function) to be performed. This is required. */
141
+ void (*task)(ws_s *ws_target, void *arg);
142
+ /** User opaque data to be passed along. */
143
+ void *arg;
144
+ /** The on_finish callback is always called. Good for cleanup. */
145
+ void (*on_finish)(ws_s *origin, void *arg);
146
+ };
147
+ /**
125
148
  Performs a task on each websocket connection that shares the same process
126
149
  (except the originating `ws_s` connection which is allowed to be NULL).
127
150
  */
128
- void websocket_each(ws_s *ws_originator,
129
- void (*task)(ws_s *ws_target, void *arg), void *arg,
130
- void (*on_finish)(ws_s *ws_originator, void *arg));
151
+ void websocket_each(struct websocket_each_args_s args);
152
+ #define websocket_each(...) \
153
+ websocket_each((struct websocket_each_args_s){__VA_ARGS__})
131
154
 
132
155
  /**
133
156
  The Arguments passed to the `websocket_write_each` function / macro are defined
@@ -135,7 +158,7 @@ here, for convinience of calling the function.
135
158
  */
136
159
  struct websocket_write_each_args_s {
137
160
  /** The originating websocket client will be excluded from the `write`.
138
- * Can be NULL. */
161
+ * Can be NULL. */
139
162
  ws_s *origin;
140
163
  /** The data to be written to the websocket - required(!) */
141
164
  void *data;
@@ -151,7 +174,7 @@ struct websocket_write_each_args_s {
151
174
  * Should return 1 to send data and 0 to exclude. */
152
175
  uint8_t (*filter)(ws_s *ws_to, void *arg);
153
176
  /** A callback called once all the data was sent. */
154
- void (*on_finished)(ws_s *ws_to, void *arg);
177
+ void (*on_finished)(ws_s *ws_origin, void *arg);
155
178
  /** A user specified argumernt passed to each of the callbacks. */
156
179
  void *arg;
157
180
  };
@@ -165,9 +188,5 @@ details for possible arguments.
165
188
  int websocket_write_each(struct websocket_write_each_args_s args);
166
189
  #define websocket_write_each(...) \
167
190
  websocket_write_each((struct websocket_write_each_args_s){__VA_ARGS__})
168
- /**
169
- Counts the number of websocket connections.
170
- */
171
- size_t websocket_count(ws_s *ws);
172
191
 
173
192
  #endif