comparison src/c/urweb.c @ 668:b0c1a46b1f15

First message send delivered, but not interpreted
author Adam Chlipala <adamc@hcoop.net>
date Sun, 22 Mar 2009 15:05:07 -0400
parents a93d5324f400
children f68eee90dbcf
comparison
equal deleted inserted replaced
667:a93d5324f400 668:b0c1a46b1f15
74 74
75 static size_t buf_avail(buf *b) { 75 static size_t buf_avail(buf *b) {
76 return b->back - b->start; 76 return b->back - b->start;
77 } 77 }
78 78
79 79 static void buf_append(buf *b, const char *s, size_t len) {
80 // Cross-request state 80 buf_check(b, len);
81 memcpy(b->front, s, len);
82 b->front += len;
83 }
84
85
86 // Persistent client state
81 87
82 typedef enum { UNUSED, USED } usage; 88 typedef enum { UNUSED, USED } usage;
83 89
84 typedef struct client { 90 typedef struct client {
85 size_t id; 91 size_t id;
99 static client **clients, *clients_free; 105 static client **clients, *clients_free;
100 static size_t n_clients; 106 static size_t n_clients;
101 107
102 static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; 108 static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
103 109
104 void uw_global_init() {
105 srand(time(NULL) ^ getpid());
106
107 clients = malloc(0);
108 }
109
110 void uw_global_free() {
111 size_t i;
112
113 for (i = 0; i < n_clients; ++i)
114 free(clients[i]);
115
116 free(clients);
117 }
118
119 static client *uw_new_client() { 110 static client *uw_new_client() {
120 client *c; 111 client *c;
121 112
122 pthread_mutex_lock(&clients_mutex); 113 pthread_mutex_lock(&clients_mutex);
123 114
145 return c; 136 return c;
146 } 137 }
147 138
148 static const char begin_msgs[] = "HTTP/1.1 200 OK\r\nContent-type: text/plain\r\n\r\n"; 139 static const char begin_msgs[] = "HTTP/1.1 200 OK\r\nContent-type: text/plain\r\n\r\n";
149 140
150 void uw_client_connect(size_t id, int pass, int sock) { 141 static client *uw_find_client(size_t id) {
151 client *c; 142 client *c;
152 143
153 pthread_mutex_lock(&clients_mutex); 144 pthread_mutex_lock(&clients_mutex);
154 145
155 if (id >= n_clients) { 146 if (id >= n_clients) {
156 pthread_mutex_unlock(&clients_mutex); 147 pthread_mutex_unlock(&clients_mutex);
148 return NULL;
149 }
150
151 c = clients[id];
152
153 if (c->mode != USED) {
154 pthread_mutex_unlock(&clients_mutex);
155 return NULL;
156 }
157
158 pthread_mutex_unlock(&clients_mutex);
159 return c;
160 }
161
162 void uw_client_connect(size_t id, int pass, int sock) {
163 client *c = uw_find_client(id);
164
165 if (c == NULL) {
157 close(sock); 166 close(sock);
158 fprintf(stderr, "Out-of-bounds client request (%d)\n", (int)id); 167 fprintf(stderr, "Out-of-bounds client request (%d)\n", (int)id);
159 return; 168 return;
160 } 169 }
161 170
162 c = clients[id];
163
164 if (c->mode != USED) {
165 pthread_mutex_unlock(&clients_mutex);
166 close(sock);
167 fprintf(stderr, "Client request for unused ID (%d)\n", (int)id);
168 return;
169 }
170
171 pthread_mutex_lock(&c->data.used.lock); 171 pthread_mutex_lock(&c->data.used.lock);
172 172
173 if (pass != c->data.used.pass) { 173 if (pass != c->data.used.pass) {
174 pthread_mutex_unlock(&c->data.used.lock); 174 pthread_mutex_unlock(&c->data.used.lock);
175 pthread_mutex_unlock(&clients_mutex);
176 close(sock); 175 close(sock);
177 fprintf(stderr, "Wrong client password (%d)\n", (int)id); 176 fprintf(stderr, "Wrong client password (%d)\n", (int)id);
178 return; 177 return;
179 } 178 }
180 179
181 if (c->data.used.sock != -1) { 180 if (c->data.used.sock != -1) {
182 pthread_mutex_unlock(&c->data.used.lock); 181 pthread_mutex_unlock(&c->data.used.lock);
183 pthread_mutex_unlock(&clients_mutex);
184 close(sock); 182 close(sock);
185 fprintf(stderr, "Duplicate client connection (%d)\n", (int)id); 183 fprintf(stderr, "Duplicate client connection (%d)\n", (int)id);
186 return; 184 return;
187 } 185 }
188 186
191 if (buf_used(&c->data.used.msgs) > 0) { 189 if (buf_used(&c->data.used.msgs) > 0) {
192 uw_really_send(sock, begin_msgs, sizeof(begin_msgs) - 1); 190 uw_really_send(sock, begin_msgs, sizeof(begin_msgs) - 1);
193 uw_really_send(sock, c->data.used.msgs.start, buf_used(&c->data.used.msgs)); 191 uw_really_send(sock, c->data.used.msgs.start, buf_used(&c->data.used.msgs));
194 close(sock); 192 close(sock);
195 } 193 }
196 else { 194 else
197 uw_really_send(sock, begin_msgs, sizeof(begin_msgs) - 1); 195 c->data.used.sock = sock;
198 uw_really_send(sock, "Hi!", 3);
199 close(sock);
200 //c->data.used.sock = sock;
201 }
202 196
203 pthread_mutex_unlock(&c->data.used.lock); 197 pthread_mutex_unlock(&c->data.used.lock);
204 pthread_mutex_unlock(&clients_mutex);
205 } 198 }
206 199
207 static void uw_free_client(client *c) { 200 static void uw_free_client(client *c) {
208 printf("Freeing client %d\n", c->id); 201 printf("Freeing client %d\n", c->id);
209 202
229 if (clients[i]->mode == USED && clients[i]->data.used.last_contact < cutoff) 222 if (clients[i]->mode == USED && clients[i]->data.used.last_contact < cutoff)
230 uw_free_client(clients[i]); 223 uw_free_client(clients[i]);
231 } 224 }
232 225
233 pthread_mutex_unlock(&clients_mutex); 226 pthread_mutex_unlock(&clients_mutex);
227 }
228
229
230 // Persistent channel state
231
232 typedef struct client_list {
233 client *data;
234 struct client_list *next;
235 } client_list;
236
237 typedef struct channel {
238 size_t id;
239 usage mode;
240 union {
241 struct channel *next;
242 struct {
243 pthread_mutex_t lock;
244 client_list *clients;
245 } used;
246 } data;
247 } channel;
248
249 static channel **channels, *channels_free;
250 static size_t n_channels;
251
252 static pthread_mutex_t channels_mutex = PTHREAD_MUTEX_INITIALIZER;
253
254 static channel *uw_new_channel() {
255 channel *ch;
256
257 pthread_mutex_lock(&channels_mutex);
258
259 if (channels_free) {
260 ch = channels_free;
261 channels_free = channels_free->data.next;
262 }
263 else {
264 ++n_channels;
265 channels = realloc(channels, sizeof(channels) * n_channels);
266 ch = malloc(sizeof(channel));
267 ch->id = n_channels-1;
268 channels[n_channels-1] = ch;
269 }
270
271 ch->mode = USED;
272 pthread_mutex_init(&ch->data.used.lock, NULL);
273 ch->data.used.clients = NULL;
274
275 pthread_mutex_unlock(&channels_mutex);
276
277 return ch;
278 }
279
280 static channel *uw_find_channel(size_t id) {
281 channel *ch = NULL;
282
283 pthread_mutex_lock(&channels_mutex);
284
285 if (id < n_channels && channels[id]->mode == USED)
286 ch = channels[id];
287
288 pthread_mutex_unlock(&channels_mutex);
289
290 return ch;
291 }
292
293 static void uw_subscribe(channel *ch, client *c) {
294 client_list *cs = malloc(sizeof(client_list));
295
296 pthread_mutex_lock(&ch->data.used.lock);
297
298 cs->data = c;
299 cs->next = ch->data.used.clients;
300 ch->data.used.clients = cs;
301
302 pthread_mutex_unlock(&ch->data.used.lock);
303 }
304
305 static void uw_unsubscribe(channel *ch, client *c) {
306 client_list *prev, *cur, *tmp;
307
308 pthread_mutex_lock(&ch->data.used.lock);
309
310 for (prev = NULL, cur = ch->data.used.clients; cur; ) {
311 if (cur->data == c) {
312 if (prev)
313 prev->next = cur->next;
314 else
315 ch->data.used.clients = cur->next;
316 tmp = cur;
317 cur = cur->next;
318 free(tmp);
319 }
320 else {
321 prev = cur;
322 cur = cur->next;
323 }
324 }
325
326 pthread_mutex_unlock(&ch->data.used.lock);
327 }
328
329 static void uw_channel_send(channel *ch, const char *msg) {
330 size_t len = strlen(msg), preLen;
331 char pre[INTS_MAX + 2];
332 client_list *cs;
333
334 sprintf(pre, "%d\n", (int)ch->id);
335 preLen = strlen(pre);
336
337 pthread_mutex_lock(&ch->data.used.lock);
338
339 for (cs = ch->data.used.clients; cs; cs = cs->next) {
340 client *c = cs->data;
341
342 pthread_mutex_lock(&c->data.used.lock);
343
344 if (c->data.used.sock != -1) {
345 uw_really_send(c->data.used.sock, begin_msgs, sizeof(begin_msgs) - 1);
346 uw_really_send(c->data.used.sock, pre, preLen);
347 uw_really_send(c->data.used.sock, msg, len);
348 uw_really_send(c->data.used.sock, "\n", 1);
349 close(c->data.used.sock);
350 c->data.used.sock = -1;
351 } else {
352 buf_append(&c->data.used.msgs, pre, preLen);
353 buf_append(&c->data.used.msgs, msg, len);
354 buf_append(&c->data.used.msgs, "\n", 1);
355 }
356
357 pthread_mutex_unlock(&c->data.used.lock);
358 }
359
360 pthread_mutex_unlock(&ch->data.used.lock);
361 }
362
363
364 // Global entry points
365
366 void uw_global_init() {
367 srand(time(NULL) ^ getpid());
368
369 clients = malloc(0);
370 channels = malloc(0);
234 } 371 }
235 372
236 373
237 // Single-request state 374 // Single-request state
238 375
580 ctx->script_header, (int)c->id, c->data.used.pass, ctx->url_prefix, ctx->script.start); 717 ctx->script_header, (int)c->id, c->data.used.pass, ctx->url_prefix, ctx->script.start);
581 return r; 718 return r;
582 } 719 }
583 } 720 }
584 721
585 const char *uw_Basis_get_listener(uw_context ctx, uw_unit u) { 722 const char *uw_Basis_get_listener(uw_context ctx, uw_Basis_string onload) {
586 if (ctx->script_header[0] == 0) 723 if (ctx->script_header[0] == 0)
587 return ""; 724 return "";
588 else 725 else if (onload[0] == 0)
589 return " onload='listener()'"; 726 return " onload='listener()'";
727 else {
728 uw_Basis_string s = uw_malloc(ctx, strlen(onload) + 22);
729
730 sprintf(s, " onload='listener();%s'", onload);
731 return s;
732 }
590 } 733 }
591 734
592 uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) { 735 uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) {
593 char *r, *s2; 736 char *r, *s2;
594 737
939 r = atoll(*s); 1082 r = atoll(*s);
940 *s = new_s; 1083 *s = new_s;
941 return r; 1084 return r;
942 } 1085 }
943 1086
1087 uw_Basis_channel uw_Basis_unurlifyChannel(uw_context ctx, char **s) {
1088 return uw_Basis_unurlifyInt(ctx, s);
1089 }
1090
944 uw_Basis_float uw_Basis_unurlifyFloat(uw_context ctx, char **s) { 1091 uw_Basis_float uw_Basis_unurlifyFloat(uw_context ctx, char **s) {
945 char *new_s = uw_unurlify_advance(*s); 1092 char *new_s = uw_unurlify_advance(*s);
946 uw_Basis_float r; 1093 uw_Basis_float r;
947 1094
948 r = atof(*s); 1095 r = atof(*s);
1028 uw_check(ctx, INTS_MAX); 1175 uw_check(ctx, INTS_MAX);
1029 sprintf(ctx->page.front, "%lld%n", n, &len); 1176 sprintf(ctx->page.front, "%lld%n", n, &len);
1030 ctx->page.front += len; 1177 ctx->page.front += len;
1031 1178
1032 return uw_unit_v; 1179 return uw_unit_v;
1180 }
1181
1182 char *uw_Basis_htmlifyChannel(uw_context ctx, uw_Basis_channel ch) {
1183 return uw_Basis_htmlifyInt(ctx, ch);
1033 } 1184 }
1034 1185
1035 char *uw_Basis_htmlifyFloat(uw_context ctx, uw_Basis_float n) { 1186 char *uw_Basis_htmlifyFloat(uw_context ctx, uw_Basis_float n) {
1036 int len; 1187 int len;
1037 char *r; 1188 char *r;
1573 uw_write_header(ctx, "\r\n"); 1724 uw_write_header(ctx, "\r\n");
1574 1725
1575 return uw_unit_v; 1726 return uw_unit_v;
1576 } 1727 }
1577 1728
1578 1729 uw_Basis_channel uw_Basis_new_channel(uw_context ctx, uw_unit u) {
1730 return uw_new_channel()->id;
1731 }
1732
1733 uw_unit uw_Basis_subscribe(uw_context ctx, uw_Basis_channel chn) {
1734 channel *ch = uw_find_channel(chn);
1735
1736 if (ch == NULL)
1737 uw_error(ctx, FATAL, "Bad channel ID %d", (int)chn);
1738 else {
1739 size_t id = atoi(uw_Basis_requestHeader(ctx, "UrWeb-Client"));
1740 int pass = atoi(uw_Basis_requestHeader(ctx, "UrWeb-Pass"));
1741 client *c = uw_find_client(id);
1742
1743 if (c == NULL)
1744 uw_error(ctx, FATAL, "Unknown client ID in subscription request");
1745 else if (c->data.used.pass != pass)
1746 uw_error(ctx, FATAL, "Wrong client password in subscription request");
1747 else
1748 uw_subscribe(ch, c);
1749 }
1750 }
1751
1752 uw_unit uw_Basis_send(uw_context ctx, uw_Basis_channel chn, uw_Basis_string msg) {
1753 channel *ch = uw_find_channel(chn);
1754
1755 if (ch == NULL)
1756 uw_error(ctx, FATAL, "Bad channel ID %d", (int)chn);
1757 else
1758 uw_channel_send(ch, msg);
1759 }