summaryrefslogtreecommitdiffstats
path: root/contrib/src/evws/evws.h
blob: 7967a64115d3abd257fb235fbf31f585dfd06542 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/**
 *  @file
 *  @author     Pawel Zubrycki <paw.zubr@gmail.com>
 *  @author     2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
 *  @copyright  Simplified BSD
 *
 *  @cond
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the FreeBSD license as published by the FreeBSD
 *  project.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 *  You should have received a copy of the FreeBSD license along with this
 *  program. If not, see <http://www.opensource.org/licenses/bsd-license>.
 *  @endcond
 */

#ifndef EVWS_H
#define EVWS_H

#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <sys/queue.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

enum evws_opcode {
	EVWS_CONTINUATION_FRAME = 0x0,
	EVWS_TEXT_FRAME = 0x1,
	EVWS_BINARY_FRAME = 0x2,
	EVWS_CONNECTION_CLOSE = 0x8,
	EVWS_PING = 0x9,
	EVWS_PONG = 0xa
};

enum evws_conn_state {
	EVWS_NULL = 0x0,
	EVWS_FIRSTLINE_READ = 0x1,
	EVWS_HEADER_READ = 0x2,
	EVWS_CONNECTED = 0x3,
	EVWS_CLOSED = 0x4,
	EVWS_READING_FRAME = 0x5,
};

enum evws_frame_state {
	EVWS_OPCODE_READ = 0x0,
	EVWS_PAYLOAD_LENGTH_LENGTH_READ = 0x1,
	EVWS_PAYLOAD_LENGTH_READ = 0x2,
	EVWS_MASKING_KEY_READ = 0x3,
	EVWS_EXTENSION_READ = 0x4,
};

struct evws_header {
	TAILQ_ENTRY(evws_header) next;
	char *key;
	char *value;
};

struct evws_frame {
	/**
	 * Indicates that this is the final fragment in a message.  The first
	 * fragment MAY also be the final fragment.
	 */
	uint8_t fin;
	
	/**
	 * MUST be 0 unless an extension is negotiated that defines meanings
	 * for non-zero values.  If a nonzero value is received and none of
	 * the negotiated extensions defines the meaning of such a nonzero
	 * value, the receiving endpoint MUST _Fail the WebSocket
	 * Connection_.
	 */
	uint8_t rsv;
	
	/**
	 *  %x0 denotes a continuation frame
	 *  %x1 denotes a text frame
	 *  %x2 denotes a binary frame
	 *  %x3-7 are reserved for further non-control frames
	 *  %x8 denotes a connection close
	 *  %x9 denotes a ping
	 *  %xA denotes a pong
	 *  %xB-F are reserved for further control frames
	 */
	enum evws_opcode opcode;
	
	/**
	 * Defines whether the "Payload data" is masked.
	 */
	uint8_t has_mask;
	
	/**
	 * The length of the "Payload data", in bytes: if 0-125, that is the
	 * payload length.  If 126, the following 2 bytes interpreted as a
	 * 16-bit unsigned integer are the payload length.  If 127, the
	 * following 8 bytes interpreted as a 64-bit unsigned integer (the
	 * most significant bit MUST be 0) are the payload length.
	 */
	uint64_t size;
	uint64_t payload_read;
	uint8_t payload_bytes;

	/**
	 * The content or payload of the frame
	 */
	char* data;
	
	/**
	 * All frames sent from the client to the server are masked by a
	 * 32-bit value that is contained within the frame.  This field is
	 * present if the mask bit is set to 1 and is absent if the mask bit
	 * is set to 0.
	 */
	uint8_t mask[4];
	uint8_t mask_bytes;
	uint8_t mask_index;
	
	uint8_t state;
};

struct evws_connection
{
	TAILQ_ENTRY(evws_connection) next;
	struct evws *ws;
	struct evws_frame *frame;
	char *uri;
	struct bufferevent *bufev;
	int state;
	int fd;

	// headers
	TAILQ_HEAD(wsheadersq, evws_header) headers;
};

typedef void (*cb_type)(struct evws_connection *, const char *, size_t, void *);
typedef void (*cb_frame_type)(struct evws_connection *, struct evws_frame *, void *);

struct evws_cb
{
	TAILQ_ENTRY(evws_cb) next;
	char * uri;
	cb_frame_type msg_cb;
	cb_type conn_cb;
	void * cb_arg;
};

struct evws_read_buf
{
	TAILQ_ENTRY(evws_read_buf) next;
	char* data;
};

TAILQ_HEAD(evwsconq, evws_connection);

struct evws
{
	struct evconnlistener *listener;
	TAILQ_HEAD(wscbq, evws_cb) callbacks;
	struct evwsconq connections;

	// generic callback
	cb_frame_type gencb;
	void * gencb_arg;
	struct event_base *base;
};

struct evws_connection *evws_connection_new(struct evws *ws, evutil_socket_t fd);
void evws_connection_free(struct evws_connection *conn);

struct evws_frame *evws_frame_new();
void evws_frame_free(struct evws_frame *frame);

struct evws *evws_new(struct event_base *base);
void evws_free(struct evws *ptr);

struct evws_header *evws_header_new(char *key, char *value);
void evws_header_free(struct evws_header *header);

char *evws_find_header(const struct wsheadersq *q, const char *key);
evutil_socket_t evws_bind_socket(struct evws * ws, unsigned short port);
int evws_set_cb(struct evws * ws, const char * pattern, cb_frame_type message_cb, cb_type connect_cb, void * arg);
cb_frame_type evws_set_gencb(struct evws *ws, cb_frame_type cb, void * arg);
void evws_broadcast(struct evws *ws, const char *uri, enum evws_opcode opcode, const char *data, uint64_t length);
void evws_send_data(struct evws_connection *conn, enum evws_opcode opcode, const char *data, uint64_t length);

#ifdef __cplusplus
}
#endif

#endif