X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/d3f01ce7bfbe5cfc2069f1d326d3b583e68029bc..1f8c7ce5ca3ca09092ecce0efe73f2bd7bbc424b:/wsockd/wsockd.c diff --git a/wsockd/wsockd.c b/wsockd/wsockd.c index e17eec47..66fa4efc 100644 --- a/wsockd/wsockd.c +++ b/wsockd/wsockd.c @@ -1,8 +1,8 @@ /* - * wsockd.c: charybdis websockets helper + * wsockd.c: solanum websockets helper * Copyright (C) 2007 Aaron Sethman * Copyright (C) 2007 ircd-ratbox development team - * Copyright (C) 2016 William Pitcock + * Copyright (C) 2016 Ariadne Conill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,12 +95,7 @@ typedef struct _conn char client_key[37]; /* maximum 36 bytes + nul */ } conn_t; -#define WEBSOCKET_OPCODE_CONTINUATION_FRAME 0 #define WEBSOCKET_OPCODE_TEXT_FRAME 1 -#define WEBSOCKET_OPCODE_BINARY_FRAME 2 -#define WEBSOCKET_OPCODE_CLOSE_FRAME 8 -#define WEBSOCKET_OPCODE_PING_FRAME 9 -#define WEBSOCKET_OPCODE_PONG_FRAME 10 #define WEBSOCKET_MASK_LENGTH 4 @@ -111,6 +106,8 @@ typedef struct { uint8_t payload_length_mask; // payload_length: 7, mask: 1 } ws_frame_hdr_t; +#define WEBSOCKET_FRAME_HDR_INIT ((ws_frame_hdr_t) { 0, 0 }) + typedef struct { ws_frame_hdr_t header; uint8_t payload_data[WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH]; @@ -125,17 +122,13 @@ typedef struct { uint16_t payload_length_extended; } ws_frame_ext_t; +#define WEBSOCKET_FRAME_EXT_INIT ((ws_frame_ext_t) { WEBSOCKET_FRAME_HDR_INIT, 0 }) + typedef struct { ws_frame_hdr_t header; uint64_t payload_length_extended; } ws_frame_ext2_t; -static inline int -ws_frame_get_opcode(ws_frame_hdr_t *header) -{ - return header->opcode_rsv_fin & 0xF; -} - static inline void ws_frame_set_opcode(ws_frame_hdr_t *header, int opcode) { @@ -143,12 +136,6 @@ ws_frame_set_opcode(ws_frame_hdr_t *header, int opcode) header->opcode_rsv_fin |= opcode & 0xF; } -static inline int -ws_frame_get_fin(ws_frame_hdr_t *header) -{ - return (header->opcode_rsv_fin >> 7) & 0x1; -} - static inline void ws_frame_set_fin(ws_frame_hdr_t *header, int fin) { @@ -156,28 +143,6 @@ ws_frame_set_fin(ws_frame_hdr_t *header, int fin) header->opcode_rsv_fin |= (fin << 7) & (0x1 << 7); } -#ifdef _WIN32 -char * -strcasestr(const char *s, const char *find) -{ - char c, sc; - size_t len; - - if ((c = *find++) != 0) { - c = tolower((unsigned char)c); - len = strlen(find); - do { - do { - if ((sc = *s++) == 0) - return (NULL); - } while ((char)tolower((unsigned char)sc) != c); - } while (strnicmp(s, find, len) != 0); - s--; - } - return ((char *)s); -} -#endif - static void close_conn(conn_t * conn, int wait_plain, const char *fmt, ...); static void conn_mod_read_cb(rb_fde_t *fd, void *data); static void conn_plain_read_cb(rb_fde_t *fd, void *data); @@ -190,7 +155,6 @@ static void conn_plain_process_recvq(conn_t *conn); #define IsCork(x) ((x)->flags & FLAG_CORK) #define IsDead(x) ((x)->flags & FLAG_DEAD) -#define IsWS(x) ((x)->flags & FLAG_WSOCK) #define IsKeyed(x) ((x)->flags & FLAG_KEYED) #define SetCork(x) ((x)->flags |= FLAG_CORK) @@ -199,15 +163,10 @@ static void conn_plain_process_recvq(conn_t *conn); #define SetKeyed(x) ((x)->flags |= FLAG_KEYED) #define ClearCork(x) ((x)->flags &= ~FLAG_CORK) -#define ClearDead(x) ((x)->flags &= ~FLAG_DEAD) -#define ClearWS(x) ((x)->flags &= ~FLAG_WSOCK) -#define ClearKeyed(x) ((x)->flags &= ~FLAG_KEYED) #define NO_WAIT 0x0 #define WAIT_PLAIN 0x1 -#define HASH_WALK_SAFE(i, max, ptr, next, table) for(i = 0; i < max; i++) { RB_DLINK_FOREACH_SAFE(ptr, next, table[i].head) -#define HASH_WALK_END } #define CONN_HASH_SIZE 2000 #define connid_hash(x) (&connid_hash_table[(x % CONN_HASH_SIZE)]) @@ -218,18 +177,15 @@ static rb_dlink_list dead_list; static void conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data); -#ifndef _WIN32 static void dummy_handler(int sig) { return; } -#endif static void setup_signals() { -#ifndef _WIN32 struct sigaction act; act.sa_flags = 0; @@ -252,38 +208,20 @@ setup_signals() act.sa_handler = dummy_handler; sigaction(SIGALRM, &act, 0); -#endif } static int maxconn(void) { -#if defined(RLIMIT_NOFILE) && defined(HAVE_SYS_RESOURCE_H) struct rlimit limit; if(!getrlimit(RLIMIT_NOFILE, &limit)) { return limit.rlim_cur; } -#endif /* RLIMIT_FD_MAX */ return MAXCONNECTIONS; } -static conn_t * -conn_find_by_id(uint32_t id) -{ - rb_dlink_node *ptr; - conn_t *conn; - - RB_DLINK_FOREACH(ptr, (connid_hash(id))->head) - { - conn = ptr->data; - if(conn->id == id && !IsDead(conn)) - return conn; - } - return NULL; -} - static void conn_add_id_hash(conn_t * conn, uint32_t id) { @@ -318,6 +256,30 @@ clean_dead_conns(void *unused) dead_list.tail = dead_list.head = NULL; } +static void +conn_plain_write_sendq(rb_fde_t *fd, void *data) +{ + conn_t *conn = data; + int retlen; + + if(IsDead(conn)) + return; + + while((retlen = rb_linebuf_flush(fd, &conn->plainbuf_out)) > 0) + conn->plain_out += retlen; + + if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) + { + close_conn(data, NO_WAIT, NULL); + return; + } + + if(rb_linebuf_alloclen(&conn->plainbuf_out) > 0) + rb_setselect(conn->plain_fd, RB_SELECT_WRITE, conn_plain_write_sendq, conn); + else + rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL); +} + static void conn_mod_write_sendq(rb_fde_t *fd, void *data) { @@ -363,9 +325,10 @@ conn_mod_write(conn_t * conn, void *data, size_t len) static void conn_mod_write_short_frame(conn_t * conn, void *data, int len) { - ws_frame_hdr_t hdr; + ws_frame_hdr_t hdr = WEBSOCKET_FRAME_HDR_INIT; - ws_frame_set_opcode(&hdr, WEBSOCKET_OPCODE_BINARY_FRAME); + ws_frame_set_opcode(&hdr, WEBSOCKET_OPCODE_TEXT_FRAME); + ws_frame_set_fin(&hdr, 1); hdr.payload_length_mask = (len + 2) & 0x7f; conn_mod_write(conn, &hdr, sizeof(hdr)); @@ -376,9 +339,10 @@ conn_mod_write_short_frame(conn_t * conn, void *data, int len) static void conn_mod_write_long_frame(conn_t * conn, void *data, int len) { - ws_frame_ext_t hdr; + ws_frame_ext_t hdr = WEBSOCKET_FRAME_EXT_INIT; - ws_frame_set_opcode(&hdr.header, WEBSOCKET_OPCODE_BINARY_FRAME); + ws_frame_set_opcode(&hdr.header, WEBSOCKET_OPCODE_TEXT_FRAME); + ws_frame_set_fin(&hdr.header, 1); hdr.header.payload_length_mask = 126; hdr.payload_length_extended = htons(len + 2); @@ -394,17 +358,12 @@ conn_mod_write_frame(conn_t *conn, void *data, int len) return; if (len < 123) - return conn_mod_write_short_frame(conn, data, len); - - return conn_mod_write_long_frame(conn, data, len); -} - -static void -conn_plain_write(conn_t * conn, void *data, size_t len) -{ - if(IsDead(conn)) /* again no point in queueing to dead men */ + { + conn_mod_write_short_frame(conn, data, len); return; - rb_linebuf_put(&conn->plainbuf_out, data, len); + } + + conn_mod_write_long_frame(conn, data, len); } static void @@ -637,6 +596,8 @@ conn_mod_process(conn_t *conn) break; } } + + conn_plain_write_sendq(conn->plain_fd, conn); } static void @@ -654,7 +615,7 @@ conn_mod_handshake_process(conn_t *conn) if (!dolen) break; - if ((p = strcasestr(inbuf, "Sec-WebSocket-Key:")) != NULL) + if ((p = rb_strcasestr(inbuf, "Sec-WebSocket-Key:")) != NULL) { char *start, *end; @@ -725,10 +686,13 @@ conn_mod_read_cb(rb_fde_t *fd, void *data) length = rb_read(fd, inbuf, sizeof(inbuf)); - if (length < 0) + if (length < 0) { if (rb_ignore_errno(errno)) + { rb_setselect(fd, RB_SELECT_READ, conn_mod_read_cb, conn); + conn_plain_write_sendq(conn->plain_fd, conn); + } else close_conn(conn, NO_WAIT, "Connection closed"); @@ -746,7 +710,7 @@ conn_mod_read_cb(rb_fde_t *fd, void *data) else conn_mod_process(conn); - if (length < sizeof(inbuf)) + if ((size_t) length < sizeof(inbuf)) { rb_setselect(fd, RB_SELECT_READ, conn_mod_read_cb, conn); return; @@ -981,7 +945,7 @@ int main(int argc, char **argv) { const char *s_ctlfd, *s_pipe, *s_pid; - int ctlfd, pipefd, x, maxfd; + int ctlfd, pipefd, maxfd, x; maxfd = maxconn(); s_ctlfd = getenv("CTL_FD"); @@ -991,7 +955,7 @@ main(int argc, char **argv) if(s_ctlfd == NULL || s_pipe == NULL || s_pid == NULL) { fprintf(stderr, - "This is the charybdis wsockd for internal ircd use.\n"); + "This is the solanum wsockd for internal ircd use.\n"); fprintf(stderr, "You aren't supposed to run me directly. Exiting.\n"); exit(1); @@ -1000,8 +964,7 @@ main(int argc, char **argv) ctlfd = atoi(s_ctlfd); pipefd = atoi(s_pipe); ppid = atoi(s_pid); - x = 0; -#ifndef _WIN32 + for(x = 0; x < maxfd; x++) { if(x != ctlfd && x != pipefd && x > 2) @@ -1020,7 +983,7 @@ main(int argc, char **argv) if(x > 2) close(x); } -#endif + setup_signals(); rb_lib_init(NULL, NULL, NULL, 0, maxfd, 1024, 4096); rb_linebuf_init(4096);