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
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];
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)
{
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)
{
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);
#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)
#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)])
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)
{
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)
{
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));
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);
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
break;
}
}
+
+ conn_plain_write_sendq(conn->plain_fd, conn);
}
static void
if (!dolen)
break;
- if ((p = strcasestr(inbuf, "Sec-WebSocket-Key:")) != NULL)
+ if ((p = rb_strcasestr(inbuf, "Sec-WebSocket-Key:")) != NULL)
{
char *start, *end;
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");
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;
main(int argc, char **argv)
{
const char *s_ctlfd, *s_pipe, *s_pid;
- int ctlfd, pipefd, x, maxfd;
+ int ctlfd, pipefd, maxfd;
maxfd = maxconn();
s_ctlfd = getenv("CTL_FD");
ctlfd = atoi(s_ctlfd);
pipefd = atoi(s_pipe);
ppid = atoi(s_pid);
- x = 0;
+
#ifndef _WIN32
+ int x = 0;
for(x = 0; x < maxfd; x++)
{
if(x != ctlfd && x != pipefd && x > 2)