Skip to content
Newer
Older
100644 226 lines (195 sloc) 7 KB
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
256a064 @jehiah undo makefile changes from last change; make should compile against i…
jehiah authored May 13, 2010
4 #include "simplehttp/queue.h"
5 #include "simplehttp/simplehttp.h"
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
6
9eca153 @nathanfolkman Added BUFSIZE.
nathanfolkman authored Aug 25, 2009
7 #define BUFSZ 1024
09802dd @nathanfolkman Adding support for multipart.
nathanfolkman authored Aug 26, 2009
8 #define BOUNDARY "xXPubSubXx"
9eca153 @nathanfolkman Added BUFSIZE.
nathanfolkman authored Aug 25, 2009
9
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
10 int ps_debug = 0;
11
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
12 typedef struct cli {
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
13 int multipart;
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
14 int websocket;
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
15 struct evbuffer *buf;
16 struct evhttp_request *req;
17 TAILQ_ENTRY(cli) entries;
18 } cli;
19 TAILQ_HEAD(, cli) clients;
20
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
21 uint32_t totalConns = 0;
22 uint32_t currentConns = 0;
23 uint32_t msgRecv = 0;
24 uint32_t msgSent = 0;
25
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
26
27 void
28 argtoi(struct evkeyvalq *args, char *key, int *val, int def)
29 {
30 char *tmp;
31
32 *val = def;
33 tmp = (char *)evhttp_find_header(args, (const char *)key);
34 if (tmp) {
35 *val = atoi(tmp);
36 }
37 }
38
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
39 void
1b59fb8 @nathanfolkman Added new /clients callback.
nathanfolkman authored Sep 14, 2009
40 clients_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx)
41 {
42 struct cli *client;
43
44 TAILQ_FOREACH(client, &clients, entries) {
45 evbuffer_add_printf(evb, "%s:%d\n", client->req->remote_host, client->req->remote_port);
46 }
47
48 evhttp_send_reply(req, HTTP_OK, "OK", evb);
49 }
50
51 void
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
52 stats_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx)
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
53 {
5b0770f @nathanfolkman Fixed args.
nathanfolkman authored Aug 25, 2009
54 struct evkeyvalq args;
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
55 char *reset, *uri;
56 char buf[33];
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
57
58 uri = evhttp_decode_uri(req->uri);
59 evhttp_parse_query(uri, &args);
60 free(uri);
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
61
1b59fb8 @nathanfolkman Added new /clients callback.
nathanfolkman authored Sep 14, 2009
62 sprintf(buf, "%d", totalConns);
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
63 evhttp_add_header(req->output_headers, "X-PUBSUB-TOTAL-CONNECTIONS", buf);
1b59fb8 @nathanfolkman Added new /clients callback.
nathanfolkman authored Sep 14, 2009
64 sprintf(buf, "%d", currentConns);
8ee367b @nathanfolkman Fixed stat name.
nathanfolkman authored Aug 26, 2009
65 evhttp_add_header(req->output_headers, "X-PUBSUB-ACTIVE-CONNECTIONS", buf);
1b59fb8 @nathanfolkman Added new /clients callback.
nathanfolkman authored Sep 14, 2009
66 sprintf(buf, "%d", msgRecv);
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
67 evhttp_add_header(req->output_headers, "X-PUBSUB-MESSAGES-RECEIVED", buf);
1b59fb8 @nathanfolkman Added new /clients callback.
nathanfolkman authored Sep 14, 2009
68 sprintf(buf, "%d", msgSent);
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
69 evhttp_add_header(req->output_headers, "X-PUBSUB-MESSAGES-SENT", buf);
70
1b59fb8 @nathanfolkman Added new /clients callback.
nathanfolkman authored Sep 14, 2009
71 evbuffer_add_printf(evb, "Active connections: %d\nTotal connections: %d\n"
72 "Messages received: %d\nMessages sent: %d\n",
a34f690 @jayridge added shoofly pie support.
jayridge authored Aug 26, 2009
73 currentConns, totalConns, msgRecv, msgSent);
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
74 reset = (char *)evhttp_find_header(&args, "reset");
b1d1329 @nathanfolkman Trying to fix new stats command.
nathanfolkman authored Aug 25, 2009
75
76 if (reset) {
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
77 totalConns = 0;
78 currentConns = 0;
79 msgRecv = 0;
80 msgSent = 0;
81 }
82
38c69fd @nathanfolkman Moved stats to HTTP response headers.
nathanfolkman authored Aug 26, 2009
83 evhttp_send_reply(req, HTTP_OK, "OK", evb);
84 evhttp_clear_headers(&args);
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
85 }
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
86
87 void on_close(struct evhttp_connection *evcon, void *ctx)
88 {
89 struct cli *client = (struct cli *)ctx;
90
91 if (client) {
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
92 currentConns--;
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
93 TAILQ_REMOVE(&clients, client, entries);
94 evbuffer_free(client->buf);
95 free(client);
96 }
97 }
98
99 void pub_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx)
100 {
101 int i = 0;
102 struct cli *client;
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
103
104 msgRecv++;
5b0770f @nathanfolkman Fixed args.
nathanfolkman authored Aug 25, 2009
105 totalConns++;
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
106
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
107 TAILQ_FOREACH(client, &clients, entries) {
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
108 msgSent++;
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
109 evbuffer_drain(client->buf, EVBUFFER_LENGTH(client->buf));
09802dd @nathanfolkman Adding support for multipart.
nathanfolkman authored Aug 26, 2009
110
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
111 if (client->websocket) {
112 // set to non-chunked so that send_reply_chunked doesn't add \r\n before/after this block
113 client->req->chunked = 0;
114 // write the frame. a websocket frame is \x00 + msg + \xFF
115 evbuffer_add(client->buf, "\0", 1);
116 evbuffer_add(client->buf, req->input_buffer->buffer, EVBUFFER_LENGTH(req->input_buffer));
117 evbuffer_add(client->buf, "\xFF", 1);
118 }
119 else if (client->multipart) {
120 /* chunked */
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
121 evbuffer_add_printf(client->buf,
122 "content-type: %s\r\ncontent-length: %d\r\n\r\n",
123 "*/*",
124 (int)EVBUFFER_LENGTH(req->input_buffer));
125 evbuffer_add(client->buf, req->input_buffer->buffer, EVBUFFER_LENGTH(req->input_buffer));
126 evbuffer_add_printf(client->buf, "\r\n--%s\r\n", BOUNDARY);
127 } else {
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
128 /* new line terminated */
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
129 evbuffer_add(client->buf, req->input_buffer->buffer, EVBUFFER_LENGTH(req->input_buffer));
130 evbuffer_add_printf(client->buf, "\n");
131 }
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
132 evhttp_send_reply_chunk(client->req, client->buf);
133 i++;
134 }
5b0770f @nathanfolkman Fixed args.
nathanfolkman authored Aug 25, 2009
135
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
136 evbuffer_add_printf(evb, "Published to %d clients.\n", i);
137 evhttp_send_reply(req, HTTP_OK, "OK", evb);
138 }
139
140 void sub_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx)
141 {
142 struct cli *client;
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
143 struct evkeyvalq args;
144 char *uri;
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
145 char *ws_origin;
146 char *ws_upgrade;
147 char *host;
148 char buf[248];
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
149
1604d50 @nathanfolkman Added stats.
nathanfolkman authored Aug 25, 2009
150 currentConns++;
151 totalConns++;
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
152 uri = evhttp_decode_uri(req->uri);
153 evhttp_parse_query(uri, &args);
154 free(uri);
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
155 client = calloc(1, sizeof(*client));
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
156 argtoi(&args, "multipart", &client->multipart, 1);
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
157 client->req = req;
158 client->buf = evbuffer_new();
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
159
160 // Connection: Upgrade
161 // Upgrade: WebSocket
162 ws_upgrade = (char *) evhttp_find_header(req->input_headers, "Upgrade");
163 ws_origin = (char *) evhttp_find_header(req->input_headers, "Origin");
164 host = (char *) evhttp_find_header(req->input_headers, "Host");
165
166 if (ps_debug && ws_upgrade) {
167 fprintf(stderr, "upgrade header is %s\n", ws_upgrade);
168 fprintf(stderr, "multipart is %d\n", client->multipart);
169 }
170
171 if (ws_upgrade && strstr(ws_upgrade, "WebSocket") != NULL) {
172 if (ps_debug) {
173 fprintf(stderr, "upgrading connection to a websocket\n");
174 }
175 client->websocket = 1;
176 client->req->major = 1;
177 client->req->minor = 1;
178 evhttp_add_header(client->req->output_headers, "Upgrade", "WebSocket");
179 evhttp_add_header(client->req->output_headers, "Connection", "Upgrade");
180 evhttp_add_header(client->req->output_headers, "Server", "simplehttp/pubsub");
181 if (ws_origin) {
182 evhttp_add_header(client->req->output_headers, "WebSocket-Origin", ws_origin);
183 }
184 if (host) {
185 sprintf(buf, "ws://%s%s", host, req->uri);
186 if (ps_debug) {
187 fprintf(stderr, "setting WebSocket-Location to %s\n", buf);
188 }
189 evhttp_add_header(client->req->output_headers, "WebSocket-Location", buf);
190 }
191 // evbuffer_add_printf(client->buf, "\r\n");
192 }
193 else if (client->multipart) {
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
194 evhttp_add_header(client->req->output_headers, "content-type",
195 "multipart/x-mixed-replace; boundary=" BOUNDARY);
196 evbuffer_add_printf(client->buf, "--%s\r\n", BOUNDARY);
197 } else {
198 evhttp_add_header(client->req->output_headers, "content-type",
199 "application/json");
200 evbuffer_add_printf(client->buf, "\r\n");
201 }
6db1157 @jehiah pubsub server speaking websocket's
jehiah authored May 14, 2010
202 if (client->websocket) {
203 evhttp_send_reply_start(client->req, 101, "Web Socket Protocol Handshake");
204 } else {
205 evhttp_send_reply_start(client->req, HTTP_OK, "OK");
206 }
09802dd @nathanfolkman Adding support for multipart.
nathanfolkman authored Aug 26, 2009
207 evhttp_send_reply_chunk(client->req, client->buf);
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
208 TAILQ_INSERT_TAIL(&clients, client, entries);
209 evhttp_connection_set_closecb(req->evcon, on_close, (void *)client);
0e581ad @jayridge added multipart=0
jayridge authored May 6, 2010
210 evhttp_clear_headers(&args);
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
211 }
212
213 int
214 main(int argc, char **argv)
215 {
216 TAILQ_INIT(&clients);
217 simplehttp_init();
218 simplehttp_set_cb("/pub*", pub_cb, NULL);
219 simplehttp_set_cb("/sub*", sub_cb, NULL);
1b59fb8 @nathanfolkman Added new /clients callback.
nathanfolkman authored Sep 14, 2009
220 simplehttp_set_cb("/stats*", stats_cb, NULL);
221 simplehttp_set_cb("/clients*", clients_cb, NULL);
eeebb66 @jayridge initial import of pubsub
jayridge authored Aug 21, 2009
222 simplehttp_main(argc, argv);
223
224 return 0;
225 }
Something went wrong with that request. Please try again.