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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +36 -3
- data/bin/config.ru +23 -2
- data/bin/http-hello +1 -1
- data/bin/ws-shootout +5 -0
- data/ext/iodine/defer.c +468 -0
- data/ext/iodine/defer.h +105 -0
- data/ext/iodine/evio.c +263 -0
- data/ext/iodine/evio.h +133 -0
- data/ext/iodine/extconf.rb +2 -1
- data/ext/iodine/facil.c +958 -0
- data/ext/iodine/facil.h +423 -0
- data/ext/iodine/http.c +90 -0
- data/ext/iodine/http.h +50 -12
- data/ext/iodine/http1.c +200 -267
- data/ext/iodine/http1.h +17 -26
- data/ext/iodine/http1_request.c +81 -0
- data/ext/iodine/http1_request.h +58 -0
- data/ext/iodine/http1_response.c +403 -0
- data/ext/iodine/http1_response.h +90 -0
- data/ext/iodine/http1_simple_parser.c +124 -108
- data/ext/iodine/http1_simple_parser.h +8 -3
- data/ext/iodine/http_request.c +104 -0
- data/ext/iodine/http_request.h +58 -102
- data/ext/iodine/http_response.c +212 -208
- data/ext/iodine/http_response.h +89 -252
- data/ext/iodine/iodine_core.c +57 -46
- data/ext/iodine/iodine_core.h +3 -1
- data/ext/iodine/iodine_http.c +105 -81
- data/ext/iodine/iodine_websocket.c +17 -13
- data/ext/iodine/iodine_websocket.h +1 -0
- data/ext/iodine/rb-call.c +9 -7
- data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
- data/ext/iodine/rb-rack-io.c +12 -6
- data/ext/iodine/rb-rack-io.h +1 -1
- data/ext/iodine/rb-registry.c +5 -2
- data/ext/iodine/sock.c +1159 -0
- data/ext/iodine/{libsock.h → sock.h} +138 -142
- data/ext/iodine/spnlock.inc +77 -0
- data/ext/iodine/websockets.c +101 -112
- data/ext/iodine/websockets.h +38 -19
- data/iodine.gemspec +3 -3
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +6 -6
- metadata +23 -19
- data/ext/iodine/http_response_http1.h +0 -382
- data/ext/iodine/libasync.c +0 -570
- data/ext/iodine/libasync.h +0 -122
- data/ext/iodine/libreact.c +0 -350
- data/ext/iodine/libreact.h +0 -244
- data/ext/iodine/libserver.c +0 -957
- data/ext/iodine/libserver.h +0 -481
- data/ext/iodine/libsock.c +0 -1025
- data/ext/iodine/spnlock.h +0 -243
data/ext/iodine/websockets.c
CHANGED
@@ -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 "
|
7
|
+
#include "spnlock.inc"
|
8
|
+
|
8
9
|
#include "bscrypt.h"
|
9
|
-
#include "
|
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
|
-
|
165
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
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
|
-
|
583
|
-
len =
|
584
|
-
|
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) { //
|
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(.
|
593
|
+
sock_write2(.uuid = fd, .buffer = buff, .length = len, .move = 1);
|
591
594
|
} else {
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
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
|
-
|
635
|
-
response = &tmp_response;
|
634
|
+
response = http_response_create(settings.request);
|
636
635
|
} else
|
637
|
-
settings.request = response->
|
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->
|
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
|
-
|
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
|
-
|
663
|
-
|
664
|
-
if (
|
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,
|
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", .
|
690
|
-
.value = "Upgrade", .
|
691
|
-
http_response_write_header(response, .name = "Upgrade", .
|
692
|
-
.value = "websocket", .
|
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
|
-
.
|
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
|
-
.
|
699
|
-
.
|
700
|
-
// inform about 0 extension support
|
701
|
-
|
702
|
-
|
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
|
-
|
714
|
+
facil_set_timeout(ws->fd, settings.timeout);
|
725
715
|
// call the on_open callback
|
726
716
|
if (settings.on_open)
|
727
|
-
|
728
|
-
|
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 *
|
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
|
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 *
|
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
|
-
|
760
|
-
|
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(
|
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 *
|
775
|
+
static void perform_ws_task(intptr_t fd, protocol_s *ws_, void *tsk_) {
|
791
776
|
(void)(fd);
|
792
|
-
struct WSTask *tsk =
|
793
|
-
tsk->task((ws_s *)(
|
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,
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
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
|
-
|
809
|
-
|
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
|
-
|
816
|
-
|
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
|
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)
|
835
|
+
(void)fd;
|
843
836
|
struct websocket_multi_write *fin = arg;
|
844
|
-
fin->on_finished
|
845
|
-
|
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
|
-
|
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,
|
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
|
-
|
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
|
-
|
921
|
-
|
922
|
-
|
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
|
}
|
data/ext/iodine/websockets.h
CHANGED
@@ -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 "
|
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
|
-
|
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 *
|
115
|
-
/**
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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(
|
129
|
-
|
130
|
-
|
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
|
-
|
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 *
|
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
|