aboutsummaryrefslogtreecommitdiff
path: root/src/microspdy
diff options
context:
space:
mode:
Diffstat (limited to 'src/microspdy')
-rw-r--r--src/microspdy/Makefile.am40
-rw-r--r--src/microspdy/alstructures.c41
-rw-r--r--src/microspdy/alstructures.h79
-rw-r--r--src/microspdy/applicationlayer.c748
-rw-r--r--src/microspdy/applicationlayer.h31
-rw-r--r--src/microspdy/compression.c441
-rw-r--r--src/microspdy/compression.h117
-rw-r--r--src/microspdy/daemon.c544
-rw-r--r--src/microspdy/daemon.h130
-rw-r--r--src/microspdy/internal.c40
-rw-r--r--src/microspdy/internal.h199
-rw-r--r--src/microspdy/io.c90
-rw-r--r--src/microspdy/io.h216
-rw-r--r--src/microspdy/io_openssl.c280
-rw-r--r--src/microspdy/io_openssl.h166
-rw-r--r--src/microspdy/io_raw.c194
-rw-r--r--src/microspdy/io_raw.h158
-rw-r--r--src/microspdy/session.c1769
-rw-r--r--src/microspdy/session.h281
-rw-r--r--src/microspdy/stream.c169
-rw-r--r--src/microspdy/stream.h76
-rw-r--r--src/microspdy/structures.c638
-rw-r--r--src/microspdy/structures.h1246
23 files changed, 0 insertions, 7693 deletions
diff --git a/src/microspdy/Makefile.am b/src/microspdy/Makefile.am
deleted file mode 100644
index 7fb2c37f..00000000
--- a/src/microspdy/Makefile.am
+++ /dev/null
@@ -1,40 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = \
3 -I$(top_srcdir)/src/include \
4 -I$(top_srcdir)/src/microspdy
5
6AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS)
7
8
9lib_LTLIBRARIES = \
10 libmicrospdy.la
11
12libmicrospdy_la_SOURCES = \
13 io.h io.c \
14 io_openssl.h io_openssl.c \
15 io_raw.h io_raw.c \
16 structures.h structures.c \
17 internal.h internal.c \
18 daemon.h daemon.c \
19 stream.h stream.c \
20 compression.h compression.c \
21 session.h session.c \
22 applicationlayer.c applicationlayer.h \
23 alstructures.c alstructures.h
24libmicrospdy_la_LIBADD = \
25 $(SPDY_LIBDEPS)
26
27libmicrospdy_la_LDFLAGS = \
28 $(SPDY_LIB_LDFLAGS)
29
30libmicrospdy_la_CPPFLAGS = \
31 $(AM_CPPFLAGS) $(SPDY_LIB_CPPFLAGS) \
32 -DBUILDING_MHD_LIB=1
33
34libmicrospdy_la_CFLAGS = -Wextra \
35 $(AM_CFLAGS) $(SPDY_LIB_CFLAGS)
36
37
38if USE_COVERAGE
39 AM_CFLAGS += --coverage
40endif
diff --git a/src/microspdy/alstructures.c b/src/microspdy/alstructures.c
deleted file mode 100644
index b588a1c8..00000000
--- a/src/microspdy/alstructures.c
+++ /dev/null
@@ -1,41 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file alstructures.c
21 * @brief structures only for the application layer
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "alstructures.h"
27#include "internal.h"
28
29void
30SPDY_destroy_request (struct SPDY_Request *request)
31{
32 if(NULL == request)
33 {
34 SPDYF_DEBUG("request is NULL");
35 return;
36 }
37 //strings into request struct are just references to strings in
38 //headers, so no need to free them twice
39 SPDY_name_value_destroy(request->headers);
40 free(request);
41}
diff --git a/src/microspdy/alstructures.h b/src/microspdy/alstructures.h
deleted file mode 100644
index 2eb36e82..00000000
--- a/src/microspdy/alstructures.h
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file alstructures.h
21 * @brief structures only for the application layer
22 * @author Andrey Uzunov
23 */
24
25#ifndef ALSTRUCTURES_H
26#define ALSTRUCTURES_H
27
28#include "platform.h"
29
30
31/**
32 * Represents a SPDY request.
33 */
34struct SPDY_Request
35{
36 /**
37 * SPDY stream in whose context the request was received
38 */
39 struct SPDYF_Stream *stream;
40
41 /**
42 * Other HTTP headers from the request
43 */
44 struct SPDY_NameValue *headers;
45
46 /**
47 * HTTP method
48 */
49 char *method;
50
51 /**
52 * HTTP path
53 */
54 char *path;
55
56 /**
57 * HTTP version just like in HTTP request/response:
58 * "HTTP/1.0" or "HTTP/1.1" currently
59 */
60 char *version;
61
62 /**
63 * called host as in HTTP
64 */
65 char *host;
66
67 /**
68 * The scheme used ("http" or "https")
69 */
70 char *scheme;
71
72 /**
73 * Extra field to be used by the user with set/get func for whatever
74 * purpose he wants.
75 */
76 void *user_cls;
77};
78
79#endif
diff --git a/src/microspdy/applicationlayer.c b/src/microspdy/applicationlayer.c
deleted file mode 100644
index bf16b785..00000000
--- a/src/microspdy/applicationlayer.c
+++ /dev/null
@@ -1,748 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file applicationlayer.c
21 * @brief SPDY application or HTTP layer
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "applicationlayer.h"
27#include "alstructures.h"
28#include "structures.h"
29#include "internal.h"
30#include "daemon.h"
31#include "session.h"
32
33
34void
35spdy_callback_response_done(void *cls,
36 struct SPDY_Response *response,
37 struct SPDY_Request *request,
38 enum SPDY_RESPONSE_RESULT status,
39 bool streamopened)
40{
41 (void)cls;
42 (void)status;
43 (void)streamopened;
44
45 SPDY_destroy_request(request);
46 SPDY_destroy_response(response);
47}
48
49
50/**
51 * Callback called when new stream is created. It extracts the info from
52 * the stream to create (HTTP) request object and pass it to the client.
53 *
54 * @param cls
55 * @param stream the new SPDY stream
56 * @return SPDY_YES on success, SPDY_NO on memomry error
57 */
58static int
59spdy_handler_new_stream (void *cls,
60 struct SPDYF_Stream * stream)
61{
62 (void)cls;
63 unsigned int i;
64 char *method = NULL;
65 char *path = NULL;
66 char *version = NULL;
67 char *host = NULL;
68 char *scheme = NULL;
69 struct SPDY_Request * request = NULL;
70 struct SPDY_NameValue * headers = NULL;
71 struct SPDY_NameValue * iterator = stream->headers;
72 struct SPDY_Daemon *daemon;
73
74 daemon = stream->session->daemon;
75
76 //if the user doesn't care, ignore it
77 if(NULL == daemon->new_request_cb)
78 return SPDY_YES;
79
80 if(NULL == (headers=SPDY_name_value_create()))
81 goto free_and_fail;
82
83 if(NULL==(request = malloc(sizeof(struct SPDY_Request))))
84 goto free_and_fail;
85
86 memset(request, 0, sizeof(struct SPDY_Request));
87 request->stream = stream;
88
89 /* extract the mandatory fields from stream->headers' structure
90 * to pass them to the client */
91 while(iterator != NULL)
92 {
93 if(strcmp(":method",iterator->name) == 0)
94 {
95 if(1 != iterator->num_values)
96 break;
97 method = iterator->value[0];
98 }
99 else if(strcmp(":path",iterator->name) == 0)
100 {
101 if(1 != iterator->num_values)
102 break;
103 path = iterator->value[0];
104 }
105 else if(strcmp(":version",iterator->name) == 0)
106 {
107 if(1 != iterator->num_values)
108 break;
109 version = iterator->value[0];
110 }
111 else if(strcmp(":host",iterator->name) == 0)
112 {
113 //TODO can it have more values?
114 if(1 != iterator->num_values)
115 break;
116 host = iterator->value[0];
117 }
118 else if(strcmp(":scheme",iterator->name) == 0)
119 {
120 if(1 != iterator->num_values)
121 break;
122 scheme = iterator->value[0];
123 }
124 else
125 for(i=0; i<iterator->num_values; ++i)
126 if (SPDY_YES != SPDY_name_value_add(headers,iterator->name,iterator->value[i]))
127 {
128 SPDY_destroy_request(request);
129 goto free_and_fail;
130 }
131
132 iterator = iterator->next;
133 }
134
135 request->method=method;
136 request->path=path;
137 request->version=version;
138 request->host=host;
139 request->scheme=scheme;
140 request->headers=headers;
141
142 //check request validity, all these fields are mandatory for a request
143 if(NULL == method || strlen(method) == 0
144 || NULL == path || strlen(path) == 0
145 || NULL == version || strlen(version) == 0
146 || NULL == host || strlen(host) == 0
147 || NULL == scheme || strlen(scheme) == 0
148 )
149 {
150 //TODO HTTP 400 Bad Request must be answered
151
152 SPDYF_DEBUG("Bad request");
153
154 SPDY_destroy_request(request);
155
156 return SPDY_YES;
157 }
158
159 //call client's callback function to notify
160 daemon->new_request_cb(daemon->cls,
161 request,
162 stream->priority,
163 method,
164 path,
165 version,
166 host,
167 scheme,
168 headers,
169 !stream->is_in_closed);
170
171 stream->cls = request;
172
173 return SPDY_YES;
174
175 //for GOTO
176 free_and_fail:
177
178 SPDY_name_value_destroy(headers);
179 return SPDY_NO;
180}
181
182
183/**
184 * TODO
185 */
186static int
187spdy_handler_new_data (void * cls,
188 struct SPDYF_Stream *stream,
189 const void * buf,
190 size_t size,
191 bool more)
192{
193 return stream->session->daemon->received_data_cb(cls, stream->cls, buf, size, more);
194}
195
196
197
198/**
199 * Callback to be called when the response queue object was handled and
200 * the data was already sent or discarded.
201 *
202 * @param cls
203 * @param response_queue the object which is being handled
204 * @param status shows if actually the response was sent or it was
205 * discarded by the lib for any reason (e.g., closing session,
206 * closing stream, stopping daemon, etc.). It is possible that
207 * status indicates an error but parts of the response headers
208 * and/or body (in one
209 * or several frames) were already sent to the client.
210 */
211static void
212spdy_handler_response_queue_result(void * cls,
213 struct SPDYF_Response_Queue *response_queue,
214 enum SPDY_RESPONSE_RESULT status)
215{
216 int streamopened;
217 struct SPDY_Request *request = (struct SPDY_Request *)cls;
218
219 SPDYF_ASSERT( ( (NULL == response_queue->data_frame) &&
220 (NULL != response_queue->control_frame) ) ||
221 ( (NULL != response_queue->data_frame) &&
222 (NULL == response_queue->control_frame) ),
223 "response queue must have either control frame or data frame");
224
225 streamopened = !response_queue->stream->is_out_closed;
226
227 response_queue->rrcb(response_queue->rrcb_cls, response_queue->response, request, status, streamopened);
228}
229
230
231int
232(SPDY_init) (enum SPDY_IO_SUBSYSTEM io_subsystem, ...)
233{
234 SPDYF_ASSERT(SPDYF_BUFFER_SIZE >= SPDY_MAX_SUPPORTED_FRAME_SIZE,
235 "Buffer size is less than max supported frame size!");
236 SPDYF_ASSERT(SPDY_MAX_SUPPORTED_FRAME_SIZE >= 32,
237 "Max supported frame size must be bigger than the minimal value!");
238 SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE == spdyf_io_initialized,
239 "SPDY_init must be called only once per program or after SPDY_deinit");
240
241 if(SPDY_IO_SUBSYSTEM_OPENSSL & io_subsystem)
242 {
243 SPDYF_openssl_global_init();
244 spdyf_io_initialized |= SPDY_IO_SUBSYSTEM_OPENSSL;
245 }
246 else if(SPDY_IO_SUBSYSTEM_RAW & io_subsystem)
247 {
248 SPDYF_raw_global_init();
249 spdyf_io_initialized |= SPDY_IO_SUBSYSTEM_RAW;
250 }
251
252 SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE != spdyf_io_initialized,
253 "SPDY_init could not find even one IO subsystem");
254
255 return SPDY_YES;
256}
257
258
259void
260SPDY_deinit ()
261{
262 SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE != spdyf_io_initialized,
263 "SPDY_init has not been called!");
264
265 if(SPDY_IO_SUBSYSTEM_OPENSSL & spdyf_io_initialized)
266 SPDYF_openssl_global_deinit();
267 else if(SPDY_IO_SUBSYSTEM_RAW & spdyf_io_initialized)
268 SPDYF_raw_global_deinit();
269
270 spdyf_io_initialized = SPDY_IO_SUBSYSTEM_NONE;
271}
272
273
274void
275SPDY_run (struct SPDY_Daemon *daemon)
276{
277 if(NULL == daemon)
278 {
279 SPDYF_DEBUG("daemon is NULL");
280 return;
281 }
282
283 SPDYF_run(daemon);
284}
285
286
287int
288SPDY_get_timeout (struct SPDY_Daemon *daemon,
289 unsigned long long *timeout)
290{
291 if(NULL == daemon)
292 {
293 SPDYF_DEBUG("daemon is NULL");
294 return SPDY_INPUT_ERROR;
295 }
296
297 return SPDYF_get_timeout(daemon,timeout);
298}
299
300
301int
302SPDY_get_fdset (struct SPDY_Daemon *daemon,
303 fd_set *read_fd_set,
304 fd_set *write_fd_set,
305 fd_set *except_fd_set)
306{
307 if(NULL == daemon
308 || NULL == read_fd_set
309 || NULL == write_fd_set
310 || NULL == except_fd_set)
311 {
312 SPDYF_DEBUG("a parameter is NULL");
313 return SPDY_INPUT_ERROR;
314 }
315
316 return SPDYF_get_fdset(daemon,
317 read_fd_set,
318 write_fd_set,
319 except_fd_set,
320 false);
321}
322
323
324struct SPDY_Daemon *
325SPDY_start_daemon (uint16_t port,
326 const char *certfile,
327 const char *keyfile,
328 SPDY_NewSessionCallback nscb,
329 SPDY_SessionClosedCallback sccb,
330 SPDY_NewRequestCallback nrcb,
331 SPDY_NewDataCallback npdcb,
332 void * cls,
333 ...)
334{
335 struct SPDY_Daemon *daemon;
336 va_list valist;
337
338 if(SPDY_IO_SUBSYSTEM_NONE == spdyf_io_initialized)
339 {
340 SPDYF_DEBUG("library not initialized");
341 return NULL;
342 }
343 /*
344 * for now make this checks in framing layer
345 if(NULL == certfile)
346 {
347 SPDYF_DEBUG("certfile is NULL");
348 return NULL;
349 }
350 if(NULL == keyfile)
351 {
352 SPDYF_DEBUG("keyfile is NULL");
353 return NULL;
354 }
355 */
356
357 va_start(valist, cls);
358 daemon = SPDYF_start_daemon_va ( port,
359 certfile,
360 keyfile,
361 nscb,
362 sccb,
363 nrcb,
364 npdcb,
365 &spdy_handler_new_stream,
366 &spdy_handler_new_data,
367 cls,
368 NULL,
369 valist
370 );
371 va_end(valist);
372
373 return daemon;
374}
375
376
377void
378SPDY_stop_daemon (struct SPDY_Daemon *daemon)
379{
380 if(NULL == daemon)
381 {
382 SPDYF_DEBUG("daemon is NULL");
383 return;
384 }
385
386 SPDYF_stop_daemon(daemon);
387}
388
389
390struct SPDY_Response *
391SPDY_build_response(int status,
392 const char * statustext,
393 const char * version,
394 struct SPDY_NameValue * headers,
395 const void * data,
396 size_t size)
397{
398 struct SPDY_Response *response = NULL;
399 struct SPDY_NameValue ** all_headers = NULL; //TODO maybe array in stack is enough
400 char *fullstatus = NULL;
401 int ret;
402 int num_hdr_containers = 1;
403
404 if(NULL == version)
405 {
406 SPDYF_DEBUG("version is NULL");
407 return NULL;
408 }
409
410 if(NULL == (response = malloc(sizeof(struct SPDY_Response))))
411 goto free_and_fail;
412 memset(response, 0, sizeof(struct SPDY_Response));
413
414 if(NULL != headers && !SPDYF_name_value_is_empty(headers))
415 num_hdr_containers = 2;
416
417 if(NULL == (all_headers = malloc(num_hdr_containers * sizeof(struct SPDY_NameValue *))))
418 goto free_and_fail;
419 memset(all_headers, 0, num_hdr_containers * sizeof(struct SPDY_NameValue *));
420
421 if(2 == num_hdr_containers)
422 all_headers[1] = headers;
423
424 if(NULL == (all_headers[0] = SPDY_name_value_create()))
425 goto free_and_fail;
426
427 if(NULL == statustext)
428 ret = asprintf(&fullstatus, "%i", status);
429 else
430 ret = asprintf(&fullstatus, "%i %s", status, statustext);
431 if(-1 == ret)
432 goto free_and_fail;
433
434 if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":status", fullstatus))
435 goto free_and_fail;
436
437 free(fullstatus);
438 fullstatus = NULL;
439
440 if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":version", version))
441 goto free_and_fail;
442
443 if(0 >= (response->headers_size = SPDYF_name_value_to_stream(all_headers,
444 num_hdr_containers,
445 &(response->headers))))
446 goto free_and_fail;
447
448 SPDY_name_value_destroy(all_headers[0]);
449 free(all_headers);
450 all_headers = NULL;
451
452 if(size > 0)
453 {
454 //copy the data to the response object
455 if(NULL == (response->data = malloc(size)))
456 {
457 free(response->headers);
458 goto free_and_fail;
459 }
460 memcpy(response->data, data, size);
461 response->data_size = size;
462 }
463
464 return response;
465
466 //for GOTO
467 free_and_fail:
468
469 free(fullstatus);
470 if(NULL != all_headers)
471 SPDY_name_value_destroy(all_headers[0]);
472 free(all_headers);
473 free(response);
474
475 return NULL;
476}
477
478
479struct SPDY_Response *
480SPDY_build_response_with_callback(int status,
481 const char * statustext,
482 const char * version,
483 struct SPDY_NameValue * headers,
484 SPDY_ResponseCallback rcb,
485 void *rcb_cls,
486 uint32_t block_size)
487{
488 struct SPDY_Response *response;
489
490 if(NULL == rcb)
491 {
492 SPDYF_DEBUG("rcb is NULL");
493 return NULL;
494 }
495 if(block_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)
496 {
497 SPDYF_DEBUG("block_size is wrong");
498 return NULL;
499 }
500
501 if(0 == block_size)
502 block_size = SPDY_MAX_SUPPORTED_FRAME_SIZE;
503
504 response = SPDY_build_response(status,
505 statustext,
506 version,
507 headers,
508 NULL,
509 0);
510
511 if(NULL == response)
512 {
513 return NULL;
514 }
515
516 response->rcb = rcb;
517 response->rcb_cls = rcb_cls;
518 response->rcb_block_size = block_size;
519
520 return response;
521}
522
523
524int
525SPDY_queue_response (struct SPDY_Request * request,
526 struct SPDY_Response *response,
527 bool closestream,
528 bool consider_priority,
529 SPDY_ResponseResultCallback rrcb,
530 void * rrcb_cls)
531{
532 struct SPDYF_Response_Queue *headers_to_queue;
533 struct SPDYF_Response_Queue *body_to_queue;
534 SPDYF_ResponseQueueResultCallback frqcb = NULL;
535 void *frqcb_cls = NULL;
536 int int_consider_priority = consider_priority ? SPDY_YES : SPDY_NO;
537
538 if(NULL == request)
539 {
540 SPDYF_DEBUG("request is NULL");
541 return SPDY_INPUT_ERROR;
542 }
543 if(NULL == response)
544 {
545 SPDYF_DEBUG("request is NULL");
546 return SPDY_INPUT_ERROR;
547 }
548
549 if(request->stream->is_out_closed
550 || SPDY_SESSION_STATUS_CLOSING == request->stream->session->status)
551 return SPDY_NO;
552
553 if(NULL != rrcb)
554 {
555 frqcb_cls = request;
556 frqcb = &spdy_handler_response_queue_result;
557 }
558
559 if(response->data_size > 0)
560 {
561 //SYN_REPLY and DATA will be queued
562
563 if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
564 response->headers,
565 response->headers_size,
566 response,
567 request->stream,
568 false,
569 NULL,
570 NULL,
571 NULL,
572 NULL)))
573 {
574 return SPDY_NO;
575 }
576
577 if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
578 response->data,
579 response->data_size,
580 response,
581 request->stream,
582 closestream,
583 frqcb,
584 frqcb_cls,
585 rrcb,
586 rrcb_cls)))
587 {
588 SPDYF_response_queue_destroy(headers_to_queue);
589 return SPDY_NO;
590 }
591
592 SPDYF_queue_response (headers_to_queue,
593 request->stream->session,
594 int_consider_priority);
595
596 SPDYF_queue_response (body_to_queue,
597 request->stream->session,
598 int_consider_priority);
599 }
600 else if(NULL == response->rcb)
601 {
602 //no "body" will be queued, e.g. HTTP 404 without body
603
604 if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
605 response->headers,
606 response->headers_size,
607 response,
608 request->stream,
609 closestream,
610 frqcb,
611 frqcb_cls,
612 rrcb,
613 rrcb_cls)))
614 {
615 return SPDY_NO;
616 }
617
618 SPDYF_queue_response (headers_to_queue,
619 request->stream->session,
620 int_consider_priority);
621 }
622 else
623 {
624 //response with callbacks
625
626 if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
627 response->headers,
628 response->headers_size,
629 response,
630 request->stream,
631 false,
632 NULL,
633 NULL,
634 NULL,
635 NULL)))
636 {
637 return SPDY_NO;
638 }
639
640 if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
641 response->data,
642 response->data_size,
643 response,
644 request->stream,
645 closestream,
646 frqcb,
647 frqcb_cls,
648 rrcb,
649 rrcb_cls)))
650 {
651 SPDYF_response_queue_destroy(headers_to_queue);
652 return SPDY_NO;
653 }
654
655 SPDYF_queue_response (headers_to_queue,
656 request->stream->session,
657 int_consider_priority);
658
659 SPDYF_queue_response (body_to_queue,
660 request->stream->session,
661 int_consider_priority);
662 }
663
664 return SPDY_YES;
665}
666
667
668socklen_t
669SPDY_get_remote_addr(struct SPDY_Session * session,
670 struct sockaddr ** addr)
671{
672 if(NULL == session)
673 {
674 SPDYF_DEBUG("session is NULL");
675 return 0;
676 }
677
678 *addr = session->addr;
679
680 return session->addr_len;
681}
682
683
684struct SPDY_Session *
685SPDY_get_session_for_request(const struct SPDY_Request * request)
686{
687 if(NULL == request)
688 {
689 SPDYF_DEBUG("request is NULL");
690 return NULL;
691 }
692
693 return request->stream->session;
694}
695
696
697void *
698SPDY_get_cls_from_session(struct SPDY_Session * session)
699{
700 if(NULL == session)
701 {
702 SPDYF_DEBUG("session is NULL");
703 return NULL;
704 }
705
706 return session->user_cls;
707}
708
709
710void
711SPDY_set_cls_to_session(struct SPDY_Session * session,
712 void * cls)
713{
714 if(NULL == session)
715 {
716 SPDYF_DEBUG("session is NULL");
717 return;
718 }
719
720 session->user_cls = cls;
721}
722
723
724void *
725SPDY_get_cls_from_request(struct SPDY_Request * request)
726{
727 if(NULL == request)
728 {
729 SPDYF_DEBUG("request is NULL");
730 return NULL;
731 }
732
733 return request->user_cls;
734}
735
736
737void
738SPDY_set_cls_to_request(struct SPDY_Request * request,
739 void * cls)
740{
741 if(NULL == request)
742 {
743 SPDYF_DEBUG("request is NULL");
744 return;
745 }
746
747 request->user_cls = cls;
748}
diff --git a/src/microspdy/applicationlayer.h b/src/microspdy/applicationlayer.h
deleted file mode 100644
index a36760fe..00000000
--- a/src/microspdy/applicationlayer.h
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file applicationlayer.h
21 * @brief SPDY application or HTTP layer
22 * @author Andrey Uzunov
23 */
24
25#ifndef APPLICATIONLAYER_H
26#define APPLICATIONLAYER_H
27
28#include "platform.h"
29
30
31#endif
diff --git a/src/microspdy/compression.c b/src/microspdy/compression.c
deleted file mode 100644
index 532ab64a..00000000
--- a/src/microspdy/compression.c
+++ /dev/null
@@ -1,441 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file compression.c
21 * @brief zlib handling functions
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27#include "internal.h"
28#include "compression.h"
29
30/* spdy ver 3 specific dictionary used by zlib */
31static const unsigned char
32spdyf_zlib_dictionary[] = {
33 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // - - - - o p t i
34 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // o n s - - - - h
35 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // e a d - - - - p
36 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // o s t - - - - p
37 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // u t - - - - d e
38 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // l e t e - - - -
39 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // t r a c e - - -
40 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // - a c c e p t -
41 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
42 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t - c h a r s e
43 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t - - - - a c c
44 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e p t - e n c o
45 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // d i n g - - - -
46 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // a c c e p t - l
47 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // a n g u a g e -
48 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
49 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t - r a n g e s
50 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // - - - - a g e -
51 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // - - - a l l o w
52 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // - - - - a u t h
53 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // o r i z a t i o
54 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n - - - - c a c
55 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // h e - c o n t r
56 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // o l - - - - c o
57 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // n n e c t i o n
58 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
59 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // e n t - b a s e
60 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
61 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e n t - e n c o
62 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // d i n g - - - -
63 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // c o n t e n t -
64 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // l a n g u a g e
65 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
66 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // e n t - l e n g
67 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // t h - - - - c o
68 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // n t e n t - l o
69 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // c a t i o n - -
70 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
71 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t - m d 5 - - -
72 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // - c o n t e n t
73 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // - r a n g e - -
74 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
75 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t - t y p e - -
76 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // - - d a t e - -
77 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // - - e t a g - -
78 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // - - e x p e c t
79 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // - - - - e x p i
80 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // r e s - - - - f
81 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // r o m - - - - h
82 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // o s t - - - - i
83 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f - m a t c h -
84 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // - - - i f - m o
85 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // d i f i e d - s
86 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // i n c e - - - -
87 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // i f - n o n e -
88 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // m a t c h - - -
89 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // - i f - r a n g
90 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e - - - - i f -
91 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // u n m o d i f i
92 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // e d - s i n c e
93 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // - - - - l a s t
94 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // - m o d i f i e
95 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d - - - - l o c
96 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // a t i o n - - -
97 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // - m a x - f o r
98 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // w a r d s - - -
99 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // - p r a g m a -
100 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // - - - p r o x y
101 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // - a u t h e n t
102 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // i c a t e - - -
103 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // - p r o x y - a
104 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // u t h o r i z a
105 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // t i o n - - - -
106 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // r a n g e - - -
107 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // - r e f e r e r
108 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // - - - - r e t r
109 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y - a f t e r -
110 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // - - - s e r v e
111 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r - - - - t e -
112 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // - - - t r a i l
113 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // e r - - - - t r
114 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // a n s f e r - e
115 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // n c o d i n g -
116 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // - - - u p g r a
117 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // d e - - - - u s
118 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // e r - a g e n t
119 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // - - - - v a r y
120 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // - - - - v i a -
121 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // - - - w a r n i
122 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // n g - - - - w w
123 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w - a u t h e n
124 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // t i c a t e - -
125 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // - - m e t h o d
126 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // - - - - g e t -
127 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // - - - s t a t u
128 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s - - - - 2 0 0
129 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // - O K - - - - v
130 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // e r s i o n - -
131 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // - - H T T P - 1
132 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // - 1 - - - - u r
133 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l - - - - p u b
134 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // l i c - - - - s
135 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // e t - c o o k i
136 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e - - - - k e e
137 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p - a l i v e -
138 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // - - - o r i g i
139 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n 1 0 0 1 0 1 2
140 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 0 1 2 0 2 2 0 5
141 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 2 0 6 3 0 0 3 0
142 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 2 3 0 3 3 0 4 3
143 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 0 5 3 0 6 3 0 7
144 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 4 0 2 4 0 5 4 0
145 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 6 4 0 7 4 0 8 4
146 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 0 9 4 1 0 4 1 1
147 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 4 1 2 4 1 3 4 1
148 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 4 4 1 5 4 1 6 4
149 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 1 7 5 0 2 5 0 4
150 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 5 0 5 2 0 3 - N
151 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // o n - A u t h o
152 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // r i t a t i v e
153 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // - I n f o r m a
154 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // t i o n 2 0 4 -
155 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // N o - C o n t e
156 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // n t 3 0 1 - M o
157 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // v e d - P e r m
158 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // a n e n t l y 4
159 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 0 0 - B a d - R
160 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // e q u e s t 4 0
161 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1 - U n a u t h
162 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // o r i z e d 4 0
163 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3 - F o r b i d
164 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // d e n 4 0 4 - N
165 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // o t - F o u n d
166 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 5 0 0 - I n t e
167 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // r n a l - S e r
168 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // v e r - E r r o
169 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r 5 0 1 - N o t
170 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // - I m p l e m e
171 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // n t e d 5 0 3 -
172 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // S e r v i c e -
173 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // U n a v a i l a
174 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // b l e J a n - F
175 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // e b - M a r - A
176 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // p r - M a y - J
177 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // u n - J u l - A
178 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // u g - S e p t -
179 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // O c t - N o v -
180 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // D e c - 0 0 - 0
181 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0 - 0 0 - M o n
182 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // - - T u e - - W
183 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // e d - - T h u -
184 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // - F r i - - S a
185 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t - - S u n - -
186 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // G M T c h u n k
187 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // e d - t e x t -
188 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // h t m l - i m a
189 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // g e - p n g - i
190 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // m a g e - j p g
191 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // - i m a g e - g
192 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // i f - a p p l i
193 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
194 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // m l - a p p l i
195 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
196 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // h t m l - x m l
197 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // - t e x t - p l
198 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // a i n - t e x t
199 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // - j a v a s c r
200 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // i p t - p u b l
201 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // i c p r i v a t
202 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // e m a x - a g e
203 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // - g z i p - d e
204 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // f l a t e - s d
205 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // c h c h a r s e
206 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t - u t f - 8 c
207 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // h a r s e t - i
208 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // s o - 8 8 5 9 -
209 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1 - u t f - - -
210 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // - e n q - 0 -
211};
212
213
214int
215SPDYF_zlib_deflate_init(z_stream *strm)
216{
217 int ret;
218
219 strm->zalloc = Z_NULL;
220 strm->zfree = Z_NULL;
221 strm->opaque = Z_NULL;
222 //the second argument is "level of compression"
223 //use 0 for no compression; 9 for best compression
224 ret = deflateInit(strm, Z_DEFAULT_COMPRESSION);
225 if(ret != Z_OK)
226 {
227 SPDYF_DEBUG("deflate init");
228 return SPDY_NO;
229 }
230 ret = deflateSetDictionary(strm,
231 spdyf_zlib_dictionary,
232 sizeof(spdyf_zlib_dictionary));
233 if(ret != Z_OK)
234 {
235 SPDYF_DEBUG("deflate set dict");
236 deflateEnd(strm);
237 return SPDY_NO;
238 }
239 return SPDY_YES;
240}
241
242
243void
244SPDYF_zlib_deflate_end(z_stream *strm)
245{
246 deflateEnd(strm);
247}
248
249int
250SPDYF_zlib_deflate(z_stream *strm,
251 const void *src,
252 size_t src_size,
253 size_t *data_used,
254 void **dest,
255 size_t *dest_size)
256{
257 int ret;
258 int flush;
259 unsigned int have;
260 Bytef out[SPDYF_ZLIB_CHUNK];
261
262 *dest = NULL;
263 *dest_size = 0;
264
265 do
266 {
267 /* check for big data bigger than the buffer used */
268 if(src_size > SPDYF_ZLIB_CHUNK)
269 {
270 strm->avail_in = SPDYF_ZLIB_CHUNK;
271 src_size -= SPDYF_ZLIB_CHUNK;
272 /* flush is used for the loop to detect if we still
273 * need to supply additional
274 * data to the stream via avail_in and next_in. */
275 flush = Z_NO_FLUSH;
276 }
277 else
278 {
279 strm->avail_in = src_size;
280 flush = Z_SYNC_FLUSH;
281 }
282 *data_used += strm->avail_in;
283
284 strm->next_in = (Bytef *)src;
285
286 /* Loop while output data is available */
287 do
288 {
289 strm->avail_out = SPDYF_ZLIB_CHUNK;
290 strm->next_out = out;
291
292 /* No need to check return value of deflate.
293 * (See zlib documentation at http://www.zlib.net/zlib_how.html */
294 ret = deflate(strm, flush);
295 have = SPDYF_ZLIB_CHUNK - strm->avail_out;
296
297 /* (Re)allocate memory for dest and keep track of it's size. */
298 *dest_size += have;
299 *dest = realloc(*dest, *dest_size);
300 if(!*dest)
301 {
302 SPDYF_DEBUG("realloc data for result");
303 deflateEnd(strm);
304 return SPDY_NO;
305 }
306 memcpy((*dest) + ((*dest_size) - have), out, have);
307 }
308 while(strm->avail_out == 0);
309 /* At this point, all of the input data should already
310 * have been used. */
311 SPDYF_ASSERT(strm->avail_in == 0,"compressing bug");
312 }
313 while(flush != Z_SYNC_FLUSH);
314
315 return Z_OK == ret ? SPDY_YES : SPDY_NO;
316}
317
318
319int
320SPDYF_zlib_inflate_init(z_stream *strm)
321{
322 int ret;
323
324 strm->zalloc = Z_NULL;
325 strm->zfree = Z_NULL;
326 strm->opaque = Z_NULL;
327 strm->avail_in = 0;
328 strm->next_in = Z_NULL;
329 //change 15 to lower value for performance and benchmark
330 //"The windowBits parameter is the base two logarithm of the
331 // maximum window size (the size of the history buffer)."
332 ret = inflateInit2(strm, 15);
333 if(ret != Z_OK)
334 {
335 SPDYF_DEBUG("Cannot inflateInit2 the stream");
336 return SPDY_NO;
337 }
338 return SPDY_YES;
339}
340
341
342void
343SPDYF_zlib_inflate_end(z_stream *strm)
344{
345 inflateEnd(strm);
346}
347
348
349int
350SPDYF_zlib_inflate(z_stream *strm,
351 const void *src,
352 size_t src_size,
353 void **dest,
354 size_t *dest_size)
355{
356 int ret = Z_OK;
357 uint32_t have;
358 Bytef out[SPDYF_ZLIB_CHUNK];
359
360 *dest = NULL;
361 *dest_size = 0;
362
363 /* decompress until deflate stream ends or end of file */
364 do
365 {
366 if(src_size > SPDYF_ZLIB_CHUNK)
367 {
368 strm->avail_in = SPDYF_ZLIB_CHUNK;
369 src_size -= SPDYF_ZLIB_CHUNK;
370 }
371 else
372 {
373 strm->avail_in = src_size;
374 src_size = 0;
375 }
376
377 if(strm->avail_in == 0){
378 //the loop breaks always here as the stream never ends
379 break;
380 }
381
382 strm->next_in = (Bytef *) src;
383 /* run inflate() on input until output buffer not full */
384 do {
385 strm->avail_out = SPDYF_ZLIB_CHUNK;
386 strm->next_out = out;
387 ret = inflate(strm, Z_SYNC_FLUSH);
388
389 switch (ret)
390 {
391 case Z_STREAM_ERROR:
392 SPDYF_DEBUG("Error on inflate");
393 //no inflateEnd here, same in zlib example
394 return SPDY_NO;
395
396 case Z_NEED_DICT:
397 ret = inflateSetDictionary(strm,
398 spdyf_zlib_dictionary,
399 sizeof(spdyf_zlib_dictionary));
400 if(ret != Z_OK)
401 {
402 SPDYF_DEBUG("Error on inflateSetDictionary");
403 inflateEnd(strm);
404 return SPDY_NO;
405 }
406 ret = inflate(strm, Z_SYNC_FLUSH);
407 if(Z_STREAM_ERROR == ret)
408 {
409 SPDYF_DEBUG("Error on inflate");
410 return SPDY_NO;
411 }
412 break;
413
414 case Z_DATA_ERROR:
415 SPDYF_DEBUG("Z_DATA_ERROR");
416 inflateEnd(strm);
417 return SPDY_NO;
418
419 case Z_MEM_ERROR:
420 SPDYF_DEBUG("Z_MEM_ERROR");
421 inflateEnd(strm);
422 return SPDY_NO;
423 }
424 have = SPDYF_ZLIB_CHUNK - strm->avail_out;
425 *dest_size += have;
426 /* (re)alloc memory for the output buffer */
427 *dest = realloc(*dest, *dest_size);
428 if(!*dest)
429 {
430 SPDYF_DEBUG("Cannot realloc memory");
431 inflateEnd(strm);
432 return SPDY_NO;
433 }
434 memcpy((*dest) + ((*dest_size) - have), out, have);
435 }
436 while (0 == strm->avail_out);
437 }
438 while (Z_STREAM_END != ret);
439
440 return Z_OK == ret || Z_STREAM_END == ret ? SPDY_YES : SPDY_NO;
441}
diff --git a/src/microspdy/compression.h b/src/microspdy/compression.h
deleted file mode 100644
index 40746e78..00000000
--- a/src/microspdy/compression.h
+++ /dev/null
@@ -1,117 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file compression.h
21 * @brief zlib handling functions
22 * @author Andrey Uzunov
23 */
24
25#ifndef COMPRESSION_H
26#define COMPRESSION_H
27
28#include "platform.h"
29
30/* size of buffers used by zlib on (de)compressing */
31#define SPDYF_ZLIB_CHUNK 16384
32
33
34/**
35 * Initializes the zlib stream for compression. Must be called once
36 * for a session on initialization.
37 *
38 * @param strm Zlib stream on which we work
39 * @return SPDY_NO if zlib failed. SPDY_YES otherwise
40 */
41int
42SPDYF_zlib_deflate_init(z_stream *strm);
43
44
45/**
46 * Deinitializes the zlib stream for compression. Should be called once
47 * for a session on cleaning up.
48 *
49 * @param strm Zlib stream on which we work
50 */
51void
52SPDYF_zlib_deflate_end(z_stream *strm);
53
54
55/**
56 * Compressing stream with zlib.
57 *
58 * @param strm Zlib stream on which we work
59 * @param src stream of the data to be compressed
60 * @param src_size size of the data
61 * @param data_used the number of bytes from src_stream that were used
62 * TODO do we need
63 * @param dest the resulting compressed stream. Should be NULL. Must be
64 * freed later manually.
65 * @param dest_size size of the data after compression
66 * @return SPDY_NO if malloc or zlib failed. SPDY_YES otherwise
67 */
68int
69SPDYF_zlib_deflate(z_stream *strm,
70 const void *src,
71 size_t src_size,
72 size_t *data_used,
73 void **dest,
74 size_t *dest_size);
75
76
77/**
78 * Initializes the zlib stream for decompression. Must be called once
79 * for a session.
80 *
81 * @param strm Zlib stream on which we work
82 * @return SPDY_NO if zlib failed. SPDY_YES otherwise
83 */
84int
85SPDYF_zlib_inflate_init(z_stream *strm);
86
87
88/**
89 * Deinitializes the zlib stream for decompression. Should be called once
90 * for a session on cleaning up.
91 *
92 * @param strm Zlib stream on which we work
93 */
94void
95SPDYF_zlib_inflate_end(z_stream *strm);
96
97
98/**
99 * Decompressing stream with zlib.
100 *
101 * @param strm Zlib stream on which we work
102 * @param src stream of the data to be decompressed
103 * @param src_size size of the data
104 * @param dest the resulting decompressed stream. Should be NULL. Must
105 * be freed manually.
106 * @param dest_size size of the data after decompression
107 * @return SPDY_NO if malloc or zlib failed. SPDY_YES otherwise. If the
108 * function fails, the SPDY session must be closed
109 */
110int
111SPDYF_zlib_inflate(z_stream *strm,
112 const void *src,
113 size_t src_size,
114 void **dest,
115 size_t *dest_size);
116
117#endif
diff --git a/src/microspdy/daemon.c b/src/microspdy/daemon.c
deleted file mode 100644
index ca6f0da7..00000000
--- a/src/microspdy/daemon.c
+++ /dev/null
@@ -1,544 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file microspdy/daemon.c
21 * @brief daemon functionality
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27#include "internal.h"
28#include "session.h"
29#include "io.h"
30
31
32/**
33 * Default implementation of the panic function,
34 * prints an error message and aborts.
35 *
36 * @param cls unused
37 * @param file name of the file with the problem
38 * @param line line number with the problem
39 * @param reason error message with details
40 */
41static void
42spdyf_panic_std (void *cls,
43 const char *file,
44 unsigned int line,
45 const char *reason)
46{
47 (void)cls;
48 fprintf (stdout, "Fatal error in libmicrospdy %s:%u: %s\n",
49 file, line, reason);
50 //raise(SIGINT); //used for gdb
51 abort ();
52}
53
54
55/**
56 * Global handler for fatal errors.
57 */
58SPDY_PanicCallback spdyf_panic = &spdyf_panic_std;
59
60
61/**
62 * Global closure argument for "spdyf_panic".
63 */
64void *spdyf_panic_cls;
65
66
67/**
68 * Free resources associated with all closed connections.
69 * (destroy responses, free buffers, etc.).
70 *
71 * @param daemon daemon to clean up
72 */
73static void
74spdyf_cleanup_sessions (struct SPDY_Daemon *daemon)
75{
76 struct SPDY_Session *session;
77
78 while (NULL != (session = daemon->cleanup_head))
79 {
80 DLL_remove (daemon->cleanup_head,
81 daemon->cleanup_tail,
82 session);
83
84 SPDYF_session_destroy(session);
85 }
86}
87
88
89/**
90 * Closing of all connections handled by the daemon.
91 *
92 * @param daemon SPDY daemon
93 */
94static void
95spdyf_close_all_sessions (struct SPDY_Daemon *daemon)
96{
97 struct SPDY_Session *session;
98
99 while (NULL != (session = daemon->sessions_head))
100 {
101 //prepare GOAWAY frame
102 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
103 //try to send the frame (it is best effort, so it will maybe sent)
104 SPDYF_session_write(session,true);
105 SPDYF_session_close(session);
106 }
107
108 spdyf_cleanup_sessions(daemon);
109}
110
111
112/**
113 * Parse a list of options given as varargs.
114 *
115 * @param daemon the daemon to initialize
116 * @param valist the options
117 * @return SPDY_YES on success, SPDY_NO on error
118 */
119static int
120spdyf_parse_options_va (struct SPDY_Daemon *daemon,
121 va_list valist)
122{
123 enum SPDY_DAEMON_OPTION opt;
124
125 while (SPDY_DAEMON_OPTION_END != (opt = (enum SPDY_DAEMON_OPTION) va_arg (valist, int)))
126 {
127 if(opt & daemon->options)
128 {
129 SPDYF_DEBUG("Daemon option %i used twice",opt);
130 return SPDY_NO;
131 }
132 daemon->options |= opt;
133
134 switch (opt)
135 {
136 case SPDY_DAEMON_OPTION_SESSION_TIMEOUT:
137 daemon->session_timeout = va_arg (valist, unsigned int) * 1000;
138 break;
139 case SPDY_DAEMON_OPTION_SOCK_ADDR:
140 daemon->address = va_arg (valist, struct sockaddr *);
141 break;
142 case SPDY_DAEMON_OPTION_FLAGS:
143 daemon->flags = va_arg (valist, enum SPDY_DAEMON_FLAG);
144 break;
145 case SPDY_DAEMON_OPTION_IO_SUBSYSTEM:
146 daemon->io_subsystem = va_arg (valist, enum SPDY_IO_SUBSYSTEM);
147 break;
148 case SPDY_DAEMON_OPTION_MAX_NUM_FRAMES:
149 daemon->max_num_frames = va_arg (valist, uint32_t);
150 break;
151 default:
152 SPDYF_DEBUG("Wrong option for the daemon %i",opt);
153 return SPDY_NO;
154 }
155 }
156 return SPDY_YES;
157}
158
159
160void
161SPDY_set_panic_func (SPDY_PanicCallback cb,
162 void *cls)
163{
164 spdyf_panic = cb;
165 spdyf_panic_cls = cls;
166}
167
168
169struct SPDY_Daemon *
170SPDYF_start_daemon_va (uint16_t port,
171 const char *certfile,
172 const char *keyfile,
173 SPDY_NewSessionCallback nscb,
174 SPDY_SessionClosedCallback sccb,
175 SPDY_NewRequestCallback nrcb,
176 SPDY_NewDataCallback npdcb,
177 SPDYF_NewStreamCallback fnscb,
178 SPDYF_NewDataCallback fndcb,
179 void * cls,
180 void * fcls,
181 va_list valist)
182{
183 struct SPDY_Daemon *daemon = NULL;
184 int afamily;
185 int option_on = 1;
186 int ret;
187 struct sockaddr_in* servaddr4 = NULL;
188#if HAVE_INET6
189 struct sockaddr_in6* servaddr6 = NULL;
190#endif
191 socklen_t addrlen;
192
193 if (NULL == (daemon = malloc (sizeof (struct SPDY_Daemon))))
194 {
195 SPDYF_DEBUG("malloc");
196 return NULL;
197 }
198 memset (daemon, 0, sizeof (struct SPDY_Daemon));
199 daemon->socket_fd = -1;
200 daemon->port = port;
201
202 if(SPDY_YES != spdyf_parse_options_va (daemon, valist))
203 {
204 SPDYF_DEBUG("parse");
205 goto free_and_fail;
206 }
207
208 if(0 == daemon->max_num_frames)
209 daemon->max_num_frames = SPDYF_NUM_SENT_FRAMES_AT_ONCE;
210
211 if(!port && NULL == daemon->address)
212 {
213 SPDYF_DEBUG("Port is 0");
214 goto free_and_fail;
215 }
216 if(0 == daemon->io_subsystem)
217 daemon->io_subsystem = SPDY_IO_SUBSYSTEM_OPENSSL;
218
219 if(SPDY_YES != SPDYF_io_set_daemon(daemon, daemon->io_subsystem))
220 goto free_and_fail;
221
222 if(SPDY_IO_SUBSYSTEM_RAW != daemon->io_subsystem)
223 {
224 if (NULL == certfile
225 || NULL == (daemon->certfile = strdup (certfile)))
226 {
227 SPDYF_DEBUG("strdup (certfile)");
228 goto free_and_fail;
229 }
230 if (NULL == keyfile
231 || NULL == (daemon->keyfile = strdup (keyfile)))
232 {
233 SPDYF_DEBUG("strdup (keyfile)");
234 goto free_and_fail;
235 }
236 }
237
238 daemon->new_session_cb = nscb;
239 daemon->session_closed_cb = sccb;
240 daemon->new_request_cb = nrcb;
241 daemon->received_data_cb = npdcb;
242 daemon->cls = cls;
243 daemon->fcls = fcls;
244 daemon->fnew_stream_cb = fnscb;
245 daemon->freceived_data_cb = fndcb;
246
247#if HAVE_INET6
248 //handling IPv6
249 if((daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
250 && NULL != daemon->address && AF_INET6 != daemon->address->sa_family)
251 {
252 SPDYF_DEBUG("SPDY_DAEMON_FLAG_ONLY_IPV6 set but IPv4 address provided");
253 goto free_and_fail;
254 }
255
256 addrlen = sizeof (struct sockaddr_in6);
257
258 if(NULL == daemon->address)
259 {
260 if (NULL == (servaddr6 = malloc (addrlen)))
261 {
262 SPDYF_DEBUG("malloc");
263 goto free_and_fail;
264 }
265 memset (servaddr6, 0, addrlen);
266 servaddr6->sin6_family = AF_INET6;
267 servaddr6->sin6_addr = in6addr_any;
268 servaddr6->sin6_port = htons (port);
269 daemon->address = (struct sockaddr *) servaddr6;
270 }
271
272 if(AF_INET6 == daemon->address->sa_family)
273 {
274 afamily = PF_INET6;
275 }
276 else
277 {
278 afamily = PF_INET;
279 }
280#else
281 //handling IPv4
282 if(daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
283 {
284 SPDYF_DEBUG("SPDY_DAEMON_FLAG_ONLY_IPV6 set but no support");
285 goto free_and_fail;
286 }
287
288 addrlen = sizeof (struct sockaddr_in);
289
290 if(NULL == daemon->address)
291 {
292 if (NULL == (servaddr4 = malloc (addrlen)))
293 {
294 SPDYF_DEBUG("malloc");
295 goto free_and_fail;
296 }
297 memset (servaddr4, 0, addrlen);
298 servaddr4->sin_family = AF_INET;
299 servaddr4->sin_addr = INADDR_ANY;
300 servaddr4->sin_port = htons (port);
301 daemon->address = (struct sockaddr *) servaddr4;
302 }
303
304 afamily = PF_INET;
305#endif
306
307 daemon->socket_fd = socket (afamily, SOCK_STREAM, 0);
308 if (-1 == daemon->socket_fd)
309 {
310 SPDYF_DEBUG("sock");
311 goto free_and_fail;
312 }
313
314 //setting option for the socket to reuse address
315 ret = setsockopt(daemon->socket_fd, SOL_SOCKET, SO_REUSEADDR, &option_on, sizeof(option_on));
316 if(ret)
317 {
318 SPDYF_DEBUG("WARNING: SO_REUSEADDR was not set for the server");
319 }
320
321#if HAVE_INET6
322 if(daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
323 {
324 ret = setsockopt(daemon->socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, &option_on, sizeof(option_on));
325 if(ret)
326 {
327 SPDYF_DEBUG("setsockopt with IPPROTO_IPV6 failed");
328 goto free_and_fail;
329 }
330 }
331#endif
332
333 if (-1 == bind (daemon->socket_fd, daemon->address, addrlen))
334 {
335 SPDYF_DEBUG("bind %i",errno);
336 goto free_and_fail;
337 }
338
339 if (listen (daemon->socket_fd, 20) < 0)
340 {
341 SPDYF_DEBUG("listen %i",errno);
342 goto free_and_fail;
343 }
344
345 if(SPDY_YES != daemon->fio_init(daemon))
346 {
347 SPDYF_DEBUG("tls");
348 goto free_and_fail;
349 }
350
351 return daemon;
352
353 //for GOTO
354 free_and_fail:
355 if(daemon->socket_fd > 0)
356 (void)MHD_socket_close_ (daemon->socket_fd);
357
358 free(servaddr4);
359#if HAVE_INET6
360 free(servaddr6);
361#endif
362 if(NULL != daemon->certfile)
363 free(daemon->certfile);
364 if(NULL != daemon->keyfile)
365 free(daemon->keyfile);
366 free (daemon);
367
368 return NULL;
369}
370
371
372void
373SPDYF_stop_daemon (struct SPDY_Daemon *daemon)
374{
375 daemon->fio_deinit(daemon);
376
377 shutdown (daemon->socket_fd, SHUT_RDWR);
378 spdyf_close_all_sessions (daemon);
379 (void)MHD_socket_close_ (daemon->socket_fd);
380
381 if(!(SPDY_DAEMON_OPTION_SOCK_ADDR & daemon->options))
382 free(daemon->address);
383
384 free(daemon->certfile);
385 free(daemon->keyfile);
386
387 free(daemon);
388}
389
390
391int
392SPDYF_get_timeout (struct SPDY_Daemon *daemon,
393 unsigned long long *timeout)
394{
395 unsigned long long earliest_deadline = 0;
396 unsigned long long now;
397 struct SPDY_Session *pos;
398 bool have_timeout;
399
400 if(0 == daemon->session_timeout)
401 return SPDY_NO;
402
403 now = SPDYF_monotonic_time();
404 have_timeout = false;
405 for (pos = daemon->sessions_head; NULL != pos; pos = pos->next)
406 {
407 if ( (! have_timeout) ||
408 (earliest_deadline > pos->last_activity + daemon->session_timeout) )
409 earliest_deadline = pos->last_activity + daemon->session_timeout;
410
411 have_timeout = true;
412
413 if (SPDY_YES == pos->fio_is_pending(pos))
414 {
415 earliest_deadline = 0;
416 break;
417 }
418 }
419
420 if (!have_timeout)
421 return SPDY_NO;
422 if (earliest_deadline <= now)
423 *timeout = 0;
424 else
425 *timeout = earliest_deadline - now;
426
427 return SPDY_YES;
428}
429
430
431int
432SPDYF_get_fdset (struct SPDY_Daemon *daemon,
433 fd_set *read_fd_set,
434 fd_set *write_fd_set,
435 fd_set *except_fd_set,
436 bool all)
437{
438 (void)except_fd_set;
439 struct SPDY_Session *pos;
440 int fd;
441 int max_fd = -1;
442
443 fd = daemon->socket_fd;
444 if (-1 != fd)
445 {
446 FD_SET (fd, read_fd_set);
447 /* update max file descriptor */
448 max_fd = fd;
449 }
450
451 for (pos = daemon->sessions_head; NULL != pos; pos = pos->next)
452 {
453 fd = pos->socket_fd;
454 FD_SET(fd, read_fd_set);
455 if (all
456 || (NULL != pos->response_queue_head) //frames pending
457 || (NULL != pos->write_buffer) //part of last frame pending
458 || (SPDY_SESSION_STATUS_CLOSING == pos->status) //the session is about to be closed
459 || (daemon->session_timeout //timeout passed for the session
460 && (pos->last_activity + daemon->session_timeout < SPDYF_monotonic_time()))
461 || (SPDY_YES == pos->fio_is_pending(pos)) //data in TLS' read buffer pending
462 || ((pos->read_buffer_offset - pos->read_buffer_beginning) > 0) // data in lib's read buffer pending
463 )
464 FD_SET(fd, write_fd_set);
465 if(fd > max_fd)
466 max_fd = fd;
467 }
468
469 return max_fd;
470}
471
472
473void
474SPDYF_run (struct SPDY_Daemon *daemon)
475{
476 struct SPDY_Session *pos;
477 struct SPDY_Session *next;
478 int num_ready;
479 fd_set rs;
480 fd_set ws;
481 fd_set es;
482 int max;
483 struct timeval timeout;
484 int ds;
485
486 timeout.tv_sec = 0;
487 timeout.tv_usec = 0;
488 FD_ZERO (&rs);
489 FD_ZERO (&ws);
490 FD_ZERO (&es);
491 //here we need really all descriptors to see later which are ready
492 max = SPDYF_get_fdset(daemon,&rs,&ws,&es, true);
493
494 num_ready = select (max + 1, &rs, &ws, &es, &timeout);
495
496 if(num_ready < 1)
497 return;
498
499 if ( (-1 != (ds = daemon->socket_fd)) &&
500 (FD_ISSET (ds, &rs)) ){
501 SPDYF_session_accept(daemon);
502 }
503
504 next = daemon->sessions_head;
505 while (NULL != (pos = next))
506 {
507 next = pos->next;
508 ds = pos->socket_fd;
509 if (ds != -1)
510 {
511 //fill the read buffer
512 if (FD_ISSET (ds, &rs) || pos->fio_is_pending(pos)){
513 SPDYF_session_read(pos);
514 }
515
516 //do something with the data in read buffer
517 if(SPDY_NO == SPDYF_session_idle(pos))
518 {
519 //the session was closed, cannot write anymore
520 //continue;
521 }
522
523 //write whatever has been put to the response queue
524 //during read or idle operation, something might be put
525 //on the response queue, thus call write operation
526 if (FD_ISSET (ds, &ws)){
527 if(SPDY_NO == SPDYF_session_write(pos, false))
528 {
529 //SPDYF_session_close(pos);
530 //continue;
531 }
532 }
533
534 /* the response queue has been flushed for half closed
535 * connections, so let close them */
536 /*if(pos->read_closed)
537 {
538 SPDYF_session_close(pos);
539 }*/
540 }
541 }
542
543 spdyf_cleanup_sessions(daemon);
544}
diff --git a/src/microspdy/daemon.h b/src/microspdy/daemon.h
deleted file mode 100644
index cb3ed5fa..00000000
--- a/src/microspdy/daemon.h
+++ /dev/null
@@ -1,130 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file daemon.h
21 * @brief daemon functionality
22 * @author Andrey Uzunov
23 */
24
25#ifndef DAEMON_H
26#define DAEMON_H
27
28#include "platform.h"
29
30
31/**
32 * Global flags containing the initialized IO subsystems.
33 */
34enum SPDY_IO_SUBSYSTEM spdyf_io_initialized;
35
36
37/**
38 * Start a SPDDY webserver on the given port.
39 *
40 * @param port port to bind to
41 * @param certfile path to the certificate that will be used by server
42 * @param keyfile path to the keyfile for the certificate
43 * @param nscb callback called when a new SPDY session is
44 * established by a client
45 * @param sccb callback called when a client closes the session
46 * @param nrcb callback called when a client sends request
47 * @param npdcb callback called when HTTP POST params are received
48 * after request
49 * @param fnscb callback called when new stream is opened by a client
50 * @param fndcb callback called when new data -- within a data frame --
51 * is received by the server
52 * @param cls extra argument to all of the callbacks without those
53 * specific only for the framing layer
54 * @param fcls extra argument to all of the callbacks, specific only for
55 * the framing layer (those vars starting with 'f').
56 * @param valist va_list of options (type-value pairs,
57 * terminated with SPDY_DAEMON_OPTION_END).
58 * @return NULL on error, handle to daemon on success
59 */
60struct SPDY_Daemon *
61SPDYF_start_daemon_va (uint16_t port,
62 const char *certfile,
63 const char *keyfile,
64 SPDY_NewSessionCallback nscb,
65 SPDY_SessionClosedCallback sccb,
66 SPDY_NewRequestCallback nrcb,
67 SPDY_NewDataCallback npdcb,
68 SPDYF_NewStreamCallback fnscb,
69 SPDYF_NewDataCallback fndcb,
70 void * cls,
71 void * fcls,
72 va_list valist);
73
74
75/**
76 * Run webserver operations (without blocking unless
77 * in client callbacks). This method must be called in the client event
78 * loop.
79 *
80 * @param daemon daemon to run
81 */
82void
83SPDYF_run (struct SPDY_Daemon *daemon);
84
85
86/**
87 * Obtain timeout value for select for this daemon. The returned value
88 * is how long select
89 * should at most block, not the timeout value set for connections.
90 *
91 * @param daemon daemon to query for timeout
92 * @param timeout set to the timeout (in milliseconds)
93 * @return SPDY_YES on success, SPDY_NO if no connections exist that
94 * would necessiate the use of a timeout right now
95 */
96int
97SPDYF_get_timeout (struct SPDY_Daemon *daemon,
98 unsigned long long *timeout);
99
100
101/**
102 * Obtain the select sets for this daemon. The idea of SPDYF_get_fdset
103 * is to return such descriptors that the select in the application can
104 * return and SPDY_run can be called only when this is really needed.
105 * That means not all sockets will be added to write_fd_set.
106 *
107 * @param daemon daemon to get sets from
108 * @param read_fd_set read set
109 * @param write_fd_set write set
110 * @param except_fd_set except set
111 * @param all add all session's descriptors to write_fd_set or not
112 * @return largest FD added
113 */
114int
115SPDYF_get_fdset (struct SPDY_Daemon *daemon,
116 fd_set *read_fd_set,
117 fd_set *write_fd_set,
118 fd_set *except_fd_set,
119 bool all);
120
121
122/**
123 * Shutdown the daemon.
124 *
125 * @param daemon daemon to stop
126 */
127void
128SPDYF_stop_daemon (struct SPDY_Daemon *daemon);
129
130#endif
diff --git a/src/microspdy/internal.c b/src/microspdy/internal.c
deleted file mode 100644
index f0d2fc11..00000000
--- a/src/microspdy/internal.c
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file microspdy/internal.c
21 * @brief internal functions and macros for the framing layer
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27
28
29unsigned long long
30SPDYF_monotonic_time (void)
31{
32#ifdef HAVE_CLOCK_GETTIME
33#ifdef CLOCK_MONOTONIC
34 struct timespec ts;
35 if (0 == clock_gettime (CLOCK_MONOTONIC, &ts))
36 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
37#endif
38#endif
39 return time (NULL) * 1000;
40}
diff --git a/src/microspdy/internal.h b/src/microspdy/internal.h
deleted file mode 100644
index b5382c01..00000000
--- a/src/microspdy/internal.h
+++ /dev/null
@@ -1,199 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file microspdy/internal.h
21 * @brief internal functions and macros for the framing layer
22 * @author Andrey Uzunov
23 */
24
25#ifndef INTERNAL_H_H
26#define INTERNAL_H_H
27
28#include "platform.h"
29#include "platform_interface.h"
30#include "microspdy.h"
31
32/**
33 * size of read buffers for each connection
34 * must be at least the size of SPDY_MAX_SUPPORTED_FRAME_SIZE
35 */
36#define SPDYF_BUFFER_SIZE 8192
37
38/**
39 * initial size of window for each stream (this is for the data
40 * within data frames that can be handled)
41 */
42#define SPDYF_INITIAL_WINDOW_SIZE 65536
43
44/**
45 * number of frames written to the socket at once. After X frames
46 * everything should be run again. In this way the application can
47 * response to more important requests while a big file is still
48 * being transmitted to the client
49 */
50#define SPDYF_NUM_SENT_FRAMES_AT_ONCE 10
51
52
53/**
54 * Handler for fatal errors.
55 */
56extern SPDY_PanicCallback spdyf_panic;
57
58
59/**
60 * Closure argument for "mhd_panic".
61 */
62extern void *spdyf_panic_cls;
63
64
65/**
66 * Trigger 'panic' action based on fatal errors.
67 *
68 * @param msg error message (const char *)
69 */
70#define SPDYF_PANIC(msg) \
71 spdyf_panic (spdyf_panic_cls, __FILE__, __LINE__, msg)
72
73
74/**
75 * Asserts the validity of an expression.
76 *
77 * @param expr (bool)
78 * @param msg message to print on error (const char *)
79 */
80#define SPDYF_ASSERT(expr, msg) \
81 if(!(expr)){\
82 SPDYF_PANIC(msg);\
83 abort();\
84 }
85
86
87/**
88 * Convert 24 bit integer from host byte order to network byte order.
89 *
90 * @param n input value (int32_t)
91 * @return converted value (uint32_t)
92 */
93#if HAVE_BIG_ENDIAN
94#define HTON24(n) n
95#else
96#define HTON24(n) (((((uint32_t)(n) & 0xFF)) << 16)\
97 | (((uint32_t)(n) & 0xFF00))\
98 | ((((uint32_t)(n) & 0xFF0000)) >> 16))
99#endif
100
101
102/**
103 * Convert 24 bit integer from network byte order to host byte order.
104 *
105 * @param n input value (int32_t)
106 * @return converted value (uint32_t)
107 */
108#if HAVE_BIG_ENDIAN
109#define NTOH24(n) n
110#else
111#define NTOH24(n) (((((uint32_t)(n) & 0xFF)) << 16)\
112 | (((uint32_t)(n) & 0xFF00))\
113 | ((((uint32_t)(n) & 0xFF0000)) >> 16))
114#endif
115
116
117/**
118 * Convert 31 bit integer from network byte order to host byte order.
119 *
120 * @param n input value (int32_t)
121 * @return converted value (uint32_t)
122 */
123#if HAVE_BIG_ENDIAN
124#define NTOH31(n) n
125#else
126#define NTOH31(n) (((((uint32_t)(n) & 0x7F)) << 24) | \
127 ((((uint32_t)(n) & 0xFF00)) << 8) | \
128 ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
129 ((((uint32_t)(n) & 0xFF000000)) >> 24))
130#endif
131
132
133/**
134 * Convert 31 bit integer from host byte order to network byte order.
135 *
136 * @param n input value (int32_t)
137 * @return converted value (uint32_t)
138 */
139#if HAVE_BIG_ENDIAN
140#define HTON31(n) n
141#else
142#define HTON31(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
143 ((((uint32_t)(n) & 0xFF00)) << 8) | \
144 ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
145 ((((uint32_t)(n) & 0x7F000000)) >> 24))
146#endif
147
148
149/**
150 * Print formatted debug value.
151 *
152 * @param fmt format (const char *)
153 * @param ... args for format
154 */
155#define SPDYF_DEBUG(fmt, ...) do { \
156 fprintf (stdout, "%s\n%u: ",__FILE__, __LINE__);\
157 fprintf(stdout,fmt,##__VA_ARGS__);\
158 fprintf(stdout,"\n");\
159 fflush(stdout); } while (0)
160
161
162/**
163 * Print stream for debuging.
164 *
165 * @param strm (void *)
166 * @param size (int)
167 */
168#define SPDYF_PRINT_STREAM(strm, size) do { \
169 int ___i;\
170 for(___i=0;___i<size;___i++){\
171 fprintf(stdout,"%x ",*((uint8_t *) strm + ___i));\
172 fflush(stdout);\
173 }\
174 fprintf(stdout,"\n");\
175 } while (0)
176
177
178/**
179 * Print message and raise SIGINT for debug purposes.
180 *
181 * @param msg message (const char *)
182 */
183#define SPDYF_SIGINT(msg) do { \
184 fprintf(stdout,"%i : %s\n", __LINE__,__FILE__);\
185 fprintf(stdout,msg);\
186 fprintf(stdout,"\n");\
187 fflush(stdout);\
188 raise(SIGINT); } while (0)
189
190
191/**
192 * Returns monotonic time, to be used for session timeouts.
193 *
194 * @return time in milliseconds
195 */
196unsigned long long
197SPDYF_monotonic_time(void);
198
199#endif
diff --git a/src/microspdy/io.c b/src/microspdy/io.c
deleted file mode 100644
index c333c89a..00000000
--- a/src/microspdy/io.c
+++ /dev/null
@@ -1,90 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file io.c
21 * @brief Generic functions for IO.
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27#include "internal.h"
28#include "io.h"
29
30
31int
32SPDYF_io_set_daemon(struct SPDY_Daemon *daemon,
33 enum SPDY_IO_SUBSYSTEM io_subsystem)
34{
35 switch(io_subsystem)
36 {
37 case SPDY_IO_SUBSYSTEM_OPENSSL:
38 daemon->fio_init = &SPDYF_openssl_init;
39 daemon->fio_deinit = &SPDYF_openssl_deinit;
40 break;
41
42 case SPDY_IO_SUBSYSTEM_RAW:
43 daemon->fio_init = &SPDYF_raw_init;
44 daemon->fio_deinit = &SPDYF_raw_deinit;
45 break;
46
47 case SPDY_IO_SUBSYSTEM_NONE:
48 default:
49 SPDYF_DEBUG("Unsupported subsystem");
50 return SPDY_NO;
51 }
52
53 return SPDY_YES;
54}
55
56
57int
58SPDYF_io_set_session(struct SPDY_Session *session,
59 enum SPDY_IO_SUBSYSTEM io_subsystem)
60{
61 switch(io_subsystem)
62 {
63 case SPDY_IO_SUBSYSTEM_OPENSSL:
64 session->fio_new_session = &SPDYF_openssl_new_session;
65 session->fio_close_session = &SPDYF_openssl_close_session;
66 session->fio_is_pending = &SPDYF_openssl_is_pending;
67 session->fio_recv = &SPDYF_openssl_recv;
68 session->fio_send = &SPDYF_openssl_send;
69 session->fio_before_write = &SPDYF_openssl_before_write;
70 session->fio_after_write = &SPDYF_openssl_after_write;
71 break;
72
73 case SPDY_IO_SUBSYSTEM_RAW:
74 session->fio_new_session = &SPDYF_raw_new_session;
75 session->fio_close_session = &SPDYF_raw_close_session;
76 session->fio_is_pending = &SPDYF_raw_is_pending;
77 session->fio_recv = &SPDYF_raw_recv;
78 session->fio_send = &SPDYF_raw_send;
79 session->fio_before_write = &SPDYF_raw_before_write;
80 session->fio_after_write = &SPDYF_raw_after_write;
81 break;
82
83 case SPDY_IO_SUBSYSTEM_NONE:
84 default:
85 SPDYF_DEBUG("Unsupported subsystem");
86 return SPDY_NO;
87 }
88
89 return SPDY_YES;
90}
diff --git a/src/microspdy/io.h b/src/microspdy/io.h
deleted file mode 100644
index c28ba21b..00000000
--- a/src/microspdy/io.h
+++ /dev/null
@@ -1,216 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file io.h
21 * @brief Signatures for IO functions.
22 * @author Andrey Uzunov
23 */
24
25#ifndef IO_H
26#define IO_H
27
28#include "platform.h"
29#include "io_openssl.h"
30#include "io_raw.h"
31
32
33/**
34 * Used for return code when reading and writing to the TLS socket.
35 */
36enum SPDY_IO_ERROR
37{
38 /**
39 * The connection was closed by the other party.
40 */
41 SPDY_IO_ERROR_CLOSED = 0,
42
43 /**
44 * Any kind of error ocurred. The session has to be closed.
45 */
46 SPDY_IO_ERROR_ERROR = -2,
47
48 /**
49 * The function had to return without processing any data. The whole
50 * cycle of events has to be called again (SPDY_run) as something
51 * either has to be written or read or the the syscall was
52 * interrupted by a signal.
53 */
54 SPDY_IO_ERROR_AGAIN = -3,
55};
56
57
58/**
59 * Global initializing. Must be called only once in the program.
60 *
61 */
62typedef void
63(*SPDYF_IOGlobalInit) ();
64
65
66/**
67 * Global deinitializing for the whole program. Should be called
68 * at the end of the program.
69 *
70 */
71typedef void
72(*SPDYF_IOGlobalDeinit) ();
73
74
75/**
76 * Initializing of io context for a specific daemon.
77 * Must be called when the daemon starts.
78 *
79 * @param daemon SPDY_Daemon for which io will be used. Daemon's
80 * certificate and key file are used for tls.
81 * @return SPDY_YES on success or SPDY_NO on error
82 */
83typedef int
84(*SPDYF_IOInit) (struct SPDY_Daemon *daemon);
85
86
87/**
88 * Deinitializing io context for a daemon. Should be called
89 * when the deamon is stopped.
90 *
91 * @param daemon SPDY_Daemon which is being stopped
92 */
93typedef void
94(*SPDYF_IODeinit) (struct SPDY_Daemon *daemon);
95
96
97/**
98 * Initializing io for a specific connection. Must be called
99 * after the connection has been accepted.
100 *
101 * @param session SPDY_Session whose socket will be used
102 * @return SPDY_NO if some funcs inside fail. SPDY_YES otherwise
103 */
104typedef int
105(*SPDYF_IONewSession) (struct SPDY_Session *session);
106
107
108/**
109 * Deinitializing io for a specific connection. Should be called
110 * closing session's socket.
111 *
112 * @param session SPDY_Session whose socket is used
113 */
114typedef void
115(*SPDYF_IOCloseSession) (struct SPDY_Session *session);
116
117
118/**
119 * Reading from session's socket. Reads available data and put it to the
120 * buffer.
121 *
122 * @param session for which data is received
123 * @param buffer where data from the socket will be written to
124 * @param size of the buffer
125 * @return number of bytes (at most size) read from the connection
126 * 0 if the other party has closed the connection
127 * SPDY_IO_ERROR code on error
128 */
129typedef int
130(*SPDYF_IORecv) (struct SPDY_Session *session,
131 void * buffer,
132 size_t size);
133
134
135/**
136 * Writing to session's socket. Writes the data given into the buffer to the
137 * socket.
138 *
139 * @param session whose context is used
140 * @param buffer from where data will be written to the socket
141 * @param size number of bytes to be taken from the buffer
142 * @return number of bytes (at most size) from the buffer that has been
143 * written to the connection
144 * 0 if the other party has closed the connection
145 * SPDY_IO_ERROR code on error
146 */
147typedef int
148(*SPDYF_IOSend) (struct SPDY_Session *session,
149 const void * buffer,
150 size_t size);
151
152
153/**
154 * Checks if there is data staying in the buffers of the underlying
155 * system that waits to be read. In case of TLS, this will call
156 * something like SSL_pending().
157 *
158 * @param session which is checked
159 * @return SPDY_YES if data is pending or SPDY_NO otherwise
160 */
161typedef int
162(*SPDYF_IOIsPending) (struct SPDY_Session *session);
163
164
165/**
166 * Called just before frames are about to be processed and written
167 * to the socket.
168 *
169 * @param session
170 * @return SPDY_NO if writing must not happen in the call;
171 * SPDY_YES otherwise
172 */
173typedef int
174(*SPDYF_IOBeforeWrite) (struct SPDY_Session *session);
175
176
177/**
178 * Called just after frames have been processed and written
179 * to the socket.
180 *
181 * @param session
182 * @param was_written has the same value as the write function for the
183 * session will return
184 * @return returned value will be used by the write function to return
185 */
186typedef int
187(*SPDYF_IOAfterWrite) (struct SPDY_Session *session,
188 int was_written);
189
190
191/**
192 * Sets callbacks for the daemon with regard to the IO subsystem.
193 *
194 * @param daemon
195 * @param io_subsystem the IO subsystem that will
196 * be initialized and used by daemon.
197 * @return SPDY_YES on success or SPDY_NO otherwise
198 */
199int
200SPDYF_io_set_daemon(struct SPDY_Daemon *daemon,
201 enum SPDY_IO_SUBSYSTEM io_subsystem);
202
203
204/**
205 * Sets callbacks for the session with regard to the IO subsystem.
206 *
207 * @param session
208 * @param io_subsystem the IO subsystem that will
209 * be initialized and used by session.
210 * @return SPDY_YES on success or SPDY_NO otherwise
211 */
212int
213SPDYF_io_set_session(struct SPDY_Session *session,
214 enum SPDY_IO_SUBSYSTEM io_subsystem);
215
216#endif
diff --git a/src/microspdy/io_openssl.c b/src/microspdy/io_openssl.c
deleted file mode 100644
index f71a9230..00000000
--- a/src/microspdy/io_openssl.c
+++ /dev/null
@@ -1,280 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file io_openssl.c
21 * @brief TLS handling using libssl. The current code assumes that
22 * blocking I/O is in use.
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include "internal.h"
28#include "session.h"
29#include "io_openssl.h"
30
31
32/**
33 * Callback to advertise spdy ver. 3 in Next Protocol Negotiation
34 *
35 * @param ssl openssl context for a connection
36 * @param out must be set to the raw data that is advertised in NPN
37 * @param outlen must be set to size of out
38 * @param arg
39 * @return SSL_TLSEXT_ERR_OK to do advertising
40 */
41static int
42spdyf_next_protos_advertised_cb (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg)
43{
44 (void)ssl;
45 (void)arg;
46 static unsigned char npn_spdy3[] = {0x06, // length of "spdy/3"
47 0x73,0x70,0x64,0x79,0x2f,0x33};// spdy/3
48
49 *out = npn_spdy3;
50 *outlen = 7; // total length of npn_spdy3
51 return SSL_TLSEXT_ERR_OK;
52}
53
54
55void
56SPDYF_openssl_global_init()
57{
58 //error strings are now not used by the lib
59 //SSL_load_error_strings();
60 //init libssl
61 SSL_library_init(); //always returns 1
62 //the table for looking up algos is not used now by the lib
63 //OpenSSL_add_all_algorithms();
64}
65
66
67void
68SPDYF_openssl_global_deinit()
69{
70 //if SSL_load_error_strings was called
71 //ERR_free_strings();
72 //if OpenSSL_add_all_algorithms was called
73 //EVP_cleanup();
74}
75
76
77int
78SPDYF_openssl_init(struct SPDY_Daemon *daemon)
79{
80 int options;
81 //create ssl context. TLSv1 used
82 if(NULL == (daemon->io_context = SSL_CTX_new(TLSv1_server_method())))
83 {
84 SPDYF_DEBUG("Couldn't create ssl context");
85 return SPDY_NO;
86 }
87 //set options for tls
88 //TODO DH is not enabled for easier debugging
89 //SSL_CTX_set_options(daemon->io_context, SSL_OP_SINGLE_DH_USE);
90
91 //TODO here session tickets are disabled for easier debuging with
92 //wireshark when using Chrome
93 // SSL_OP_NO_COMPRESSION disables TLS compression to avoid CRIME attack
94 options = SSL_OP_NO_TICKET;
95#ifdef SSL_OP_NO_COMPRESSION
96 options |= SSL_OP_NO_COMPRESSION;
97#elif OPENSSL_VERSION_NUMBER >= 0x00908000L /* workaround for OpenSSL 0.9.8 */
98 sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
99#endif
100
101 SSL_CTX_set_options(daemon->io_context, options);
102 if(1 != SSL_CTX_use_certificate_file(daemon->io_context, daemon->certfile , SSL_FILETYPE_PEM))
103 {
104 SPDYF_DEBUG("Couldn't load the cert file");
105 SSL_CTX_free(daemon->io_context);
106 return SPDY_NO;
107 }
108 if(1 != SSL_CTX_use_PrivateKey_file(daemon->io_context, daemon->keyfile, SSL_FILETYPE_PEM))
109 {
110 SPDYF_DEBUG("Couldn't load the name file");
111 SSL_CTX_free(daemon->io_context);
112 return SPDY_NO;
113 }
114 SSL_CTX_set_next_protos_advertised_cb(daemon->io_context, &spdyf_next_protos_advertised_cb, NULL);
115 if (1 != SSL_CTX_set_cipher_list(daemon->io_context, "HIGH"))
116 {
117 SPDYF_DEBUG("Couldn't set the desired cipher list");
118 SSL_CTX_free(daemon->io_context);
119 return SPDY_NO;
120 }
121
122 return SPDY_YES;
123}
124
125
126void
127SPDYF_openssl_deinit(struct SPDY_Daemon *daemon)
128{
129 SSL_CTX_free(daemon->io_context);
130}
131
132
133int
134SPDYF_openssl_new_session(struct SPDY_Session *session)
135{
136 int ret;
137
138 if(NULL == (session->io_context = SSL_new(session->daemon->io_context)))
139 {
140 SPDYF_DEBUG("Couldn't create ssl structure");
141 return SPDY_NO;
142 }
143 if(1 != (ret = SSL_set_fd(session->io_context, session->socket_fd)))
144 {
145 SPDYF_DEBUG("SSL_set_fd %i",ret);
146 SSL_free(session->io_context);
147 session->io_context = NULL;
148 return SPDY_NO;
149 }
150
151 //for non-blocking I/O SSL_accept may return -1
152 //and this function won't work
153 if(1 != (ret = SSL_accept(session->io_context)))
154 {
155 SPDYF_DEBUG("SSL_accept %i",ret);
156 SSL_free(session->io_context);
157 session->io_context = NULL;
158 return SPDY_NO;
159 }
160 /* alternatively
161 SSL_set_accept_state(session->io_context);
162 * may be called and then the negotiation will be done on reading
163 */
164
165 return SPDY_YES;
166}
167
168
169void
170SPDYF_openssl_close_session(struct SPDY_Session *session)
171{
172 //SSL_shutdown sends TLS "close notify" as in TLS standard.
173 //The function may fail as it waits for the other party to also close
174 //the TLS session. The lib just sends it and will close the socket
175 //after that because the browsers don't seem to care much about
176 //"close notify"
177 SSL_shutdown(session->io_context);
178
179 SSL_free(session->io_context);
180}
181
182
183int
184SPDYF_openssl_recv(struct SPDY_Session *session,
185 void * buffer,
186 size_t size)
187{
188 int ret;
189 int n = SSL_read(session->io_context,
190 buffer,
191 size);
192 //if(n > 0) SPDYF_DEBUG("recvd: %i",n);
193 if (n <= 0)
194 {
195 ret = SSL_get_error(session->io_context, n);
196 switch(ret)
197 {
198 case SSL_ERROR_ZERO_RETURN:
199 return 0;
200
201 case SSL_ERROR_WANT_READ:
202 case SSL_ERROR_WANT_WRITE:
203 return SPDY_IO_ERROR_AGAIN;
204
205 case SSL_ERROR_SYSCALL:
206 if(EINTR == errno)
207 return SPDY_IO_ERROR_AGAIN;
208 return SPDY_IO_ERROR_ERROR;
209 default:
210 return SPDY_IO_ERROR_ERROR;
211 }
212 }
213
214 return n;
215}
216
217
218int
219SPDYF_openssl_send(struct SPDY_Session *session,
220 const void * buffer,
221 size_t size)
222{
223 int ret;
224
225 int n = SSL_write(session->io_context,
226 buffer,
227 size);
228 //if(n > 0) SPDYF_DEBUG("sent: %i",n);
229 if (n <= 0)
230 {
231 ret = SSL_get_error(session->io_context, n);
232 switch(ret)
233 {
234 case SSL_ERROR_ZERO_RETURN:
235 return 0;
236
237 case SSL_ERROR_WANT_READ:
238 case SSL_ERROR_WANT_WRITE:
239 return SPDY_IO_ERROR_AGAIN;
240
241 case SSL_ERROR_SYSCALL:
242 if(EINTR == errno)
243 return SPDY_IO_ERROR_AGAIN;
244 return SPDY_IO_ERROR_ERROR;
245 default:
246 return SPDY_IO_ERROR_ERROR;
247 }
248 }
249
250 return n;
251}
252
253
254int
255SPDYF_openssl_is_pending(struct SPDY_Session *session)
256{
257 /* From openssl docs:
258 * BUGS
259SSL_pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). If the SSL object's read_ahead flag is set, additional protocol bytes may have been read containing more TLS/SSL records; these are ignored by SSL_pending().
260 */
261 return SSL_pending(session->io_context) > 0 ? SPDY_YES : SPDY_NO;
262}
263
264
265int
266SPDYF_openssl_before_write(struct SPDY_Session *session)
267{
268 (void)session;
269
270 return SPDY_YES;
271}
272
273
274int
275SPDYF_openssl_after_write(struct SPDY_Session *session, int was_written)
276{
277 (void)session;
278
279 return was_written;
280}
diff --git a/src/microspdy/io_openssl.h b/src/microspdy/io_openssl.h
deleted file mode 100644
index a4e94293..00000000
--- a/src/microspdy/io_openssl.h
+++ /dev/null
@@ -1,166 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file io_openssl.h
21 * @brief TLS handling. openssl with NPN is used, but as long as the
22 * functions conform to this interface file, other libraries
23 * can be used.
24 * @author Andrey Uzunov
25 */
26
27#ifndef IO_OPENSSL_H
28#define IO_OPENSSL_H
29
30#include "platform.h"
31#include "io.h"
32#include <openssl/err.h>
33#include <openssl/ssl.h>
34#include <openssl/rand.h>
35
36
37/**
38 * Global initializing of openssl. Must be called only once in the program.
39 *
40 */
41void
42SPDYF_openssl_global_init();
43
44
45/**
46 * Global deinitializing of openssl for the whole program. Should be called
47 * at the end of the program.
48 *
49 */
50void
51SPDYF_openssl_global_deinit();
52
53
54/**
55 * Initializing of openssl for a specific daemon.
56 * Must be called when the daemon starts.
57 *
58 * @param daemon SPDY_Daemon for which openssl will be used. Daemon's
59 * certificate and key file are used.
60 * @return SPDY_YES on success or SPDY_NO on error
61 */
62int
63SPDYF_openssl_init(struct SPDY_Daemon *daemon);
64
65
66/**
67 * Deinitializing openssl for a daemon. Should be called
68 * when the deamon is stopped.
69 *
70 * @param daemon SPDY_Daemon which is being stopped
71 */
72void
73SPDYF_openssl_deinit(struct SPDY_Daemon *daemon);
74
75
76/**
77 * Initializing openssl for a specific connection. Must be called
78 * after the connection has been accepted.
79 *
80 * @param session SPDY_Session whose socket will be used by openssl
81 * @return SPDY_NO if some openssl funcs fail. SPDY_YES otherwise
82 */
83int
84SPDYF_openssl_new_session(struct SPDY_Session *session);
85
86
87/**
88 * Deinitializing openssl for a specific connection. Should be called
89 * closing session's socket.
90 *
91 * @param session SPDY_Session whose socket is used by openssl
92 */
93void
94SPDYF_openssl_close_session(struct SPDY_Session *session);
95
96
97/**
98 * Reading from a TLS socket. Reads available data and put it to the
99 * buffer.
100 *
101 * @param session for which data is received
102 * @param buffer where data from the socket will be written to
103 * @param size of the buffer
104 * @return number of bytes (at most size) read from the TLS connection
105 * 0 if the other party has closed the connection
106 * SPDY_IO_ERROR code on error
107 */
108int
109SPDYF_openssl_recv(struct SPDY_Session *session,
110 void * buffer,
111 size_t size);
112
113
114/**
115 * Writing to a TLS socket. Writes the data given into the buffer to the
116 * TLS socket.
117 *
118 * @param session whose context is used
119 * @param buffer from where data will be written to the socket
120 * @param size number of bytes to be taken from the buffer
121 * @return number of bytes (at most size) from the buffer that has been
122 * written to the TLS connection
123 * 0 if the other party has closed the connection
124 * SPDY_IO_ERROR code on error
125 */
126int
127SPDYF_openssl_send(struct SPDY_Session *session,
128 const void * buffer,
129 size_t size);
130
131
132/**
133 * Checks if there is data staying in the buffers of the underlying
134 * system that waits to be read.
135 *
136 * @param session which is checked
137 * @return SPDY_YES if data is pending or SPDY_NO otherwise
138 */
139int
140SPDYF_openssl_is_pending(struct SPDY_Session *session);
141
142
143/**
144 * Nothing.
145 *
146 * @param session
147 * @return SPDY_NO if writing must not happen in the call;
148 * SPDY_YES otherwise
149 */
150int
151SPDYF_openssl_before_write(struct SPDY_Session *session);
152
153
154/**
155 * Nothing.
156 *
157 * @param session
158 * @param was_written has the same value as the write function for the
159 * session will return
160 * @return returned value will be used by the write function to return
161 */
162int
163SPDYF_openssl_after_write(struct SPDY_Session *session, int was_written);
164
165
166#endif
diff --git a/src/microspdy/io_raw.c b/src/microspdy/io_raw.c
deleted file mode 100644
index 722f347e..00000000
--- a/src/microspdy/io_raw.c
+++ /dev/null
@@ -1,194 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file io_raw.c
21 * @brief IO for SPDY without TLS.
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "internal.h"
27#include "session.h"
28#include "io_raw.h"
29//TODO put in in the right place
30#include <netinet/tcp.h>
31
32
33void
34SPDYF_raw_global_init()
35{
36}
37
38
39void
40SPDYF_raw_global_deinit()
41{
42}
43
44
45int
46SPDYF_raw_init(struct SPDY_Daemon *daemon)
47{
48 (void)daemon;
49
50 return SPDY_YES;
51}
52
53
54void
55SPDYF_raw_deinit(struct SPDY_Daemon *daemon)
56{
57 (void)daemon;
58}
59
60
61int
62SPDYF_raw_new_session(struct SPDY_Session *session)
63{
64 int fd_flags;
65 int val = 1;
66 int ret;
67
68 //setting the socket to be non-blocking
69 fd_flags = fcntl (session->socket_fd, F_GETFL);
70 if ( -1 == fd_flags
71 || 0 != fcntl (session->socket_fd, F_SETFL, fd_flags | O_NONBLOCK))
72 SPDYF_DEBUG("WARNING: Couldn't set the new connection to be non-blocking");
73
74 if(SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)
75 {
76 ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
77 if(-1 == ret)
78 SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_NODELAY");
79 }
80
81 return SPDY_YES;
82}
83
84
85void
86SPDYF_raw_close_session(struct SPDY_Session *session)
87{
88 (void)session;
89}
90
91
92int
93SPDYF_raw_recv(struct SPDY_Session *session,
94 void * buffer,
95 size_t size)
96{
97 int n = read(session->socket_fd,
98 buffer,
99 size);
100 //if(n > 0) SPDYF_DEBUG("recvd: %i",n);
101 if (n < 0)
102 {
103 switch(errno)
104 {
105 case EAGAIN:
106#if EAGAIN != EWOULDBLOCK
107 case EWOULDBLOCK:
108#endif
109 case EINTR:
110 return SPDY_IO_ERROR_AGAIN;
111
112 default:
113 return SPDY_IO_ERROR_ERROR;
114 }
115 }
116
117 return n;
118}
119
120
121int
122SPDYF_raw_send(struct SPDY_Session *session,
123 const void * buffer,
124 size_t size)
125{
126 int n = write(session->socket_fd,
127 buffer,
128 size);
129 //if(n > 0) SPDYF_DEBUG("sent: %i",n);
130 if (n < 0)
131 {
132 switch(errno)
133 {
134 case EAGAIN:
135#if EAGAIN != EWOULDBLOCK
136 case EWOULDBLOCK:
137#endif
138 case EINTR:
139 return SPDY_IO_ERROR_AGAIN;
140
141 default:
142 return SPDY_IO_ERROR_ERROR;
143 }
144 }
145
146 return n;
147}
148
149
150int
151SPDYF_raw_is_pending(struct SPDY_Session *session)
152{
153 (void)session;
154
155 return SPDY_NO;
156}
157
158
159int
160SPDYF_raw_before_write(struct SPDY_Session *session)
161{
162#if HAVE_DECL_TCP_CORK
163 if(0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags))
164 {
165 int val = 1;
166 int ret;
167
168 ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_CORK, &val, (socklen_t)sizeof(val));
169 if(-1 == ret)
170 SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_CORK");
171 }
172#endif
173
174 return SPDY_YES;
175}
176
177
178int
179SPDYF_raw_after_write(struct SPDY_Session *session, int was_written)
180{
181#if HAVE_DECL_TCP_CORK
182 if(SPDY_YES == was_written && 0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags))
183 {
184 int val = 0;
185 int ret;
186
187 ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_CORK, &val, (socklen_t)sizeof(val));
188 if(-1 == ret)
189 SPDYF_DEBUG("WARNING: Couldn't unset the new connection to TCP_CORK");
190 }
191
192#endif
193 return was_written;
194}
diff --git a/src/microspdy/io_raw.h b/src/microspdy/io_raw.h
deleted file mode 100644
index 8ca830bf..00000000
--- a/src/microspdy/io_raw.h
+++ /dev/null
@@ -1,158 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file io_raw.h
21 * @brief IO for SPDY without TLS.
22 * @author Andrey Uzunov
23 */
24
25#ifndef IO_RAW_H
26#define IO_RAW_H
27
28#include "platform.h"
29
30
31/**
32 * Must be called only once in the program.
33 *
34 */
35void
36SPDYF_raw_global_init();
37
38
39/**
40 * Should be called
41 * at the end of the program.
42 *
43 */
44void
45SPDYF_raw_global_deinit();
46
47
48/**
49 * Must be called when the daemon starts.
50 *
51 * @param daemon SPDY_Daemon
52 * @return SPDY_YES on success or SPDY_NO on error
53 */
54int
55SPDYF_raw_init(struct SPDY_Daemon *daemon);
56
57
58/**
59 * Should be called
60 * when the deamon is stopped.
61 *
62 * @param daemon SPDY_Daemon which is being stopped
63 */
64void
65SPDYF_raw_deinit(struct SPDY_Daemon *daemon);
66
67
68/**
69 * Must be called
70 * after the connection has been accepted.
71 *
72 * @param session SPDY_Session whose socket will be used
73 * @return SPDY_NO if some funcs fail. SPDY_YES otherwise
74 */
75int
76SPDYF_raw_new_session(struct SPDY_Session *session);
77
78
79/**
80 * Should be called
81 * closing session's socket.
82 *
83 * @param session SPDY_Session whose socket is used
84 */
85void
86SPDYF_raw_close_session(struct SPDY_Session *session);
87
88
89/**
90 * Reading from socket. Reads available data and put it to the
91 * buffer.
92 *
93 * @param session for which data is received
94 * @param buffer where data from the socket will be written to
95 * @param size of the buffer
96 * @return number of bytes (at most size) read from the connection
97 * 0 if the other party has closed the connection
98 * SPDY_IO_ERROR code on error
99 */
100int
101SPDYF_raw_recv(struct SPDY_Session *session,
102 void * buffer,
103 size_t size);
104
105
106/**
107 * Writing to socket. Writes the data given into the buffer to the
108 * socket.
109 *
110 * @param session whose context is used
111 * @param buffer from where data will be written to the socket
112 * @param size number of bytes to be taken from the buffer
113 * @return number of bytes (at most size) from the buffer that has been
114 * written to the connection
115 * 0 if the other party has closed the connection
116 * SPDY_IO_ERROR code on error
117 */
118int
119SPDYF_raw_send(struct SPDY_Session *session,
120 const void * buffer,
121 size_t size);
122
123
124/**
125 * Checks if there is data staying in the buffers of the underlying
126 * system that waits to be read. Always returns SPDY_NO, as we do not
127 * use a subsystem here.
128 *
129 * @param session which is checked
130 * @return SPDY_YES if data is pending or SPDY_NO otherwise
131 */
132int
133SPDYF_raw_is_pending(struct SPDY_Session *session);
134
135
136/**
137 * Sets TCP_CORK.
138 *
139 * @param session
140 * @return SPDY_NO if writing must not happen in the call;
141 * SPDY_YES otherwise
142 */
143int
144SPDYF_raw_before_write(struct SPDY_Session *session);
145
146
147/**
148 * Unsets TCP_CORK.
149 *
150 * @param session
151 * @param was_written has the same value as the write function for the
152 * session will return
153 * @return returned value will be used by the write function to return
154 */
155int
156SPDYF_raw_after_write(struct SPDY_Session *session, int was_written);
157
158#endif
diff --git a/src/microspdy/session.c b/src/microspdy/session.c
deleted file mode 100644
index 7cb8c3d1..00000000
--- a/src/microspdy/session.c
+++ /dev/null
@@ -1,1769 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file session.c
21 * @brief TCP connection/SPDY session handling. So far most of the
22 * functions for handling SPDY framing layer are here.
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include "structures.h"
28#include "internal.h"
29#include "session.h"
30#include "compression.h"
31#include "stream.h"
32#include "io.h"
33
34
35/**
36 * Handler for reading the full SYN_STREAM frame after we know that
37 * the frame is such.
38 * The function waits for the full frame and then changes status
39 * of the session. New stream is created.
40 *
41 * @param session SPDY_Session whose read buffer is used.
42 */
43static void
44spdyf_handler_read_syn_stream (struct SPDY_Session *session)
45{
46 size_t name_value_strm_size = 0;
47 unsigned int compressed_data_size;
48 int ret;
49 void *name_value_strm = NULL;
50 struct SPDYF_Control_Frame *frame;
51 struct SPDY_NameValue *headers;
52
53 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
54 || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
55 "the function is called wrong");
56
57 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
58
59 //handle subheaders
60 if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
61 {
62 if(0 == frame->length)
63 {
64 //protocol error: incomplete frame
65 //we just ignore it since there is no stream id for which to
66 //send RST_STREAM
67 //TODO maybe GOAWAY and closing session is appropriate
68 SPDYF_DEBUG("zero long SYN_STREAM received");
69 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
70 free(frame);
71 return;
72 }
73
74 if(SPDY_YES != SPDYF_stream_new(session))
75 {
76 /* waiting for some more fields to create new stream
77 or something went wrong, SPDYF_stream_new has handled the
78 situation */
79 return;
80 }
81
82 session->current_stream_id = session->streams_head->stream_id;
83 if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
84 {
85 //TODO no need to create stream if this happens
86 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
87 return;
88 }
89 else
90 session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
91 }
92
93 //handle body
94
95 //start reading the compressed name/value pairs (http headers)
96 compressed_data_size = frame->length //everything after length field
97 - 10;//4B stream id, 4B assoc strem id, 2B priority, unused and slot
98
99 if(session->read_buffer_offset - session->read_buffer_beginning < compressed_data_size)
100 {
101 // the full frame is not yet here, try later
102 return;
103 }
104
105 if ( (compressed_data_size > 0) &&
106 (SPDY_YES !=
107 SPDYF_zlib_inflate(&session->zlib_recv_stream,
108 session->read_buffer + session->read_buffer_beginning,
109 compressed_data_size,
110 &name_value_strm,
111 &name_value_strm_size)) )
112 {
113 /* something went wrong on inflating,
114 * the state of the stream for decompression is unknown
115 * and we may not be able to read anything more received on
116 * this session,
117 * so it is better to close the session */
118 free(name_value_strm);
119 free(frame);
120
121 /* mark the session for closing and close it, when
122 * everything on the output queue is already written */
123 session->status = SPDY_SESSION_STATUS_FLUSHING;
124
125 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
126
127 return;
128 }
129
130 if(0 == name_value_strm_size || 0 == compressed_data_size)
131 {
132 //Protocol error: send RST_STREAM
133 if(SPDY_YES != SPDYF_prepare_rst_stream(session, session->streams_head,
134 SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR))
135 {
136 //no memory, try later to send RST
137 free(name_value_strm);
138 return;
139 }
140 }
141 else
142 {
143 ret = SPDYF_name_value_from_stream(name_value_strm, name_value_strm_size, &headers);
144 if(SPDY_NO == ret)
145 {
146 //memory error, try later
147 free(name_value_strm);
148 return;
149 }
150
151 session->streams_head->headers = headers;
152 //inform the application layer for the new stream received
153 if(SPDY_YES != session->daemon->fnew_stream_cb(session->daemon->fcls, session->streams_head))
154 {
155 //memory error, try later
156 free(name_value_strm);
157 return;
158 }
159
160 session->read_buffer_beginning += compressed_data_size;
161 }
162
163 //SPDYF_DEBUG("syn_stream received: id %i", session->current_stream_id);
164
165 //change state to wait for new frame
166 free(name_value_strm);
167 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
168 free(frame);
169}
170
171
172/**
173 * Handler for reading the GOAWAY frame after we know that
174 * the frame is such.
175 * The function waits for the full frame and then changes status
176 * of the session.
177 *
178 * @param session SPDY_Session whose read buffer is used.
179 */
180static void
181spdyf_handler_read_goaway (struct SPDY_Session *session)
182{
183 struct SPDYF_Control_Frame *frame;
184 uint32_t last_good_stream_id;
185 uint32_t status_int;
186 enum SPDY_GOAWAY_STATUS status;
187
188 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
189 "the function is called wrong");
190
191 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
192
193 if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
194 {
195 //this is a protocol error/attack
196 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
197 return;
198 }
199
200 if(0 != frame->flags || 8 != frame->length)
201 {
202 //this is a protocol error
203 SPDYF_DEBUG("wrong GOAWAY received");
204 //anyway, it will be handled
205 }
206
207 if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
208 {
209 //not all fields are received
210 //try later
211 return;
212 }
213
214 //mark that the session is almost closed
215 session->is_goaway_received = true;
216
217 if(8 == frame->length)
218 {
219 memcpy(&last_good_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
220 last_good_stream_id = NTOH31(last_good_stream_id);
221 session->read_buffer_beginning += 4;
222
223 memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
224 status = ntohl(status_int);
225 session->read_buffer_beginning += 4;
226
227 //TODO do something with last_good
228
229 //SPDYF_DEBUG("Received GOAWAY; status=%i; lastgood=%i",status,last_good_stream_id);
230
231 //do something according to the status
232 //TODO
233 switch(status)
234 {
235 case SPDY_GOAWAY_STATUS_OK:
236 break;
237 case SPDY_GOAWAY_STATUS_PROTOCOL_ERROR:
238 break;
239 case SPDY_GOAWAY_STATUS_INTERNAL_ERROR:
240 break;
241 }
242
243 //SPDYF_DEBUG("goaway received: status %i", status);
244 }
245
246 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
247 free(frame);
248}
249
250
251/**
252 * Handler for reading RST_STREAM frames. After receiving the frame
253 * the stream moves into closed state and status
254 * of the session is changed. Frames, belonging to this stream, which
255 * are still at the output queue, will be ignored later.
256 *
257 * @param session SPDY_Session whose read buffer is used.
258 */
259static void
260spdyf_handler_read_rst_stream (struct SPDY_Session *session)
261{
262 struct SPDYF_Control_Frame *frame;
263 uint32_t stream_id;
264 int32_t status_int;
265 //enum SPDY_RST_STREAM_STATUS status; //for debug
266 struct SPDYF_Stream *stream;
267
268 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
269 "the function is called wrong");
270
271 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
272
273 if(0 != frame->flags || 8 != frame->length)
274 {
275 //this is a protocol error
276 SPDYF_DEBUG("wrong RST_STREAM received");
277 //ignore as a large frame
278 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
279 return;
280 }
281
282 if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
283 {
284 //not all fields are received
285 //try later
286 return;
287 }
288
289 memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
290 stream_id = NTOH31(stream_id);
291 session->read_buffer_beginning += 4;
292
293 memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
294 //status = ntohl(status_int); //for debug
295 session->read_buffer_beginning += 4;
296
297 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
298 free(frame);
299
300 //mark the stream as closed
301 stream = session->streams_head;
302 while(NULL != stream)
303 {
304 if(stream_id == stream->stream_id)
305 {
306 stream->is_in_closed = true;
307 stream->is_out_closed = true;
308 break;
309 }
310 stream = stream->next;
311 }
312
313 //SPDYF_DEBUG("Received RST_STREAM; status=%i; id=%i",status,stream_id);
314
315 //do something according to the status
316 //TODO
317 /*switch(status)
318 {
319 case SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR:
320 break;
321 }*/
322}
323
324
325/**
326 * Handler for reading DATA frames. In requests they are used for POST
327 * arguments.
328 *
329 * @param session SPDY_Session whose read buffer is used.
330 */
331static void
332spdyf_handler_read_data (struct SPDY_Session *session)
333{
334 int ret;
335 struct SPDYF_Data_Frame * frame;
336 struct SPDYF_Stream * stream;
337
338 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
339 || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
340 "the function is called wrong");
341
342 //SPDYF_DEBUG("DATA frame received (POST?). Ignoring");
343
344 //SPDYF_SIGINT("");
345
346 frame = (struct SPDYF_Data_Frame *)session->frame_handler_cls;
347
348 //handle subheaders
349 if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
350 {
351 if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
352 {
353 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
354 return;
355 }
356 else
357 session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
358 }
359
360 //handle body
361
362 if(session->read_buffer_offset - session->read_buffer_beginning
363 >= frame->length)
364 {
365 stream = SPDYF_stream_find(frame->stream_id, session);
366
367 if(NULL == stream || stream->is_in_closed || NULL == session->daemon->received_data_cb)
368 {
369 if(NULL == session->daemon->received_data_cb)
370 SPDYF_DEBUG("No callback for DATA frame set; Ignoring DATA frame!");
371
372 //TODO send error?
373
374 //TODO for now ignore frame
375 session->read_buffer_beginning += frame->length;
376 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
377 free(frame);
378 return;
379 }
380
381 ret = session->daemon->freceived_data_cb(session->daemon->cls,
382 stream,
383 session->read_buffer + session->read_buffer_beginning,
384 frame->length,
385 0 == (SPDY_DATA_FLAG_FIN & frame->flags));
386
387 session->read_buffer_beginning += frame->length;
388
389 stream->window_size -= frame->length;
390
391 //TODO close in and send rst maybe
392 SPDYF_ASSERT(SPDY_YES == ret, "Cancel POST data is not yet implemented");
393
394 if(SPDY_DATA_FLAG_FIN & frame->flags)
395 {
396 stream->is_in_closed = true;
397 }
398 else if(stream->window_size < SPDYF_INITIAL_WINDOW_SIZE / 2)
399 {
400 //very simple implementation of flow control
401 //when the window's size is under the half of the initial value,
402 //increase it again up to the initial value
403
404 //prepare WINDOW_UPDATE
405 if(SPDY_YES == SPDYF_prepare_window_update(session, stream,
406 SPDYF_INITIAL_WINDOW_SIZE - stream->window_size))
407 {
408 stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
409 }
410 //else: do it later
411 }
412
413 //SPDYF_DEBUG("data received: id %i", frame->stream_id);
414
415 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
416 free(frame);
417 }
418}
419
420
421int
422SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
423{
424 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
425 struct SPDYF_Stream *stream = response_queue->stream;
426 struct SPDYF_Control_Frame control_frame;
427 void *compressed_headers = NULL;
428 size_t compressed_headers_size=0;
429 size_t used_data=0;
430 size_t total_size;
431 uint32_t stream_id_nbo;
432
433 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
434
435 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
436
437 if(SPDY_YES != SPDYF_zlib_deflate(&session->zlib_send_stream,
438 response_queue->data,
439 response_queue->data_size,
440 &used_data,
441 &compressed_headers,
442 &compressed_headers_size))
443 {
444 /* something went wrong on compressing,
445 * the state of the stream for compression is unknown
446 * and we may not be able to send anything more on
447 * this session,
448 * so it is better to close the session right now */
449 session->status = SPDY_SESSION_STATUS_CLOSING;
450
451 free(compressed_headers);
452
453 return SPDY_NO;
454 }
455
456 //TODO do we need this used_Data
457 SPDYF_ASSERT(used_data == response_queue->data_size, "not everything was used by zlib");
458
459 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
460 + 4 // stream id as "subheader"
461 + compressed_headers_size;
462
463 if(NULL == (session->write_buffer = malloc(total_size)))
464 {
465 /* no memory
466 * since we do not save the compressed data anywhere and
467 * the sending zlib stream is already in new state, we must
468 * close the session */
469 session->status = SPDY_SESSION_STATUS_CLOSING;
470
471 free(compressed_headers);
472
473 return SPDY_NO;
474 }
475 session->write_buffer_beginning = 0;
476 session->write_buffer_offset = 0;
477 session->write_buffer_size = total_size;
478
479 control_frame.length = compressed_headers_size + 4; // compressed data + stream_id
480 SPDYF_CONTROL_FRAME_HTON(&control_frame);
481
482 //put frame headers to write buffer
483 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
484 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
485
486 //put stream id to write buffer
487 stream_id_nbo = HTON31(stream->stream_id);
488 memcpy(session->write_buffer + session->write_buffer_offset, &stream_id_nbo, 4);
489 session->write_buffer_offset += 4;
490
491 //put compressed name/value pairs to write buffer
492 memcpy(session->write_buffer + session->write_buffer_offset, compressed_headers, compressed_headers_size);
493 session->write_buffer_offset += compressed_headers_size;
494
495 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
496 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
497
498 //DEBUG CODE, break compression state to see what happens
499/* SPDYF_zlib_deflate(&session->zlib_send_stream,
500 "1234567890",
501 10,
502 &used_data,
503 &compressed_headers,
504 &compressed_headers_size);
505*/
506 free(compressed_headers);
507
508 session->last_replied_to_stream_id = stream->stream_id;
509
510 //SPDYF_DEBUG("syn_reply sent: id %i", stream->stream_id);
511
512 return SPDY_YES;
513}
514
515
516int
517SPDYF_handler_write_goaway (struct SPDY_Session *session)
518{
519 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
520 struct SPDYF_Control_Frame control_frame;
521 size_t total_size;
522 int last_good_stream_id;
523
524 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
525
526 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
527
528 session->is_goaway_sent = true;
529
530 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
531 + 4 // last good stream id as "subheader"
532 + 4; // status code as "subheader"
533
534 if(NULL == (session->write_buffer = malloc(total_size)))
535 {
536 return SPDY_NO;
537 }
538 session->write_buffer_beginning = 0;
539 session->write_buffer_offset = 0;
540 session->write_buffer_size = total_size;
541
542 control_frame.length = 8; // always for GOAWAY
543 SPDYF_CONTROL_FRAME_HTON(&control_frame);
544
545 //put frame headers to write buffer
546 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
547 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
548
549 //put last good stream id to write buffer
550 last_good_stream_id = HTON31(session->last_replied_to_stream_id);
551 memcpy(session->write_buffer + session->write_buffer_offset, &last_good_stream_id, 4);
552 session->write_buffer_offset += 4;
553
554 //put "data" to write buffer. This is the status
555 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 4);
556 session->write_buffer_offset += 4;
557 //data is not freed by the destroy function so:
558 //free(response_queue->data);
559
560 //SPDYF_DEBUG("goaway sent: status %i", NTOH31(*(uint32_t*)(response_queue->data)));
561
562 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
563 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
564
565 return SPDY_YES;
566}
567
568
569int
570SPDYF_handler_write_data (struct SPDY_Session *session)
571{
572 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
573 struct SPDYF_Response_Queue *new_response_queue;
574 size_t total_size;
575 struct SPDYF_Data_Frame data_frame;
576 ssize_t ret;
577 bool more;
578
579 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
580
581 memcpy(&data_frame, response_queue->data_frame, sizeof(data_frame));
582
583 if(NULL == response_queue->response->rcb)
584 {
585 //standard response with data into the struct
586 SPDYF_ASSERT(NULL != response_queue->data, "no data for the response");
587
588 total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
589 + response_queue->data_size;
590
591 if(NULL == (session->write_buffer = malloc(total_size)))
592 {
593 return SPDY_NO;
594 }
595 session->write_buffer_beginning = 0;
596 session->write_buffer_offset = 0;
597 session->write_buffer_size = total_size;
598
599 data_frame.length = response_queue->data_size;
600 SPDYF_DATA_FRAME_HTON(&data_frame);
601
602 //put SPDY headers to the writing buffer
603 memcpy(session->write_buffer + session->write_buffer_offset,&data_frame,sizeof(struct SPDYF_Data_Frame));
604 session->write_buffer_offset += sizeof(struct SPDYF_Data_Frame);
605
606 //put data to the writing buffer
607 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, response_queue->data_size);
608 session->write_buffer_offset += response_queue->data_size;
609 }
610 else
611 {
612 /* response with callbacks. The lib will produce more than 1
613 * data frames
614 */
615
616 total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
617 + SPDY_MAX_SUPPORTED_FRAME_SIZE; //max possible size
618
619 if(NULL == (session->write_buffer = malloc(total_size)))
620 {
621 return SPDY_NO;
622 }
623 session->write_buffer_beginning = 0;
624 session->write_buffer_offset = 0;
625 session->write_buffer_size = total_size;
626
627 ret = response_queue->response->rcb(response_queue->response->rcb_cls,
628 session->write_buffer + sizeof(struct SPDYF_Data_Frame),
629 response_queue->response->rcb_block_size,
630 &more);
631
632 if(ret < 0 || ret > response_queue->response->rcb_block_size)
633 {
634 free(session->write_buffer);
635 session->write_buffer = NULL;
636
637 //send RST_STREAM
638 if(SPDY_YES == (ret = SPDYF_prepare_rst_stream(session,
639 response_queue->stream,
640 SPDY_RST_STREAM_STATUS_INTERNAL_ERROR)))
641 {
642 return SPDY_NO;
643 }
644
645 //else no memory
646 //for now close session
647 //TODO what?
648 session->status = SPDY_SESSION_STATUS_CLOSING;
649
650 return SPDY_NO;
651 }
652 if(0 == ret && more)
653 {
654 //the app couldn't write anything to buf but later will
655 free(session->write_buffer);
656 session->write_buffer = NULL;
657 session->write_buffer_size = 0;
658
659 if(NULL != response_queue->next)
660 {
661 //put the frame at the end of the queue
662 //otherwise - head of line blocking
663 session->response_queue_head = response_queue->next;
664 session->response_queue_head->prev = NULL;
665 session->response_queue_tail->next = response_queue;
666 response_queue->prev = session->response_queue_tail;
667 response_queue->next = NULL;
668 session->response_queue_tail = response_queue;
669 }
670
671 return SPDY_YES;
672 }
673
674 if(more)
675 {
676 //create another response queue object to call the user cb again
677 if(NULL == (new_response_queue = SPDYF_response_queue_create(true,
678 NULL,
679 0,
680 response_queue->response,
681 response_queue->stream,
682 false,
683 response_queue->frqcb,
684 response_queue->frqcb_cls,
685 response_queue->rrcb,
686 response_queue->rrcb_cls)))
687 {
688 //TODO send RST_STREAM
689 //for now close session
690 session->status = SPDY_SESSION_STATUS_CLOSING;
691
692 free(session->write_buffer);
693 session->write_buffer = NULL;
694 return SPDY_NO;
695 }
696
697 //put it at second position on the queue
698 new_response_queue->prev = response_queue;
699 new_response_queue->next = response_queue->next;
700 if(NULL == response_queue->next)
701 {
702 session->response_queue_tail = new_response_queue;
703 }
704 else
705 {
706 response_queue->next->prev = new_response_queue;
707 }
708 response_queue->next = new_response_queue;
709
710 response_queue->frqcb = NULL;
711 response_queue->frqcb_cls = NULL;
712 response_queue->rrcb = NULL;
713 response_queue->rrcb_cls = NULL;
714 }
715 else
716 {
717 data_frame.flags |= SPDY_DATA_FLAG_FIN;
718 }
719
720 data_frame.length = ret;
721 SPDYF_DATA_FRAME_HTON(&data_frame);
722
723 //put SPDY headers to the writing buffer
724 memcpy(session->write_buffer + session->write_buffer_offset,
725 &data_frame,
726 sizeof(struct SPDYF_Data_Frame));
727 session->write_buffer_offset += sizeof(struct SPDYF_Data_Frame);
728 session->write_buffer_offset += ret;
729 session->write_buffer_size = session->write_buffer_offset;
730 }
731
732 //SPDYF_DEBUG("data sent: id %i", NTOH31(data_frame.stream_id));
733
734 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
735 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
736
737 return SPDY_YES;
738}
739
740
741int
742SPDYF_handler_write_rst_stream (struct SPDY_Session *session)
743{
744 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
745 struct SPDYF_Control_Frame control_frame;
746 size_t total_size;
747
748 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
749
750 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
751
752 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
753 + 4 // stream id as "subheader"
754 + 4; // status code as "subheader"
755
756 if(NULL == (session->write_buffer = malloc(total_size)))
757 {
758 return SPDY_NO;
759 }
760 session->write_buffer_beginning = 0;
761 session->write_buffer_offset = 0;
762 session->write_buffer_size = total_size;
763
764 control_frame.length = 8; // always for RST_STREAM
765 SPDYF_CONTROL_FRAME_HTON(&control_frame);
766
767 //put frame headers to write buffer
768 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
769 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
770
771 //put stream id to write buffer. This is the status
772 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8);
773 session->write_buffer_offset += 8;
774 //data is not freed by the destroy function so:
775 //free(response_queue->data);
776
777 //SPDYF_DEBUG("rst_stream sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32));
778
779 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
780 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
781
782 return SPDY_YES;
783}
784
785
786int
787SPDYF_handler_write_window_update (struct SPDY_Session *session)
788{
789 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
790 struct SPDYF_Control_Frame control_frame;
791 size_t total_size;
792
793 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
794
795 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
796
797 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
798 + 4 // stream id as "subheader"
799 + 4; // delta-window-size as "subheader"
800
801 if(NULL == (session->write_buffer = malloc(total_size)))
802 {
803 return SPDY_NO;
804 }
805 session->write_buffer_beginning = 0;
806 session->write_buffer_offset = 0;
807 session->write_buffer_size = total_size;
808
809 control_frame.length = 8; // always for WINDOW_UPDATE
810 SPDYF_CONTROL_FRAME_HTON(&control_frame);
811
812 //put frame headers to write buffer
813 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
814 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
815
816 //put stream id and delta-window-size to write buffer
817 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8);
818 session->write_buffer_offset += 8;
819
820 //SPDYF_DEBUG("window_update sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32));
821
822 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
823 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
824
825 return SPDY_YES;
826}
827
828
829void
830SPDYF_handler_ignore_frame (struct SPDY_Session *session)
831{
832 struct SPDYF_Control_Frame *frame;
833
834 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
835 || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
836 "the function is called wrong");
837
838
839 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
840
841 //handle subheaders
842 if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
843 {
844 if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
845 {
846 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
847 return;
848 }
849 else
850 session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
851 }
852
853 //handle body
854
855 if(session->read_buffer_offset - session->read_buffer_beginning
856 >= frame->length)
857 {
858 session->read_buffer_beginning += frame->length;
859 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
860 free(frame);
861 }
862}
863
864
865int
866SPDYF_session_read (struct SPDY_Session *session)
867{
868 int bytes_read;
869 bool reallocate;
870 size_t actual_buf_size;
871
872 if(SPDY_SESSION_STATUS_CLOSING == session->status
873 || SPDY_SESSION_STATUS_FLUSHING == session->status)
874 return SPDY_NO;
875
876 //if the read buffer is full to the end, we need to reallocate space
877 if (session->read_buffer_size == session->read_buffer_offset)
878 {
879 //but only if the state of the session requires it
880 //i.e. no further proceeding is possible without reallocation
881 reallocate = false;
882 actual_buf_size = session->read_buffer_offset
883 - session->read_buffer_beginning;
884 switch(session->status)
885 {
886 case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
887
888 case SPDY_SESSION_STATUS_IGNORE_BYTES:
889 //we need space for a whole control frame header
890 if(actual_buf_size < sizeof(struct SPDYF_Control_Frame))
891 reallocate = true;
892 break;
893
894 case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
895
896 case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
897 //we need as many bytes as set in length field of the
898 //header
899 SPDYF_ASSERT(NULL != session->frame_handler_cls,
900 "no frame for session");
901 if(session->frame_handler != &spdyf_handler_read_data)
902 {
903 if(actual_buf_size
904 < ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length)
905 reallocate = true;
906 }
907 else
908 {
909 if(actual_buf_size
910 < ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length)
911 reallocate = true;
912 }
913 break;
914
915 case SPDY_SESSION_STATUS_CLOSING:
916 case SPDY_SESSION_STATUS_FLUSHING:
917 //nothing needed
918 break;
919 }
920
921 if(reallocate)
922 {
923 //reuse the space in the buffer that was already read by the lib
924 memmove(session->read_buffer,
925 session->read_buffer + session->read_buffer_beginning,
926 session->read_buffer_offset - session->read_buffer_beginning);
927
928 session->read_buffer_offset -= session->read_buffer_beginning;
929 session->read_buffer_beginning = 0;
930 }
931 else
932 {
933 //will read next time
934 //TODO optimize it, memmove more often?
935 return SPDY_NO;
936 }
937 }
938
939 session->last_activity = SPDYF_monotonic_time();
940
941 //actual read from the TLS socket
942 bytes_read = session->fio_recv(session,
943 session->read_buffer + session->read_buffer_offset,
944 session->read_buffer_size - session->read_buffer_offset);
945
946 switch(bytes_read)
947 {
948 case SPDY_IO_ERROR_CLOSED:
949 //The TLS connection was closed by the other party, clean
950 //or not
951 shutdown (session->socket_fd, SHUT_RD);
952 session->read_closed = true;
953 session->status = SPDY_SESSION_STATUS_CLOSING;
954 return SPDY_YES;
955
956 case SPDY_IO_ERROR_ERROR:
957 //any kind of error in the TLS subsystem
958 //try to prepare GOAWAY frame
959 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
960 //try to flush the queue when write is called
961 session->status = SPDY_SESSION_STATUS_FLUSHING;
962 return SPDY_YES;
963
964 case SPDY_IO_ERROR_AGAIN:
965 //read or write should be called again; leave it for the
966 //next time
967 return SPDY_NO;
968
969 //default:
970 //something was really read from the TLS subsystem
971 //just continue
972 }
973
974 session->read_buffer_offset += bytes_read;
975
976 return SPDY_YES;
977}
978
979
980int
981SPDYF_session_write (struct SPDY_Session *session,
982 bool only_one_frame)
983{
984 unsigned int i;
985 int bytes_written;
986 struct SPDYF_Response_Queue *queue_head;
987 struct SPDYF_Response_Queue *response_queue;
988
989 if(SPDY_SESSION_STATUS_CLOSING == session->status)
990 return SPDY_NO;
991
992 if(SPDY_NO == session->fio_before_write(session))
993 return SPDY_NO;
994
995 for(i=0;
996 only_one_frame
997 ? i < 1
998 : i < session->max_num_frames;
999 ++i)
1000 {
1001 //if the buffer is not null, part of the last frame is still
1002 //pending to be sent
1003 if(NULL == session->write_buffer)
1004 {
1005 //discard frames on closed streams
1006 response_queue = session->response_queue_head;
1007
1008 while(NULL != response_queue)
1009 {
1010 //if stream is closed, remove not yet sent frames
1011 //associated with it
1012 //GOAWAY frames are not associated to streams
1013 //and still need to be sent
1014 if(NULL == response_queue->stream
1015 || !response_queue->stream->is_out_closed)
1016 break;
1017
1018 DLL_remove(session->response_queue_head,session->response_queue_tail,response_queue);
1019
1020 if(NULL != response_queue->frqcb)
1021 {
1022 response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_STREAM_CLOSED);
1023 }
1024
1025 SPDYF_response_queue_destroy(response_queue);
1026 response_queue = session->response_queue_head;
1027 }
1028
1029 if(NULL == session->response_queue_head)
1030 break;//nothing on the queue
1031
1032 //get next data from queue and put it to the write buffer
1033 // to send it
1034 if(SPDY_NO == session->response_queue_head->process_response_handler(session))
1035 {
1036 //error occured and the handler changed or not the
1037 //session's status appropriately
1038 if(SPDY_SESSION_STATUS_CLOSING == session->status)
1039 {
1040 //try to send GOAWAY first if the current frame is different
1041 if(session->response_queue_head->is_data
1042 || SPDY_CONTROL_FRAME_TYPES_GOAWAY
1043 != session->response_queue_head->control_frame->type)
1044 {
1045 session->status = SPDY_SESSION_STATUS_FLUSHING;
1046 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, true);
1047 SPDYF_session_write(session,true);
1048 session->status = SPDY_SESSION_STATUS_CLOSING;
1049 }
1050 return SPDY_YES;
1051 }
1052
1053 //just return from the loop to return from this function
1054 ++i;
1055 break;
1056 }
1057
1058 //check if something was prepared for writing
1059 //on respones with callbacks it is possible that their is no
1060 //data available
1061 if(0 == session->write_buffer_size)//nothing to write
1062 {
1063 if(response_queue != session->response_queue_head)
1064 {
1065 //the handler modified the queue
1066 continue;
1067 }
1068 else
1069 {
1070 //no need to try the same frame again
1071 ++i;
1072 break;
1073 }
1074 }
1075 }
1076
1077 session->last_activity = SPDYF_monotonic_time();
1078
1079 //actual write to the IO
1080 bytes_written = session->fio_send(session,
1081 session->write_buffer + session->write_buffer_beginning,
1082 session->write_buffer_offset - session->write_buffer_beginning);
1083
1084 switch(bytes_written)
1085 {
1086 case SPDY_IO_ERROR_CLOSED:
1087 //The TLS connection was closed by the other party, clean
1088 //or not
1089 shutdown (session->socket_fd, SHUT_RD);
1090 session->read_closed = true;
1091 session->status = SPDY_SESSION_STATUS_CLOSING;
1092 return SPDY_YES;
1093
1094 case SPDY_IO_ERROR_ERROR:
1095 //any kind of error in the TLS subsystem
1096 //forbid more writing
1097 session->status = SPDY_SESSION_STATUS_CLOSING;
1098 return SPDY_YES;
1099
1100 case SPDY_IO_ERROR_AGAIN:
1101 //read or write should be called again; leave it for the
1102 //next time; return from the function as we do not now
1103 //whether reading or writing is needed
1104 return i>0 ? SPDY_YES : SPDY_NO;
1105
1106 //default:
1107 //something was really read from the TLS subsystem
1108 //just continue
1109 }
1110
1111 session->write_buffer_beginning += bytes_written;
1112
1113 //check if the full buffer was written
1114 if(session->write_buffer_beginning == session->write_buffer_size)
1115 {
1116 //that response is handled, remove it from queue
1117 free(session->write_buffer);
1118 session->write_buffer = NULL;
1119 session->write_buffer_size = 0;
1120 queue_head = session->response_queue_head;
1121 if(NULL == queue_head->next)
1122 {
1123 session->response_queue_head = NULL;
1124 session->response_queue_tail = NULL;
1125 }
1126 else
1127 {
1128 session->response_queue_head = queue_head->next;
1129 session->response_queue_head->prev = NULL;
1130 }
1131
1132 //set stream to closed if the frame's fin flag is set
1133 SPDYF_stream_set_flags_on_write(queue_head);
1134
1135 if(NULL != queue_head->frqcb)
1136 {
1137 //application layer callback to notify sending of the response
1138 queue_head->frqcb(queue_head->frqcb_cls, queue_head, SPDY_RESPONSE_RESULT_SUCCESS);
1139 }
1140
1141 SPDYF_response_queue_destroy(queue_head);
1142 }
1143 }
1144
1145 if(SPDY_SESSION_STATUS_FLUSHING == session->status
1146 && NULL == session->response_queue_head)
1147 session->status = SPDY_SESSION_STATUS_CLOSING;
1148
1149 //return i>0 ? SPDY_YES : SPDY_NO;
1150 return session->fio_after_write(session, i>0 ? SPDY_YES : SPDY_NO);
1151}
1152
1153
1154int
1155SPDYF_session_idle (struct SPDY_Session *session)
1156{
1157 size_t read_buffer_beginning;
1158 size_t frame_length;
1159 struct SPDYF_Control_Frame* control_frame;
1160 struct SPDYF_Data_Frame *data_frame;
1161
1162 //prepare session for closing if timeout is used and already passed
1163 if(SPDY_SESSION_STATUS_CLOSING != session->status
1164 && session->daemon->session_timeout
1165 && (session->last_activity + session->daemon->session_timeout < SPDYF_monotonic_time()))
1166 {
1167 session->status = SPDY_SESSION_STATUS_CLOSING;
1168 //best effort for sending GOAWAY
1169 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
1170 SPDYF_session_write(session,true);
1171 }
1172
1173 switch(session->status)
1174 {
1175 //expect new frame to arrive
1176 case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
1177 session->current_stream_id = 0;
1178 //check if the whole frame header is already here
1179 //both frame types have the same length
1180 if(session->read_buffer_offset - session->read_buffer_beginning
1181 < sizeof(struct SPDYF_Control_Frame))
1182 return SPDY_NO;
1183
1184 /* check the first bit to see if it is data or control frame
1185 * and also if the version is supported */
1186 if(0x80 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning)
1187 && SPDY_VERSION == *((uint8_t *)session->read_buffer + session->read_buffer_beginning + 1))
1188 {
1189 //control frame
1190 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1191 {
1192 SPDYF_DEBUG("No memory");
1193 return SPDY_NO;
1194 }
1195
1196 //get frame headers
1197 memcpy(control_frame,
1198 session->read_buffer + session->read_buffer_beginning,
1199 sizeof(struct SPDYF_Control_Frame));
1200 session->read_buffer_beginning += sizeof(struct SPDYF_Control_Frame);
1201 SPDYF_CONTROL_FRAME_NTOH(control_frame);
1202
1203 session->status = SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER;
1204 //assign different frame handler according to frame type
1205 switch(control_frame->type){
1206 case SPDY_CONTROL_FRAME_TYPES_SYN_STREAM:
1207 session->frame_handler = &spdyf_handler_read_syn_stream;
1208 break;
1209 case SPDY_CONTROL_FRAME_TYPES_GOAWAY:
1210 session->frame_handler = &spdyf_handler_read_goaway;
1211 break;
1212 case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
1213 session->frame_handler = &spdyf_handler_read_rst_stream;
1214 break;
1215 default:
1216 session->frame_handler = &SPDYF_handler_ignore_frame;
1217 }
1218 session->frame_handler_cls = control_frame;
1219 //DO NOT break the outer case
1220 }
1221 else if(0 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning))
1222 {
1223 //needed for POST
1224 //data frame
1225 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
1226 {
1227 SPDYF_DEBUG("No memory");
1228 return SPDY_NO;
1229 }
1230
1231 //get frame headers
1232 memcpy(data_frame,
1233 session->read_buffer + session->read_buffer_beginning,
1234 sizeof(struct SPDYF_Data_Frame));
1235 session->read_buffer_beginning += sizeof(struct SPDYF_Data_Frame);
1236 SPDYF_DATA_FRAME_NTOH(data_frame);
1237
1238 session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
1239 session->frame_handler = &spdyf_handler_read_data;
1240 session->frame_handler_cls = data_frame;
1241 //DO NOT brake the outer case
1242 }
1243 else
1244 {
1245 SPDYF_DEBUG("another protocol or version received!");
1246
1247 /* According to the draft the lib should send here
1248 * RST_STREAM with status UNSUPPORTED_VERSION. I don't
1249 * see any sense of keeping the session open since
1250 * we don't know how many bytes is the bogus "frame".
1251 * And the latter normally will be HTTP request.
1252 *
1253 */
1254
1255 //shutdown(session->socket_fd, SHUT_RD);
1256 session->status = SPDY_SESSION_STATUS_FLUSHING;
1257 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_PROTOCOL_ERROR,false);
1258 //SPDYF_session_write(session,false);
1259 /* close connection since the client expects another
1260 protocol from us */
1261 //SPDYF_session_close(session);
1262 return SPDY_YES;
1263 }
1264
1265 //expect specific header fields after the standard header
1266 case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
1267 if(NULL!=session->frame_handler)
1268 {
1269 read_buffer_beginning = session->read_buffer_beginning;
1270 //if everything is ok, the "body" will also be processed
1271 //by the handler
1272 session->frame_handler(session);
1273
1274 if(SPDY_SESSION_STATUS_IGNORE_BYTES == session->status)
1275 {
1276 //check for larger than max supported frame
1277 if(session->frame_handler != &spdyf_handler_read_data)
1278 {
1279 frame_length = ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length;
1280 }
1281 else
1282 {
1283 frame_length = ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length;
1284 }
1285
1286 //if(SPDY_MAX_SUPPORTED_FRAME_SIZE < frame_length)
1287 {
1288 SPDYF_DEBUG("received frame with unsupported size: %zu", frame_length);
1289 //the data being received must be ignored and
1290 //RST_STREAM sent
1291
1292 //ignore bytes that will arive later
1293 session->read_ignore_bytes = frame_length
1294 + read_buffer_beginning
1295 - session->read_buffer_offset;
1296 //ignore what is already in read buffer
1297 session->read_buffer_beginning = session->read_buffer_offset;
1298
1299 SPDYF_prepare_rst_stream(session,
1300 session->current_stream_id > 0 ? session->streams_head : NULL, //may be 0 here which is not good
1301 SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE);
1302
1303 //actually the read buffer can be bigger than the
1304 //max supported size
1305 session->status = session->read_ignore_bytes
1306 ? SPDY_SESSION_STATUS_IGNORE_BYTES
1307 : SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
1308
1309 free(session->frame_handler_cls);
1310 }
1311 }
1312 }
1313
1314 if(SPDY_SESSION_STATUS_IGNORE_BYTES != session->status)
1315 {
1316 break;
1317 }
1318
1319 //ignoring data in read buffer
1320 case SPDY_SESSION_STATUS_IGNORE_BYTES:
1321 SPDYF_ASSERT(session->read_ignore_bytes > 0,
1322 "Session is in wrong state");
1323 if(session->read_ignore_bytes
1324 > session->read_buffer_offset - session->read_buffer_beginning)
1325 {
1326 session->read_ignore_bytes -=
1327 session->read_buffer_offset - session->read_buffer_beginning;
1328 session->read_buffer_beginning = session->read_buffer_offset;
1329 }
1330 else
1331 {
1332 session->read_buffer_beginning += session->read_ignore_bytes;
1333 session->read_ignore_bytes = 0;
1334 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
1335 }
1336 break;
1337
1338 //expect frame body (name/value pairs)
1339 case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
1340 if(NULL!=session->frame_handler)
1341 session->frame_handler(session);
1342 break;
1343
1344 case SPDY_SESSION_STATUS_FLUSHING:
1345
1346 return SPDY_NO;
1347
1348 //because of error the session needs to be closed
1349 case SPDY_SESSION_STATUS_CLOSING:
1350 //error should be already sent to the client
1351 SPDYF_session_close(session);
1352 return SPDY_YES;
1353 }
1354
1355 return SPDY_YES;
1356}
1357
1358
1359void
1360SPDYF_session_close (struct SPDY_Session *session)
1361{
1362 struct SPDY_Daemon *daemon = session->daemon;
1363 int by_client = session->read_closed ? SPDY_YES : SPDY_NO;
1364
1365 //shutdown the tls and deinit the tls context
1366 session->fio_close_session(session);
1367 shutdown (session->socket_fd,
1368 session->read_closed ? SHUT_WR : SHUT_RDWR);
1369 session->read_closed = true;
1370
1371 //remove session from the list
1372 DLL_remove (daemon->sessions_head,
1373 daemon->sessions_tail,
1374 session);
1375 //add the session for the list for cleaning up
1376 DLL_insert (daemon->cleanup_head,
1377 daemon->cleanup_tail,
1378 session);
1379
1380 //call callback for closed session
1381 if(NULL != daemon->session_closed_cb)
1382 {
1383 daemon->session_closed_cb(daemon->cls, session, by_client);
1384 }
1385}
1386
1387
1388int
1389SPDYF_session_accept(struct SPDY_Daemon *daemon)
1390{
1391 int new_socket_fd;
1392 int ret;
1393 struct SPDY_Session *session = NULL;
1394 socklen_t addr_len;
1395 struct sockaddr *addr;
1396
1397#if HAVE_INET6
1398 struct sockaddr_in6 addr6;
1399
1400 addr = (struct sockaddr *)&addr6;
1401 addr_len = sizeof(addr6);
1402#else
1403 struct sockaddr_in addr4;
1404
1405 addr = (struct sockaddr *)&addr4;
1406 addr_len = sizeof(addr6);
1407#endif
1408
1409 new_socket_fd = accept (daemon->socket_fd, addr, &addr_len);
1410
1411 if(new_socket_fd < 1)
1412 return SPDY_NO;
1413
1414 if (NULL == (session = malloc (sizeof (struct SPDY_Session))))
1415 {
1416 goto free_and_fail;
1417 }
1418 memset (session, 0, sizeof (struct SPDY_Session));
1419
1420 session->daemon = daemon;
1421 session->socket_fd = new_socket_fd;
1422 session->max_num_frames = daemon->max_num_frames;
1423
1424 ret = SPDYF_io_set_session(session, daemon->io_subsystem);
1425 SPDYF_ASSERT(SPDY_YES == ret, "Somehow daemon->io_subsystem iswrong here");
1426
1427 //init TLS context, handshake will be done
1428 if(SPDY_YES != session->fio_new_session(session))
1429 {
1430 goto free_and_fail;
1431 }
1432
1433 //read buffer
1434 session->read_buffer_size = SPDYF_BUFFER_SIZE;
1435 if (NULL == (session->read_buffer = malloc (session->read_buffer_size)))
1436 {
1437 session->fio_close_session(session);
1438 goto free_and_fail;
1439 }
1440
1441 //address of the client
1442 if (NULL == (session->addr = malloc (addr_len)))
1443 {
1444 session->fio_close_session(session);
1445 goto free_and_fail;
1446 }
1447 memcpy (session->addr, addr, addr_len);
1448
1449 session->addr_len = addr_len;
1450 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
1451
1452 //init zlib context for the whole session
1453 if(SPDY_YES != SPDYF_zlib_deflate_init(&session->zlib_send_stream))
1454 {
1455 session->fio_close_session(session);
1456 goto free_and_fail;
1457 }
1458 if(SPDY_YES != SPDYF_zlib_inflate_init(&session->zlib_recv_stream))
1459 {
1460 session->fio_close_session(session);
1461 SPDYF_zlib_deflate_end(&session->zlib_send_stream);
1462 goto free_and_fail;
1463 }
1464
1465 //add it to daemon's list
1466 DLL_insert(daemon->sessions_head,daemon->sessions_tail,session);
1467
1468 session->last_activity = SPDYF_monotonic_time();
1469
1470 if(NULL != daemon->new_session_cb)
1471 daemon->new_session_cb(daemon->cls, session);
1472
1473 return SPDY_YES;
1474
1475 //for GOTO
1476 free_and_fail:
1477 /* something failed, so shutdown, close and free memory */
1478 shutdown (new_socket_fd, SHUT_RDWR);
1479 (void)MHD_socket_close_ (new_socket_fd);
1480
1481 if(NULL != session)
1482 {
1483 if(NULL != session->addr)
1484 free (session->addr);
1485 if(NULL != session->read_buffer)
1486 free (session->read_buffer);
1487 free (session);
1488 }
1489 return SPDY_NO;
1490}
1491
1492
1493void
1494SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
1495 struct SPDY_Session *session,
1496 int consider_priority)
1497{
1498 struct SPDYF_Response_Queue *pos;
1499 struct SPDYF_Response_Queue *last;
1500 uint8_t priority;
1501
1502 SPDYF_ASSERT(SPDY_YES != consider_priority || NULL != response_to_queue->stream,
1503 "called with consider_priority but no stream provided");
1504
1505 last = response_to_queue;
1506 while(NULL != last->next)
1507 {
1508 last = last->next;
1509 }
1510
1511 if(SPDY_NO == consider_priority)
1512 {
1513 //put it at the end of the queue
1514 response_to_queue->prev = session->response_queue_tail;
1515 if (NULL == session->response_queue_head)
1516 session->response_queue_head = response_to_queue;
1517 else
1518 session->response_queue_tail->next = response_to_queue;
1519 session->response_queue_tail = last;
1520 return;
1521 }
1522 else if(-1 == consider_priority)
1523 {
1524 //put it at the head of the queue
1525 last->next = session->response_queue_head;
1526 if (NULL == session->response_queue_tail)
1527 session->response_queue_tail = last;
1528 else
1529 session->response_queue_head->prev = response_to_queue;
1530 session->response_queue_head = response_to_queue;
1531 return;
1532 }
1533
1534 if(NULL == session->response_queue_tail)
1535 {
1536 session->response_queue_head = response_to_queue;
1537 session->response_queue_tail = last;
1538 return;
1539 }
1540
1541 //search for the right position to put it
1542 pos = session->response_queue_tail;
1543 priority = response_to_queue->stream->priority;
1544 while(NULL != pos
1545 && pos->stream->priority > priority)
1546 {
1547 pos = pos->prev;
1548 }
1549
1550 if(NULL == pos)
1551 {
1552 //put it on the head
1553 session->response_queue_head->prev = last;
1554 last->next = session->response_queue_head;
1555 session->response_queue_head = response_to_queue;
1556 }
1557 else if(NULL == pos->next)
1558 {
1559 //put it at the end
1560 response_to_queue->prev = pos;
1561 pos->next = response_to_queue;
1562 session->response_queue_tail = last;
1563 }
1564 else
1565 {
1566 response_to_queue->prev = pos;
1567 last->next = pos->next;
1568 pos->next = response_to_queue;
1569 last->next->prev = last;
1570 }
1571}
1572
1573
1574void
1575SPDYF_session_destroy(struct SPDY_Session *session)
1576{
1577 struct SPDYF_Stream *stream;
1578 struct SPDYF_Response_Queue *response_queue;
1579
1580 (void)MHD_socket_close_ (session->socket_fd);
1581 SPDYF_zlib_deflate_end(&session->zlib_send_stream);
1582 SPDYF_zlib_inflate_end(&session->zlib_recv_stream);
1583
1584 //clean up unsent data in the output queue
1585 while (NULL != (response_queue = session->response_queue_head))
1586 {
1587 DLL_remove (session->response_queue_head,
1588 session->response_queue_tail,
1589 response_queue);
1590
1591 if(NULL != response_queue->frqcb)
1592 {
1593 response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_SESSION_CLOSED);
1594 }
1595
1596 SPDYF_response_queue_destroy(response_queue);
1597 }
1598
1599 //clean up the streams belonging to this session
1600 while (NULL != (stream = session->streams_head))
1601 {
1602 DLL_remove (session->streams_head,
1603 session->streams_tail,
1604 stream);
1605
1606 SPDYF_stream_destroy(stream);
1607 }
1608
1609 free(session->addr);
1610 free(session->read_buffer);
1611 free(session->write_buffer);
1612 free(session);
1613}
1614
1615
1616int
1617SPDYF_prepare_goaway (struct SPDY_Session *session,
1618 enum SPDY_GOAWAY_STATUS status,
1619 bool in_front)
1620{
1621 struct SPDYF_Response_Queue *response_to_queue;
1622 struct SPDYF_Control_Frame *control_frame;
1623 uint32_t *data;
1624
1625 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
1626 {
1627 return SPDY_NO;
1628 }
1629 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
1630
1631 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1632 {
1633 free(response_to_queue);
1634 return SPDY_NO;
1635 }
1636 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
1637
1638 if(NULL == (data = malloc(4)))
1639 {
1640 free(control_frame);
1641 free(response_to_queue);
1642 return SPDY_NO;
1643 }
1644 *(data) = htonl(status);
1645
1646 control_frame->control_bit = 1;
1647 control_frame->version = SPDY_VERSION;
1648 control_frame->type = SPDY_CONTROL_FRAME_TYPES_GOAWAY;
1649 control_frame->flags = 0;
1650
1651 response_to_queue->control_frame = control_frame;
1652 response_to_queue->process_response_handler = &SPDYF_handler_write_goaway;
1653 response_to_queue->data = data;
1654 response_to_queue->data_size = 4;
1655
1656 SPDYF_queue_response (response_to_queue,
1657 session,
1658 in_front ? -1 : SPDY_NO);
1659
1660 return SPDY_YES;
1661}
1662
1663
1664int
1665SPDYF_prepare_rst_stream (struct SPDY_Session *session,
1666 struct SPDYF_Stream * stream,
1667 enum SPDY_RST_STREAM_STATUS status)
1668{
1669 struct SPDYF_Response_Queue *response_to_queue;
1670 struct SPDYF_Control_Frame *control_frame;
1671 uint32_t *data;
1672 uint32_t stream_id;
1673
1674 if(NULL == stream)
1675 stream_id = 0;
1676 else
1677 stream_id = stream->stream_id;
1678
1679 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
1680 {
1681 return SPDY_NO;
1682 }
1683 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
1684
1685 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1686 {
1687 free(response_to_queue);
1688 return SPDY_NO;
1689 }
1690 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
1691
1692 if(NULL == (data = malloc(8)))
1693 {
1694 free(control_frame);
1695 free(response_to_queue);
1696 return SPDY_NO;
1697 }
1698 *(data) = HTON31(stream_id);
1699 *(data + 1) = htonl(status);
1700
1701 control_frame->control_bit = 1;
1702 control_frame->version = SPDY_VERSION;
1703 control_frame->type = SPDY_CONTROL_FRAME_TYPES_RST_STREAM;
1704 control_frame->flags = 0;
1705
1706 response_to_queue->control_frame = control_frame;
1707 response_to_queue->process_response_handler = &SPDYF_handler_write_rst_stream;
1708 response_to_queue->data = data;
1709 response_to_queue->data_size = 8;
1710 response_to_queue->stream = stream;
1711
1712 SPDYF_queue_response (response_to_queue,
1713 session,
1714 -1);
1715
1716 return SPDY_YES;
1717}
1718
1719
1720int
1721SPDYF_prepare_window_update (struct SPDY_Session *session,
1722 struct SPDYF_Stream * stream,
1723 int32_t delta_window_size)
1724{
1725 struct SPDYF_Response_Queue *response_to_queue;
1726 struct SPDYF_Control_Frame *control_frame;
1727 uint32_t *data;
1728
1729 SPDYF_ASSERT(NULL != stream, "stream cannot be NULL");
1730
1731 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
1732 {
1733 return SPDY_NO;
1734 }
1735 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
1736
1737 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1738 {
1739 free(response_to_queue);
1740 return SPDY_NO;
1741 }
1742 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
1743
1744 if(NULL == (data = malloc(8)))
1745 {
1746 free(control_frame);
1747 free(response_to_queue);
1748 return SPDY_NO;
1749 }
1750 *(data) = HTON31(stream->stream_id);
1751 *(data + 1) = HTON31(delta_window_size);
1752
1753 control_frame->control_bit = 1;
1754 control_frame->version = SPDY_VERSION;
1755 control_frame->type = SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE;
1756 control_frame->flags = 0;
1757
1758 response_to_queue->control_frame = control_frame;
1759 response_to_queue->process_response_handler = &SPDYF_handler_write_window_update;
1760 response_to_queue->data = data;
1761 response_to_queue->data_size = 8;
1762 response_to_queue->stream = stream;
1763
1764 SPDYF_queue_response (response_to_queue,
1765 session,
1766 -1);
1767
1768 return SPDY_YES;
1769}
diff --git a/src/microspdy/session.h b/src/microspdy/session.h
deleted file mode 100644
index 29ab550f..00000000
--- a/src/microspdy/session.h
+++ /dev/null
@@ -1,281 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file session.h
21 * @brief TCP connection/SPDY session handling
22 * @author Andrey Uzunov
23 */
24
25#ifndef SESSION_H
26#define SESSION_H
27
28#include "platform.h"
29#include "structures.h"
30
31/**
32 * Called by the daemon when the socket for the session has available
33 * data to be read. Reads data from the TLS socket and puts it to the
34 * session's read buffer. The latte
35 *
36 * @param session SPDY_Session for which data will be read.
37 * @return SPDY_YES if something was read or session's status was
38 * changed. It is possible that error occurred but was handled
39 * and the status was therefore changed.
40 * SPDY_NO if nothing happened, e.g. the subsystem wants read/
41 * write to be called again.
42 */
43int
44SPDYF_session_read (struct SPDY_Session *session);
45
46
47/**
48 * Called by the daemon when the socket for the session is ready for some
49 * data to be written to it. For one or more objects on the response
50 * queue tries to fill in the write buffer, based on the frame on the
51 * queue, and to write data to the TLS socket.
52 *
53 * @param session SPDY_Session for which data will be written.
54 * @param only_one_frame when true, the function will write at most one
55 * SPDY frame to the underlying IO subsystem;
56 * when false, the function will write up to
57 * session->max_num_frames SPDY frames
58 * @return SPDY_YES if the session's internal writing state has changed:
59 * something was written and/or session's status was
60 * changed and/or response callback was called but did not provide
61 * data. It is possible that error occurred but was handled
62 * and the status was therefore changed.
63 * SPDY_NO if nothing happened. However, it is possible that some
64 * frames were discarded within the call, e.g. frames belonging
65 * to a closed stream.
66 */
67int
68SPDYF_session_write (struct SPDY_Session *session,
69 bool only_one_frame);
70
71
72/**
73 * Called by the daemon on SPDY_run to handle the data in the read and write
74 * buffer of a session. Based on the state and the content of the read
75 * buffer new frames are received and interpreted, appropriate user
76 * callbacks are called and maybe something is put on the response queue
77 * ready to be handled by session_write.
78 *
79 * @param session SPDY_Session which will be handled.
80 * @return SPDY_YES if something from the read buffers was processed,
81 * session's status was changed and/or the session was closed.
82 * SPDY_NO if nothing happened, e.g. the session is in a state,
83 * not allowing processing read buffers.
84 */
85int
86SPDYF_session_idle (struct SPDY_Session *session);
87
88
89/**
90 * This function shutdowns the socket, moves the session structure to
91 * daemon's queue for sessions to be cleaned up.
92 *
93 * @param session SPDY_Session which will be handled.
94 */
95void
96SPDYF_session_close (struct SPDY_Session *session);
97
98
99/**
100 * Called to accept new TCP connection and create SPDY session.
101 *
102 * @param daemon SPDY_Daemon whose listening socket is used.
103 * @return SPDY_NO on any kind of error while accepting new TCP connection
104 * and initializing new SPDY_Session.
105 * SPDY_YES otherwise.
106 */
107int
108SPDYF_session_accept(struct SPDY_Daemon *daemon);
109
110
111/**
112 * Puts SPDYF_Response_Queue object on the queue to be sent to the
113 * client later.
114 *
115 * @param response_to_queue linked list of objects containing SPDY
116 * frame and data to be added to the queue
117 * @param session SPDY session for which the response is sent
118 * @param consider_priority if SPDY_NO, the list will be added to the
119 * end of the queue.
120 * If SPDY_YES, the response will be added after
121 * the last previously added response with priority of the
122 * request grater or equal to that of the current one.
123 * If -1, the object will be put at the head of the queue.
124 */
125void
126SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
127 struct SPDY_Session *session,
128 int consider_priority);
129
130
131/**
132 * Cleans up the TSL context for the session, closes the TCP connection,
133 * cleans up any data pointed by members of the session structure
134 * (buffers, queue of responses, etc.) and frees the memory allocated by
135 * the session itself.
136 */
137void
138SPDYF_session_destroy(struct SPDY_Session *session);
139
140
141/**
142 * Prepares GOAWAY frame to tell the client to stop creating new streams.
143 * The session should be closed soon after this call.
144 *
145 * @param session SPDY session
146 * @param status code for the GOAWAY frame
147 * @param in_front whether or not to put the frame in front of everything
148 * on the response queue
149 * @return SPDY_NO on error (not enough memory) or
150 * SPDY_YES on success
151 */
152int
153SPDYF_prepare_goaway (struct SPDY_Session *session,
154 enum SPDY_GOAWAY_STATUS status,
155 bool in_front);
156
157
158/**
159 * Prepares RST_STREAM frame to terminate a stream. This frame may or
160 * not indicate an error. The frame will be put at the head of the queue.
161 * This means that frames for this stream which are still in the queue
162 * will be discarded soon.
163 *
164 * @param session SPDY session
165 * @param stream stream to terminate
166 * @param status code for the RST_STREAM frame
167 * @return SPDY_NO on memory error or
168 * SPDY_YES on success
169 */
170int
171SPDYF_prepare_rst_stream (struct SPDY_Session *session,
172 struct SPDYF_Stream * stream,
173 enum SPDY_RST_STREAM_STATUS status);
174
175
176/**
177 * Prepares WINDOW_UPDATE frame to tell the other party that more
178 * data can be sent on the stream. The frame will be put at the head of
179 * the queue.
180 *
181 * @param session SPDY session
182 * @param stream stream to which the changed window will apply
183 * @param delta_window_size how much the window grows
184 * @return SPDY_NO on memory error or
185 * SPDY_YES on success
186 */
187int
188SPDYF_prepare_window_update (struct SPDY_Session *session,
189 struct SPDYF_Stream * stream,
190 int32_t delta_window_size);
191
192
193/**
194 * Handler called by session_write to fill the write buffer according to
195 * the data frame waiting in the response queue.
196 * When response data is given by user callback, the lib does not know
197 * how many frames are needed. In such case this call produces
198 * another ResponseQueue object and puts it on the queue while the the
199 * user callback says that there will be more data.
200 *
201 * @return SPDY_NO on error (not enough memory or the user calback for
202 * providing response data did something wrong). If
203 * the error is unrecoverable the handler changes session's
204 * status.
205 * SPDY_YES on success
206 */
207int
208SPDYF_handler_write_data (struct SPDY_Session *session);
209
210
211/**
212 * Handler called by session_write to fill the write buffer based on the
213 * control frame (SYN_REPLY) waiting in the response queue.
214 *
215 * @param session SPDY session
216 * @return SPDY_NO on error (zlib state is broken; the session MUST be
217 * closed). If
218 * the error is unrecoverable the handler changes session's
219 * status.
220 * SPDY_YES on success
221 */
222int
223SPDYF_handler_write_syn_reply (struct SPDY_Session *session);
224
225
226/**
227 * Handler called by session_write to fill the write buffer based on the
228 * control frame (GOAWAY) waiting in the response queue.
229 *
230 * @param session SPDY session
231 * @return SPDY_NO on error (not enough memory; by specification the
232 * session must be closed
233 * soon, thus there is no need to handle the error) or
234 * SPDY_YES on success
235 */
236int
237SPDYF_handler_write_goaway (struct SPDY_Session *session);
238
239
240/**
241 * Handler called by session_write to fill the write buffer based on the
242 * control frame (RST_STREAM) waiting in the response queue.
243 *
244 * @param session SPDY session
245 * @return SPDY_NO on error (not enough memory). If
246 * the error is unrecoverable the handler changes session's
247 * status.
248 * SPDY_YES on success
249 */
250int
251SPDYF_handler_write_rst_stream (struct SPDY_Session *session);
252
253
254/**
255 * Handler called by session_write to fill the write buffer based on the
256 * control frame (WINDOW_UPDATE) waiting in the response queue.
257 *
258 * @param session SPDY session
259 * @return SPDY_NO on error (not enough memory). If
260 * the error is unrecoverable the handler changes session's
261 * status.
262 * SPDY_YES on success
263 */
264int
265SPDYF_handler_write_window_update (struct SPDY_Session *session);
266
267
268/**
269 * Carefully ignore the full size of frames which are not yet supported
270 * by the lib.
271 * TODO Ignoring frames containing compressed bodies means that the
272 * compress state will be corrupted on next received frame. According to
273 * the draft the lib SHOULD try to decompress data also in corrupted
274 * frames just to keep right compression state.
275 *
276 * @param session SPDY_Session whose read buffer is used.
277 */
278void
279SPDYF_handler_ignore_frame (struct SPDY_Session *session);
280
281#endif
diff --git a/src/microspdy/stream.c b/src/microspdy/stream.c
deleted file mode 100644
index 9b6dc08d..00000000
--- a/src/microspdy/stream.c
+++ /dev/null
@@ -1,169 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file stream.c
21 * @brief SPDY streams handling
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27#include "internal.h"
28#include "session.h"
29
30
31int
32SPDYF_stream_new (struct SPDY_Session *session)
33{
34 uint32_t stream_id;
35 uint32_t assoc_stream_id;
36 uint8_t priority;
37 uint8_t slot;
38 size_t buffer_pos = session->read_buffer_beginning;
39 struct SPDYF_Stream *stream;
40 struct SPDYF_Control_Frame *frame;
41
42 if((session->read_buffer_offset - session->read_buffer_beginning) < 10)
43 {
44 //not all fields are received to create new stream
45 return SPDY_NO;
46 }
47
48 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
49
50 //get stream id of the new stream
51 memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
52 stream_id = NTOH31(stream_id);
53 session->read_buffer_beginning += 4;
54 if(stream_id <= session->last_in_stream_id || 0==(stream_id % 2))
55 {
56 //wrong stream id sent by client
57 //GOAWAY with PROTOCOL_ERROR MUST be sent
58 //TODO
59
60 //ignore frame
61 session->frame_handler = &SPDYF_handler_ignore_frame;
62 return SPDY_NO;
63 }
64 else if(session->is_goaway_sent)
65 {
66 //the client is not allowed to create new streams anymore
67 //we MUST ignore the frame
68 session->frame_handler = &SPDYF_handler_ignore_frame;
69 return SPDY_NO;
70 }
71
72 //set highest stream id for session
73 session->last_in_stream_id = stream_id;
74
75 //get assoc stream id of the new stream
76 //this value is used with SPDY PUSH, thus nothing to do with it here
77 memcpy(&assoc_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
78 assoc_stream_id = NTOH31(assoc_stream_id);
79 session->read_buffer_beginning += 4;
80
81 //get stream priority (3 bits)
82 //after it there are 5 bits that are not used
83 priority = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning) >> 5;
84 session->read_buffer_beginning++;
85
86 //get slot (see SPDY draft)
87 slot = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning);
88 session->read_buffer_beginning++;
89
90 if(NULL == (stream = malloc(sizeof(struct SPDYF_Stream))))
91 {
92 SPDYF_DEBUG("No memory");
93 //revert buffer state
94 session->read_buffer_beginning = buffer_pos;
95 return SPDY_NO;
96 }
97 memset(stream,0, sizeof(struct SPDYF_Stream));
98 stream->session = session;
99 stream->stream_id = stream_id;
100 stream->assoc_stream_id = assoc_stream_id;
101 stream->priority = priority;
102 stream->slot = slot;
103 stream->is_in_closed = (frame->flags & SPDY_SYN_STREAM_FLAG_FIN) != 0;
104 stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0;
105 stream->is_out_closed = stream->flag_unidirectional;
106 stream->is_server_initiator = false;
107 stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
108
109 //put the stream to the list of streams for the session
110 DLL_insert(session->streams_head, session->streams_tail, stream);
111
112 return SPDY_YES;
113}
114
115
116void
117SPDYF_stream_destroy(struct SPDYF_Stream *stream)
118{
119 SPDY_name_value_destroy(stream->headers);
120 free(stream);
121 stream = NULL;
122}
123
124
125void
126SPDYF_stream_set_flags_on_write(struct SPDYF_Response_Queue *response_queue)
127{
128 struct SPDYF_Stream * stream = response_queue->stream;
129
130 if(NULL != response_queue->data_frame)
131 {
132 stream->is_out_closed = (bool)(response_queue->data_frame->flags & SPDY_DATA_FLAG_FIN);
133 }
134 else if(NULL != response_queue->control_frame)
135 {
136 switch(response_queue->control_frame->type)
137 {
138 case SPDY_CONTROL_FRAME_TYPES_SYN_REPLY:
139 stream->is_out_closed = (bool)(response_queue->control_frame->flags & SPDY_SYN_REPLY_FLAG_FIN);
140 break;
141
142 case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
143 if(NULL != stream)
144 {
145 stream->is_out_closed = true;
146 stream->is_in_closed = true;
147 }
148 break;
149
150 }
151 }
152}
153
154
155//TODO add function *on_read
156
157
158struct SPDYF_Stream *
159SPDYF_stream_find(uint32_t stream_id, struct SPDY_Session * session)
160{
161 struct SPDYF_Stream * stream = session->streams_head;
162
163 while(NULL != stream && stream_id != stream->stream_id)
164 {
165 stream = stream->next;
166 }
167
168 return stream;
169}
diff --git a/src/microspdy/stream.h b/src/microspdy/stream.h
deleted file mode 100644
index 220231f4..00000000
--- a/src/microspdy/stream.h
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file stream.h
21 * @brief SPDY streams handling
22 * @author Andrey Uzunov
23 */
24
25#ifndef STREAM_H
26#define STREAM_H
27
28#include "platform.h"
29
30
31/**
32 * Reads data from session's read buffer and tries to create a new SPDY
33 * stream. This function is called after control frame's header has been
34 * read from the buffer (after the length field). If bogus frame is
35 * received the function changes the read handler of the session and
36 * fails, i.e. there is no need of further error handling by the caller.
37 *
38 * @param session SPDY_Session whose read buffer is being read
39 * @return SPDY_YES if a new SPDY stream request was correctly received
40 * and handled. SPDY_NO if the whole SPDY frame was not yet
41 * received or memory error occurred.
42 */
43int
44SPDYF_stream_new (struct SPDY_Session *session);
45
46
47/**
48 * Destroys stream structure and whatever is in it.
49 *
50 * @param stream SPDY_Stream to destroy
51 */
52void
53SPDYF_stream_destroy(struct SPDYF_Stream *stream);
54
55
56/**
57 * Set stream flags if needed based on the type of the frame that was
58 * just sent (e.g., close stream if it was RST_STREAM).
59 *
60 * @param response_queue sent for this stream
61 */
62void
63SPDYF_stream_set_flags_on_write(struct SPDYF_Response_Queue *response_queue);
64
65
66/**
67 * Find and return a session's stream, based on stream's ID.
68 *
69 * @param stream_id to search for
70 * @param session whose streams are considered
71 * @return SPDY_Stream with the desired ID. Can be NULL.
72 */
73struct SPDYF_Stream *
74SPDYF_stream_find(uint32_t stream_id, struct SPDY_Session * session);
75
76#endif
diff --git a/src/microspdy/structures.c b/src/microspdy/structures.c
deleted file mode 100644
index f00806bc..00000000
--- a/src/microspdy/structures.c
+++ /dev/null
@@ -1,638 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file structures.c
21 * @brief Functions for handling most of the structures in defined
22 * in structures.h
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include "structures.h"
28#include "internal.h"
29#include "session.h"
30//TODO not for here?
31#include <ctype.h>
32
33
34int
35SPDYF_name_value_is_empty(struct SPDY_NameValue *container)
36{
37 SPDYF_ASSERT(NULL != container, "NULL is not an empty container!");
38 return (NULL == container->name && NULL == container->value) ? SPDY_YES : SPDY_NO;
39}
40
41struct SPDY_NameValue *
42SPDY_name_value_create ()
43{
44 struct SPDY_NameValue *pair;
45
46 if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
47 return NULL;
48
49 memset (pair, 0, sizeof (struct SPDY_NameValue));
50
51 return pair;
52}
53
54
55int
56SPDY_name_value_add (struct SPDY_NameValue *container,
57 const char *name,
58 const char *value)
59{
60 unsigned int i;
61 unsigned int len;
62 struct SPDY_NameValue *pair;
63 struct SPDY_NameValue *temp;
64 char **temp_value;
65 char *temp_string;
66
67 if(NULL == container || NULL == name || NULL == value || 0 == (len = strlen(name)))
68 return SPDY_INPUT_ERROR;
69 //TODO there is old code handling value==NULL
70 //update it to handle strlen(value)==0
71
72 for(i=0; i<len; ++i)
73 {
74 if(isupper((int) name[i]))
75 return SPDY_INPUT_ERROR;
76 }
77
78 if(SPDYF_name_value_is_empty(container))
79 {
80 //container is empty/just created
81 if (NULL == (container->name = strdup (name)))
82 {
83 return SPDY_NO;
84 }
85 if (NULL == (container->value = malloc(sizeof(char *))))
86 {
87 free(container->name);
88 return SPDY_NO;
89 }
90 /*if(NULL == value)
91 container->value[0] = NULL;
92 else */if (NULL == (container->value[0] = strdup (value)))
93 {
94 free(container->value);
95 free(container->name);
96 return SPDY_NO;
97 }
98 container->num_values = 1;
99 return SPDY_YES;
100 }
101
102 pair = container;
103 while(NULL != pair)
104 {
105 if(0 == strcmp(pair->name, name))
106 {
107 //the value will be added to this pair
108 break;
109 }
110 pair = pair->next;
111 }
112
113 if(NULL == pair)
114 {
115 //the name doesn't exist in container, add new pair
116 if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
117 return SPDY_NO;
118
119 memset(pair, 0, sizeof(struct SPDY_NameValue));
120
121 if (NULL == (pair->name = strdup (name)))
122 {
123 free(pair);
124 return SPDY_NO;
125 }
126 if (NULL == (pair->value = malloc(sizeof(char *))))
127 {
128 free(pair->name);
129 free(pair);
130 return SPDY_NO;
131 }
132 /*if(NULL == value)
133 pair->value[0] = NULL;
134 else */if (NULL == (pair->value[0] = strdup (value)))
135 {
136 free(pair->value);
137 free(pair->name);
138 free(pair);
139 return SPDY_NO;
140 }
141 pair->num_values = 1;
142
143 temp = container;
144 while(NULL != temp->next)
145 temp = temp->next;
146 temp->next = pair;
147 pair->prev = temp;
148
149 return SPDY_YES;
150 }
151
152 //check for duplication (case sensitive)
153 for(i=0; i<pair->num_values; ++i)
154 if(0 == strcmp(pair->value[i], value))
155 return SPDY_NO;
156
157 if(strlen(pair->value[0]) > 0)
158 {
159 //the value will be appended to the others for this name
160 if (NULL == (temp_value = malloc((pair->num_values + 1) * sizeof(char *))))
161 {
162 return SPDY_NO;
163 }
164 memcpy(temp_value, pair->value, pair->num_values * sizeof(char *));
165 if (NULL == (temp_value[pair->num_values] = strdup (value)))
166 {
167 free(temp_value);
168 return SPDY_NO;
169 }
170 free(pair->value);
171 pair->value = temp_value;
172 ++pair->num_values;
173 return SPDY_YES;
174 }
175
176 //just replace the empty value
177
178 if (NULL == (temp_string = strdup (value)))
179 {
180 return SPDY_NO;
181 }
182 free(pair->value[0]);
183 pair->value[0] = temp_string;
184
185 return SPDY_YES;
186}
187
188
189const char * const *
190SPDY_name_value_lookup (struct SPDY_NameValue *container,
191 const char *name,
192 int *num_values)
193{
194 struct SPDY_NameValue *temp = container;
195
196 if(NULL == container || NULL == name || NULL == num_values)
197 return NULL;
198 if(SPDYF_name_value_is_empty(container))
199 return NULL;
200
201 do
202 {
203 if(strcmp(name, temp->name) == 0)
204 {
205 *num_values = temp->num_values;
206 return (const char * const *)temp->value;
207 }
208
209 temp = temp->next;
210 }
211 while(NULL != temp);
212
213 return NULL;
214}
215
216
217void
218SPDY_name_value_destroy (struct SPDY_NameValue *container)
219{
220 unsigned int i;
221 struct SPDY_NameValue *temp = container;
222
223 while(NULL != temp)
224 {
225 container = container->next;
226 free(temp->name);
227 for(i=0; i<temp->num_values; ++i)
228 free(temp->value[i]);
229 free(temp->value);
230 free(temp);
231 temp=container;
232 }
233}
234
235
236int
237SPDY_name_value_iterate (struct SPDY_NameValue *container,
238 SPDY_NameValueIterator iterator,
239 void *iterator_cls)
240{
241 int count;
242 int ret;
243 struct SPDY_NameValue *temp = container;
244
245 if(NULL == container)
246 return SPDY_INPUT_ERROR;
247
248 //check if container is an empty struct
249 if(SPDYF_name_value_is_empty(container))
250 return 0;
251
252 count = 0;
253
254 if(NULL == iterator)
255 {
256 do
257 {
258 ++count;
259 temp=temp->next;
260 }
261 while(NULL != temp);
262
263 return count;
264 }
265
266 //code duplication for avoiding if here
267 do
268 {
269 ++count;
270 ret = iterator(iterator_cls, temp->name, (const char * const *)temp->value, temp->num_values);
271 temp=temp->next;
272 }
273 while(NULL != temp && SPDY_YES == ret);
274
275 return count;
276}
277
278void
279SPDY_destroy_response(struct SPDY_Response *response)
280{
281 if(NULL == response)
282 return;
283 free(response->data);
284 free(response->headers);
285 free(response);
286}
287
288
289struct SPDYF_Response_Queue *
290SPDYF_response_queue_create(bool is_data,
291 void *data,
292 size_t data_size,
293 struct SPDY_Response *response,
294 struct SPDYF_Stream *stream,
295 bool closestream,
296 SPDYF_ResponseQueueResultCallback frqcb,
297 void *frqcb_cls,
298 SPDY_ResponseResultCallback rrcb,
299 void *rrcb_cls)
300{
301 struct SPDYF_Response_Queue *head = NULL;
302 struct SPDYF_Response_Queue *prev;
303 struct SPDYF_Response_Queue *response_to_queue;
304 struct SPDYF_Control_Frame *control_frame;
305 struct SPDYF_Data_Frame *data_frame;
306 unsigned int i;
307 bool is_last;
308
309 SPDYF_ASSERT((! is_data)
310 || ((0 == data_size) && (NULL != response->rcb))
311 || ((0 < data_size) && (NULL == response->rcb)),
312 "either data or request->rcb must not be null");
313
314 if (is_data && (data_size > SPDY_MAX_SUPPORTED_FRAME_SIZE))
315 {
316 //separate the data in more frames and add them to the queue
317
318 prev=NULL;
319 for(i = 0; i < data_size; i += SPDY_MAX_SUPPORTED_FRAME_SIZE)
320 {
321 is_last = (i + SPDY_MAX_SUPPORTED_FRAME_SIZE) >= data_size;
322
323 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
324 goto free_and_fail;
325
326 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
327 if(0 == i)
328 head = response_to_queue;
329
330 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
331 {
332 free(response_to_queue);
333 goto free_and_fail;
334 }
335 memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
336 data_frame->control_bit = 0;
337 data_frame->stream_id = stream->stream_id;
338 if(is_last && closestream)
339 data_frame->flags |= SPDY_DATA_FLAG_FIN;
340
341 response_to_queue->data_frame = data_frame;
342 response_to_queue->process_response_handler = &SPDYF_handler_write_data;
343 response_to_queue->is_data = is_data;
344 response_to_queue->stream = stream;
345 if(is_last)
346 {
347 response_to_queue->frqcb = frqcb;
348 response_to_queue->frqcb_cls = frqcb_cls;
349 response_to_queue->rrcb = rrcb;
350 response_to_queue->rrcb_cls = rrcb_cls;
351 }
352 response_to_queue->data = data + i;
353 response_to_queue->data_size = is_last
354 ? (data_size - 1) % SPDY_MAX_SUPPORTED_FRAME_SIZE + 1
355 : SPDY_MAX_SUPPORTED_FRAME_SIZE;
356 response_to_queue->response = response;
357
358 response_to_queue->prev = prev;
359 if(NULL != prev)
360 prev->next = response_to_queue;
361 prev = response_to_queue;
362 }
363
364 return head;
365
366 //for GOTO
367 free_and_fail:
368 while(NULL != head)
369 {
370 response_to_queue = head;
371 head = head->next;
372 free(response_to_queue->data_frame);
373 free(response_to_queue);
374 }
375 return NULL;
376 }
377
378 //create only one frame for data, data with callback or control frame
379
380 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
381 {
382 return NULL;
383 }
384 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
385
386 if(is_data)
387 {
388 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
389 {
390 free(response_to_queue);
391 return NULL;
392 }
393 memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
394 data_frame->control_bit = 0;
395 data_frame->stream_id = stream->stream_id;
396 if(closestream && NULL == response->rcb)
397 data_frame->flags |= SPDY_DATA_FLAG_FIN;
398
399 response_to_queue->data_frame = data_frame;
400 response_to_queue->process_response_handler = &SPDYF_handler_write_data;
401 }
402 else
403 {
404 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
405 {
406 free(response_to_queue);
407 return NULL;
408 }
409 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
410 control_frame->control_bit = 1;
411 control_frame->version = SPDY_VERSION;
412 control_frame->type = SPDY_CONTROL_FRAME_TYPES_SYN_REPLY;
413 if(closestream)
414 control_frame->flags |= SPDY_SYN_REPLY_FLAG_FIN;
415
416 response_to_queue->control_frame = control_frame;
417 response_to_queue->process_response_handler = &SPDYF_handler_write_syn_reply;
418 }
419
420 response_to_queue->is_data = is_data;
421 response_to_queue->stream = stream;
422 response_to_queue->frqcb = frqcb;
423 response_to_queue->frqcb_cls = frqcb_cls;
424 response_to_queue->rrcb = rrcb;
425 response_to_queue->rrcb_cls = rrcb_cls;
426 response_to_queue->data = data;
427 response_to_queue->data_size = data_size;
428 response_to_queue->response = response;
429
430 return response_to_queue;
431}
432
433
434void
435SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue)
436{
437 //data is not copied to the struct but only linked
438 //but this is not valid for GOAWAY and RST_STREAM
439 if(!response_queue->is_data
440 && (SPDY_CONTROL_FRAME_TYPES_RST_STREAM == response_queue->control_frame->type
441 || SPDY_CONTROL_FRAME_TYPES_GOAWAY == response_queue->control_frame->type))
442 {
443 free(response_queue->data);
444 }
445 if(response_queue->is_data)
446 free(response_queue->data_frame);
447 else
448 free(response_queue->control_frame);
449
450 free(response_queue);
451}
452
453
454/* Needed by testcase to be extern -- should this be
455 in the header? */
456_MHD_EXTERN ssize_t
457SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
458 int num_containers,
459 void **stream)
460{
461 size_t size;
462 int32_t num_pairs = 0;
463 int32_t value_size;
464 int32_t name_size;
465 int32_t temp;
466 unsigned int i;
467 unsigned int offset;
468 unsigned int value_offset;
469 struct SPDY_NameValue * iterator;
470 int j;
471
472 size = 4; //for num pairs
473
474 for(j=0; j<num_containers; ++j)
475 {
476 iterator = container[j];
477 while(iterator != NULL)
478 {
479 ++num_pairs;
480 size += 4 + strlen(iterator->name); //length + string
481
482 SPDYF_ASSERT(iterator->num_values>0, "num_values is 0");
483
484 size += 4; //value length
485
486 for(i=0; i<iterator->num_values; ++i)
487 {
488 //if(NULL == iterator->value[i])
489 // continue;
490 size += strlen(iterator->value[i]); // string
491 if(i/* || !strlen(iterator->value[i])*/) ++size; //NULL separator
492 }
493
494 iterator = iterator->next;
495 }
496 }
497
498 if(NULL == (*stream = malloc(size)))
499 {
500 return -1;
501 }
502
503 //put num_pairs to the stream
504 num_pairs = htonl(num_pairs);
505 memcpy(*stream, &num_pairs, 4);
506 offset = 4;
507
508 //put all other headers to the stream
509 for(j=0; j<num_containers; ++j)
510 {
511 iterator = container[j];
512 while(iterator != NULL)
513 {
514 name_size = strlen(iterator->name);
515 temp = htonl(name_size);
516 memcpy(*stream + offset, &temp, 4);
517 offset += 4;
518 strncpy(*stream + offset, iterator->name, name_size);
519 offset += name_size;
520
521 value_offset = offset;
522 offset += 4;
523 for(i=0; i<iterator->num_values; ++i)
524 {
525 if(i /*|| !strlen(iterator->value[0])*/)
526 {
527 memset(*stream + offset, 0, 1);
528 ++offset;
529 //if(!i) continue;
530 }
531 //else if(NULL != iterator->value[i])
532 //{
533 strncpy(*stream + offset, iterator->value[i], strlen(iterator->value[i]));
534 offset += strlen(iterator->value[i]);
535 //}
536 }
537 value_size = offset - value_offset - 4;
538 value_size = htonl(value_size);
539 memcpy(*stream + value_offset, &value_size, 4);
540
541 iterator = iterator->next;
542 }
543 }
544
545 SPDYF_ASSERT(offset == size,"offset is wrong");
546
547 return size;
548}
549
550
551/* Needed by testcase to be extern -- should this be
552 in the header? */
553_MHD_EXTERN int
554SPDYF_name_value_from_stream(void *stream,
555 size_t size,
556 struct SPDY_NameValue ** container)
557{
558 int32_t num_pairs;
559 int32_t value_size;
560 int32_t name_size;
561 int i;
562 unsigned int offset = 0;
563 unsigned int value_end_offset;
564 char *name;
565 char *value;
566
567 if(NULL == (*container = SPDY_name_value_create ()))
568 {
569 return SPDY_NO;
570 }
571
572 //get number of pairs
573 memcpy(&num_pairs, stream, 4);
574 offset = 4;
575 num_pairs = ntohl(num_pairs);
576
577 if(num_pairs > 0)
578 {
579 for(i = 0; i < num_pairs; ++i)
580 {
581 //get name size
582 memcpy(&name_size, stream + offset, 4);
583 offset += 4;
584 name_size = ntohl(name_size);
585 //get name
586 if(NULL == (name = strndup(stream + offset, name_size)))
587 {
588 SPDY_name_value_destroy(*container);
589 return SPDY_NO;
590 }
591 offset+=name_size;
592
593 //get value size
594 memcpy(&value_size, stream + offset, 4);
595 offset += 4;
596 value_size = ntohl(value_size);
597 value_end_offset = offset + value_size;
598 //get value
599 do
600 {
601 if(NULL == (value = strndup(stream + offset, value_size)))
602 {
603 free(name);
604 SPDY_name_value_destroy(*container);
605 return SPDY_NO;
606 }
607 offset += strlen(value);
608 if(offset < value_end_offset)
609 ++offset; //NULL separator
610
611 //add name/value to the struct
612 if(SPDY_YES != SPDY_name_value_add(*container, name, value))
613 {
614 free(name);
615 free(value);
616 SPDY_name_value_destroy(*container);
617 return SPDY_NO;
618 }
619 free(value);
620 }
621 while(offset < value_end_offset);
622
623 free(name);
624
625 if(offset != value_end_offset)
626 {
627 SPDY_name_value_destroy(*container);
628 return SPDY_INPUT_ERROR;
629 }
630 }
631 }
632
633 if(offset == size)
634 return SPDY_YES;
635
636 SPDY_name_value_destroy(*container);
637 return SPDY_INPUT_ERROR;
638}
diff --git a/src/microspdy/structures.h b/src/microspdy/structures.h
deleted file mode 100644
index e1f8797a..00000000
--- a/src/microspdy/structures.h
+++ /dev/null
@@ -1,1246 +0,0 @@
1/*
2 This file is part of libmicrospdy
3 Copyright Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file structures.h
21 * @brief internal and public structures -- most of the structs used by
22 * the library are defined here
23 * @author Andrey Uzunov
24 */
25
26#ifndef STRUCTURES_H
27#define STRUCTURES_H
28
29#include "platform.h"
30#include "microspdy.h"
31#include "io.h"
32
33
34/**
35 * All possible SPDY control frame types. The number is used in the header
36 * of the control frame.
37 */
38enum SPDY_CONTROL_FRAME_TYPES
39{
40 /**
41 * The SYN_STREAM control frame allows the sender to asynchronously
42 * create a stream between the endpoints.
43 */
44 SPDY_CONTROL_FRAME_TYPES_SYN_STREAM = 1,
45
46 /**
47 * SYN_REPLY indicates the acceptance of a stream creation by
48 * the recipient of a SYN_STREAM frame.
49 */
50 SPDY_CONTROL_FRAME_TYPES_SYN_REPLY = 2,
51
52 /**
53 * The RST_STREAM frame allows for abnormal termination of a stream.
54 * When sent by the creator of a stream, it indicates the creator
55 * wishes to cancel the stream. When sent by the recipient of a
56 * stream, it indicates an error or that the recipient did not want
57 * to accept the stream, so the stream should be closed.
58 */
59 SPDY_CONTROL_FRAME_TYPES_RST_STREAM = 3,
60
61 /**
62 * A SETTINGS frame contains a set of id/value pairs for
63 * communicating configuration data about how the two endpoints may
64 * communicate. SETTINGS frames can be sent at any time by either
65 * endpoint, are optionally sent, and are fully asynchronous. When
66 * the server is the sender, the sender can request that
67 * configuration data be persisted by the client across SPDY
68 * sessions and returned to the server in future communications.
69 */
70 SPDY_CONTROL_FRAME_TYPES_SETTINGS = 4,
71
72 /**
73 * The PING control frame is a mechanism for measuring a minimal
74 * round-trip time from the sender. It can be sent from the client
75 * or the server. Recipients of a PING frame should send an
76 * identical frame to the sender as soon as possible (if there is
77 * other pending data waiting to be sent, PING should take highest
78 * priority). Each ping sent by a sender should use a unique ID.
79 */
80 SPDY_CONTROL_FRAME_TYPES_PING = 6,
81
82 /**
83 * The GOAWAY control frame is a mechanism to tell the remote side
84 * of the connection to stop creating streams on this session. It
85 * can be sent from the client or the server.
86 */
87 SPDY_CONTROL_FRAME_TYPES_GOAWAY = 7,
88
89 /**
90 * The HEADERS frame augments a stream with additional headers. It
91 * may be optionally sent on an existing stream at any time.
92 * Specific application of the headers in this frame is
93 * application-dependent. The name/value header block within this
94 * frame is compressed.
95 */
96 SPDY_CONTROL_FRAME_TYPES_HEADERS = 8,
97
98 /**
99 * The WINDOW_UPDATE control frame is used to implement per stream
100 * flow control in SPDY. Flow control in SPDY is per hop, that is,
101 * only between the two endpoints of a SPDY connection. If there are
102 * one or more intermediaries between the client and the origin
103 * server, flow control signals are not explicitly forwarded by the
104 * intermediaries.
105 */
106 SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE = 9,
107
108 /**
109 * The CREDENTIAL control frame is used by the client to send
110 * additional client certificates to the server. A SPDY client may
111 * decide to send requests for resources from different origins on
112 * the same SPDY session if it decides that that server handles both
113 * origins. For example if the IP address associated with both
114 * hostnames matches and the SSL server certificate presented in the
115 * initial handshake is valid for both hostnames. However, because
116 * the SSL connection can contain at most one client certificate,
117 * the client needs a mechanism to send additional client
118 * certificates to the server.
119 */
120 SPDY_CONTROL_FRAME_TYPES_CREDENTIAL = 11
121};
122
123
124/**
125 * SPDY_SESSION_STATUS is used to show the current receiving state
126 * of each session, i.e. what is expected to come now, and how it should
127 * be handled.
128 */
129enum SPDY_SESSION_STATUS
130{
131 /**
132 * The session is in closing state, do not read read anything from
133 * it. Do not write anything to it.
134 */
135 SPDY_SESSION_STATUS_CLOSING = 0,
136
137 /**
138 * Wait for new SPDY frame to come.
139 */
140 SPDY_SESSION_STATUS_WAIT_FOR_HEADER = 1,
141
142 /**
143 * The standard 8 byte header of the SPDY frame was received and
144 * handled. Wait for the specific (sub)headers according to the
145 * frame type.
146 */
147 SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER = 2,
148
149 /**
150 * The specific (sub)headers were received and handled. Wait for the
151 * "body", i.e. wait for the name/value pairs compressed by zlib.
152 */
153 SPDY_SESSION_STATUS_WAIT_FOR_BODY = 3,
154
155 /**
156 * Ignore all the bytes read from the socket, e.g. larger frames.
157 */
158 SPDY_SESSION_STATUS_IGNORE_BYTES= 4,
159
160 /**
161 * The session is in pre-closing state, do not read read anything
162 * from it. In this state the output queue will be written to the
163 * socket.
164 */
165 SPDY_SESSION_STATUS_FLUSHING = 5,
166};
167
168
169/**
170 * Specific flags for the SYN_STREAM control frame.
171 */
172enum SPDY_SYN_STREAM_FLAG
173{
174 /**
175 * The sender won't send any more frames on this stream.
176 */
177 SPDY_SYN_STREAM_FLAG_FIN = 1,
178
179 /**
180 * The sender creates this stream as unidirectional.
181 */
182 SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL = 2
183};
184
185
186/**
187 * Specific flags for the SYN_REPLY control frame.
188 */
189enum SPDY_SYN_REPLY_FLAG
190{
191 /**
192 * The sender won't send any more frames on this stream.
193 */
194 SPDY_SYN_REPLY_FLAG_FIN = 1
195};
196
197
198/**
199 * Specific flags for the data frame.
200 */
201enum SPDY_DATA_FLAG
202{
203 /**
204 * The sender won't send any more frames on this stream.
205 */
206 SPDY_DATA_FLAG_FIN = 1,
207
208 /**
209 * The data in the frame is compressed.
210 * This flag appears only in the draft on ietf.org but not on
211 * chromium.org.
212 */
213 SPDY_DATA_FLAG_COMPRESS = 2
214};
215
216/**
217 * Status code within RST_STREAM control frame.
218 */
219enum SPDY_RST_STREAM_STATUS
220{
221 /**
222 * This is a generic error, and should only be used if a more
223 * specific error is not available.
224 */
225 SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR = 1,
226
227 /**
228 * This is returned when a frame is received for a stream which is
229 * not active.
230 */
231 SPDY_RST_STREAM_STATUS_INVALID_STREAM = 2,
232
233 /**
234 * Indicates that the stream was refused before any processing has
235 * been done on the stream.
236 */
237 SPDY_RST_STREAM_STATUS_REFUSED_STREAM = 3,
238
239 /**
240 * Indicates that the recipient of a stream does not support the
241 * SPDY version requested.
242 */
243 SPDY_RST_STREAM_STATUS_UNSUPPORTED_VERSION = 4,
244
245 /**
246 * Used by the creator of a stream to indicate that the stream is
247 * no longer needed.
248 */
249 SPDY_RST_STREAM_STATUS_CANCEL = 5,
250
251 /**
252 * This is a generic error which can be used when the implementation
253 * has internally failed, not due to anything in the protocol.
254 */
255 SPDY_RST_STREAM_STATUS_INTERNAL_ERROR = 6,
256
257 /**
258 * The endpoint detected that its peer violated the flow control
259 * protocol.
260 */
261 SPDY_RST_STREAM_STATUS_FLOW_CONTROL_ERROR = 7,
262
263 /**
264 * The endpoint received a SYN_REPLY for a stream already open.
265 */
266 SPDY_RST_STREAM_STATUS_STREAM_IN_USE = 8,
267
268 /**
269 * The endpoint received a data or SYN_REPLY frame for a stream
270 * which is half closed.
271 */
272 SPDY_RST_STREAM_STATUS_STREAM_ALREADY_CLOSED = 9,
273
274 /**
275 * The server received a request for a resource whose origin does
276 * not have valid credentials in the client certificate vector.
277 */
278 SPDY_RST_STREAM_STATUS_INVALID_CREDENTIALS = 10,
279
280 /**
281 * The endpoint received a frame which this implementation could not
282 * support. If FRAME_TOO_LARGE is sent for a SYN_STREAM, HEADERS,
283 * or SYN_REPLY frame without fully processing the compressed
284 * portion of those frames, then the compression state will be
285 * out-of-sync with the other endpoint. In this case, senders of
286 * FRAME_TOO_LARGE MUST close the session.
287 */
288 SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE = 11
289};
290
291
292/**
293 * Status code within GOAWAY control frame.
294 */
295enum SPDY_GOAWAY_STATUS
296{
297 /**
298 * This is a normal session teardown.
299 */
300 SPDY_GOAWAY_STATUS_OK = 0,
301
302 /**
303 * This is a generic error, and should only be used if a more
304 * specific error is not available.
305 */
306 SPDY_GOAWAY_STATUS_PROTOCOL_ERROR = 1,
307
308 /**
309 * This is a generic error which can be used when the implementation
310 * has internally failed, not due to anything in the protocol.
311 */
312 SPDY_GOAWAY_STATUS_INTERNAL_ERROR = 11
313};
314
315
316struct SPDYF_Stream;
317
318struct SPDYF_Response_Queue;
319
320
321/**
322 * Callback for received new data chunk.
323 *
324 * @param cls client-defined closure
325 * @param stream handler
326 * @param buf data chunk from the data
327 * @param size the size of the data chunk 'buf' in bytes
328 * @param more false if this is the last frame received on this stream. Note:
329 * true does not mean that more data will come, exceptional
330 * situation is possible
331 * @return SPDY_YES to continue calling the function,
332 * SPDY_NO to stop calling the function for this stream
333 */
334typedef int
335(*SPDYF_NewDataCallback) (void * cls,
336 struct SPDYF_Stream *stream,
337 const void * buf,
338 size_t size,
339 bool more);
340
341
342/**
343 * Callback for new stream. To be used in the application layer of the
344 * lib.
345 *
346 * @param cls
347 * @param stream the new stream
348 * @return SPDY_YES on success,
349 * SPDY_NO if error occurs
350 */
351typedef int
352(*SPDYF_NewStreamCallback) (void *cls,
353 struct SPDYF_Stream * stream);
354
355
356/**
357 * Callback to be called when the response queue object was handled and
358 * the data was already sent.
359 *
360 * @param cls
361 * @param response_queue the SPDYF_Response_Queue structure which will
362 * be cleaned very soon
363 * @param status shows if actually the response was sent or it was
364 * discarded by the lib for any reason (e.g., closing session,
365 * closing stream, stopping daemon, etc.). It is possible that
366 * status indicates an error but part of the response (in one
367 * or several frames) was sent to the client.
368 */
369typedef void
370(*SPDYF_ResponseQueueResultCallback) (void * cls,
371 struct SPDYF_Response_Queue *response_queue,
372 enum SPDY_RESPONSE_RESULT status);
373
374
375/**
376 * Representation of the control frame's headers, which are common for
377 * all types.
378 */
379struct __attribute__((__packed__)) SPDYF_Control_Frame
380{
381 uint16_t version : 15;
382 uint16_t control_bit : 1; /* always 1 for control frames */
383 uint16_t type;
384 uint32_t flags : 8;
385 uint32_t length : 24;
386};
387
388
389/**
390 * Representation of the data frame's headers.
391 */
392struct __attribute__((__packed__)) SPDYF_Data_Frame
393{
394 uint32_t stream_id : 31;
395 uint32_t control_bit : 1; /* always 0 for data frames */
396 uint32_t flags : 8;
397 uint32_t length : 24;
398};
399
400
401/**
402 * Queue of the responses, to be handled (e.g. compressed) and sent later.
403 */
404struct SPDYF_Response_Queue
405{
406 /**
407 * This is a doubly-linked list.
408 */
409 struct SPDYF_Response_Queue *next;
410
411 /**
412 * This is a doubly-linked list.
413 */
414 struct SPDYF_Response_Queue *prev;
415
416 /**
417 * Stream (Request) for which is the response.
418 */
419 struct SPDYF_Stream *stream;
420
421 /**
422 * Response structure with all the data (uncompressed headers) to be sent.
423 */
424 struct SPDY_Response *response;
425
426 /**
427 * Control frame. The length field should be set after compressing
428 * the headers!
429 */
430 struct SPDYF_Control_Frame *control_frame;
431
432 /**
433 * Data frame. The length field should be set after compressing
434 * the body!
435 */
436 struct SPDYF_Data_Frame *data_frame;
437
438 /**
439 * Data to be sent: name/value pairs in control frames or body in data frames.
440 */
441 void *data;
442
443 /**
444 * Specific handler for different frame types.
445 */
446 int (* process_response_handler)(struct SPDY_Session *session);
447
448 /**
449 * Callback to be called when the last bytes from the response was sent
450 * to the client.
451 */
452 SPDYF_ResponseQueueResultCallback frqcb;
453
454 /**
455 * Closure for frqcb.
456 */
457 void *frqcb_cls;
458
459 /**
460 * Callback to be used by the application layer.
461 */
462 SPDY_ResponseResultCallback rrcb;
463
464 /**
465 * Closure for rcb.
466 */
467 void *rrcb_cls;
468
469 /**
470 * Data size.
471 */
472 size_t data_size;
473
474 /**
475 * True if data frame should be sent. False if control frame should
476 * be sent.
477 */
478 bool is_data;
479};
480
481
482
483/**
484 * Collection of HTTP headers used in requests and responses.
485 */
486struct SPDY_NameValue
487{
488 /**
489 * This is a doubly-linked list.
490 */
491 struct SPDY_NameValue *next;
492
493 /**
494 * This is a doubly-linked list.
495 */
496 struct SPDY_NameValue *prev;
497
498 /**
499 * Null terminated string for name.
500 */
501 char *name;
502
503 /**
504 * Array of Null terminated strings for value. num_values is the
505 * length of the array.
506 */
507 char **value;
508
509 /**
510 * Number of values, this is >= 0.
511 */
512 unsigned int num_values;
513};
514
515
516/**
517 * Represents a SPDY stream
518 */
519struct SPDYF_Stream
520{
521 /**
522 * This is a doubly-linked list.
523 */
524 struct SPDYF_Stream *next;
525
526 /**
527 * This is a doubly-linked list.
528 */
529 struct SPDYF_Stream *prev;
530
531 /**
532 * Reference to the SPDY_Session struct.
533 */
534 struct SPDY_Session *session;
535
536 /**
537 * Name value pairs, sent within the frame which created the stream.
538 */
539 struct SPDY_NameValue *headers;
540
541 /**
542 * Any object to be used by the application layer.
543 */
544 void *cls;
545
546 /**
547 * This stream's ID.
548 */
549 uint32_t stream_id;
550
551 /**
552 * Stream to which this one is associated.
553 */
554 uint32_t assoc_stream_id;
555
556 /**
557 * The window of the data within data frames.
558 */
559 uint32_t window_size;
560
561 /**
562 * Stream priority. 0 is the highest, 7 is the lowest.
563 */
564 uint8_t priority;
565
566 /**
567 * Integer specifying the index in the server's CREDENTIAL vector of
568 * the client certificate to be used for this request The value 0
569 * means no client certificate should be associated with this stream.
570 */
571 uint8_t slot;
572
573 /**
574 * If initially the stream was created as unidirectional.
575 */
576 bool flag_unidirectional;
577
578 /**
579 * If the stream won't be used for receiving frames anymore. The
580 * client has sent FLAG_FIN or the stream was terminated with
581 * RST_STREAM.
582 */
583 bool is_in_closed;
584
585 /**
586 * If the stream won't be used for sending out frames anymore. The
587 * server has sent FLAG_FIN or the stream was terminated with
588 * RST_STREAM.
589 */
590 bool is_out_closed;
591
592 /**
593 * Which entity (server/client) has created the stream.
594 */
595 bool is_server_initiator;
596};
597
598
599/**
600 * Represents a SPDY session which is just a TCP connection
601 */
602struct SPDY_Session
603{
604 /**
605 * zlib stream for decompressing all the name/pair values from the
606 * received frames. All the received compressed data must be
607 * decompressed within one context: this stream. Thus, it should be
608 * unique for the session and initialized at its creation.
609 */
610 z_stream zlib_recv_stream;
611
612 /**
613 * zlib stream for compressing all the name/pair values from the
614 * frames to be sent. All the sent compressed data must be
615 * compressed within one context: this stream. Thus, it should be
616 * unique for the session and initialized at its creation.
617 */
618 z_stream zlib_send_stream;
619
620 /**
621 * This is a doubly-linked list.
622 */
623 struct SPDY_Session *next;
624
625 /**
626 * This is a doubly-linked list.
627 */
628 struct SPDY_Session *prev;
629
630 /**
631 * Reference to the SPDY_Daemon struct.
632 */
633 struct SPDY_Daemon *daemon;
634
635 /**
636 * Foreign address (of length addr_len).
637 */
638 struct sockaddr *addr;
639
640 /**
641 * Head of doubly-linked list of the SPDY streams belonging to the
642 * session.
643 */
644 struct SPDYF_Stream *streams_head;
645
646 /**
647 * Tail of doubly-linked list of the streams.
648 */
649 struct SPDYF_Stream *streams_tail;
650
651 /**
652 * Unique IO context for the session. Initialized on each creation
653 * (actually when the TCP connection is established).
654 */
655 void *io_context;
656
657 /**
658 * Head of doubly-linked list of the responses.
659 */
660 struct SPDYF_Response_Queue *response_queue_head;
661
662 /**
663 * Tail of doubly-linked list of the responses.
664 */
665 struct SPDYF_Response_Queue *response_queue_tail;
666
667 /**
668 * Buffer for reading requests.
669 */
670 void *read_buffer;
671
672 /**
673 * Buffer for writing responses.
674 */
675 void *write_buffer;
676
677 /**
678 * Specific handler for the frame that is currently being received.
679 */
680 void (*frame_handler) (struct SPDY_Session * session);
681
682 /**
683 * Closure for frame_handler.
684 */
685 void *frame_handler_cls;
686
687 /**
688 * Extra field to be used by the user with set/get func for whatever
689 * purpose he wants.
690 */
691 void *user_cls;
692
693 /**
694 * Function to initialize the IO context for a new session.
695 */
696 SPDYF_IONewSession fio_new_session;
697
698 /**
699 * Function to deinitialize the IO context for a session.
700 */
701 SPDYF_IOCloseSession fio_close_session;
702
703 /**
704 * Function to read data from socket.
705 */
706 SPDYF_IORecv fio_recv;
707
708 /**
709 * Function to write data to socket.
710 */
711 SPDYF_IOSend fio_send;
712
713 /**
714 * Function to check for pending data in IO buffers.
715 */
716 SPDYF_IOIsPending fio_is_pending;
717
718 /**
719 * Function to call before writing set of frames.
720 */
721 SPDYF_IOBeforeWrite fio_before_write;
722
723 /**
724 * Function to call after writing set of frames.
725 */
726 SPDYF_IOAfterWrite fio_after_write;
727
728 /**
729 * Number of bytes that the lib must ignore immediately after they
730 * are read from the TLS socket without adding them to the read buf.
731 * This is needed, for instance, when receiving frame bigger than
732 * the buffer to avoid deadlock situations.
733 */
734 size_t read_ignore_bytes;
735
736 /**
737 * Size of read_buffer (in bytes). This value indicates
738 * how many bytes we're willing to read into the buffer;
739 * the real buffer is one byte longer to allow for
740 * adding zero-termination (when needed).
741 */
742 size_t read_buffer_size;
743
744 /**
745 * Position where we currently append data in
746 * read_buffer (last valid position).
747 */
748 size_t read_buffer_offset;
749
750 /**
751 * Position until where everything was already read
752 */
753 size_t read_buffer_beginning;
754
755 /**
756 * Size of write_buffer (in bytes). This value indicates
757 * how many bytes we're willing to prepare for writing.
758 */
759 size_t write_buffer_size;
760
761 /**
762 * Position where we currently append data in
763 * write_buffer (last valid position).
764 */
765 size_t write_buffer_offset;
766
767 /**
768 * Position until where everything was already written to the socket
769 */
770 size_t write_buffer_beginning;
771
772 /**
773 * Last time this connection had any activity
774 * (reading or writing). In milliseconds.
775 */
776 unsigned long long last_activity;
777
778 /**
779 * Socket for this connection. Set to -1 if
780 * this connection has died (daemon should clean
781 * up in that case).
782 */
783 int socket_fd;
784
785 /**
786 * Length of the foreign address.
787 */
788 socklen_t addr_len;
789
790 /**
791 * The biggest stream ID for this session for streams initiated
792 * by the client.
793 */
794 uint32_t last_in_stream_id;
795
796 /**
797 * The biggest stream ID for this session for streams initiated
798 * by the server.
799 */
800 uint32_t last_out_stream_id;
801
802 /**
803 * This value is updated whenever SYN_REPLY or RST_STREAM are sent
804 * and is used later in GOAWAY frame.
805 * TODO it is not clear in the draft what happens when streams are
806 * not answered in the order of their IDs. Moreover, why should we
807 * send GOAWAY with the ID of received bogus SYN_STREAM with huge ID?
808 */
809 uint32_t last_replied_to_stream_id;
810
811 /**
812 * Shows the stream id of the currently handled frame. This value is
813 * to be used when sending RST_STREAM in answer to a problematic
814 * frame, e.g. larger than supported.
815 */
816 uint32_t current_stream_id;
817
818 /**
819 * Maximum number of frames to be written to the socket at once. The
820 * library tries to send max_num_frames in a single call to SPDY_run
821 * for a single session. This means no requests can be received nor
822 * other sessions can send data as long the current one has enough
823 * frames to send and there is no error on writing.
824 */
825 uint32_t max_num_frames;
826
827 /**
828 * Shows the current receiving state the session, i.e. what is
829 * expected to come now, and how it shold be handled.
830 */
831 enum SPDY_SESSION_STATUS status;
832
833 /**
834 * Has this socket been closed for reading (i.e.
835 * other side closed the connection)? If so,
836 * we must completely close the connection once
837 * we are done sending our response (and stop
838 * trying to read from this socket).
839 */
840 bool read_closed;
841
842 /**
843 * If the server sends GOAWAY, it must ignore all SYN_STREAMS for
844 * this session. Normally the server will soon close the TCP session.
845 */
846 bool is_goaway_sent;
847
848 /**
849 * If the server receives GOAWAY, it must not send new SYN_STREAMS
850 * on this session. Normally the client will soon close the TCP
851 * session.
852 */
853 bool is_goaway_received;
854};
855
856
857/**
858 * State and settings kept for each SPDY daemon.
859 */
860struct SPDY_Daemon
861{
862
863 /**
864 * Tail of doubly-linked list of our current, active sessions.
865 */
866 struct SPDY_Session *sessions_head;
867
868 /**
869 * Tail of doubly-linked list of our current, active sessions.
870 */
871 struct SPDY_Session *sessions_tail;
872
873 /**
874 * Tail of doubly-linked list of connections to clean up.
875 */
876 struct SPDY_Session *cleanup_head;
877
878 /**
879 * Tail of doubly-linked list of connections to clean up.
880 */
881 struct SPDY_Session *cleanup_tail;
882
883 /**
884 * Unique IO context for the daemon. Initialized on daemon start.
885 */
886 void *io_context;
887
888 /**
889 * Certificate file of the server. File path is kept here.
890 */
891 char *certfile;
892
893 /**
894 * Key file for the certificate of the server. File path is
895 * kept here.
896 */
897 char *keyfile;
898
899
900 /**
901 * The address to which the listening socket is bound.
902 */
903 struct sockaddr *address;
904
905 /**
906 * Callback called when a new SPDY session is
907 * established by a client
908 */
909 SPDY_NewSessionCallback new_session_cb;
910
911 /**
912 * Callback called when a client closes the session
913 */
914 SPDY_SessionClosedCallback session_closed_cb;
915
916 /**
917 * Callback called when a client sends request
918 */
919 SPDY_NewRequestCallback new_request_cb;
920
921 /**
922 * Callback called when HTTP POST params are received
923 * after request. To be used by the application layer
924 */
925 SPDY_NewDataCallback received_data_cb;
926
927 /**
928 * Callback called when DATA frame is received.
929 */
930 SPDYF_NewDataCallback freceived_data_cb;
931
932 /**
933 * Closure argument for all the callbacks that can be used by the client.
934 */
935 void *cls;
936
937 /**
938 * Callback called when new stream is created.
939 */
940 SPDYF_NewStreamCallback fnew_stream_cb;
941
942 /**
943 * Closure argument for all the callbacks defined in the framing layer.
944 */
945 void *fcls;
946
947 /**
948 * Function to initialize the IO context for the daemon.
949 */
950 SPDYF_IOInit fio_init;
951
952 /**
953 * Function to deinitialize the IO context for the daemon.
954 */
955 SPDYF_IODeinit fio_deinit;
956
957 /**
958 * After how many milliseconds of inactivity should
959 * connections time out? Zero for no timeout.
960 */
961 unsigned long long session_timeout;
962
963 /**
964 * Listen socket.
965 */
966 int socket_fd;
967
968 /**
969 * This value is inherited by all sessions of the daemon.
970 * Maximum number of frames to be written to the socket at once. The
971 * library tries to send max_num_frames in a single call to SPDY_run
972 * for a single session. This means no requests can be received nor
973 * other sessions can send data as long the current one has enough
974 * frames to send and there is no error on writing.
975 */
976 uint32_t max_num_frames;
977
978 /**
979 * Daemon's options.
980 */
981 enum SPDY_DAEMON_OPTION options;
982
983 /**
984 * Daemon's flags.
985 */
986 enum SPDY_DAEMON_FLAG flags;
987
988 /**
989 * IO subsystem type used by daemon and all its sessions.
990 */
991 enum SPDY_IO_SUBSYSTEM io_subsystem;
992
993 /**
994 * Listen port.
995 */
996 uint16_t port;
997};
998
999
1000/**
1001 * Represents a SPDY response.
1002 */
1003struct SPDY_Response
1004{
1005 /**
1006 * Raw uncompressed stream of the name/value pairs in SPDY frame
1007 * used for the HTTP headers.
1008 */
1009 void *headers;
1010
1011 /**
1012 * Raw stream of the data to be sent. Equivalent to the body in HTTP
1013 * response.
1014 */
1015 void *data;
1016
1017 /**
1018 * Callback function to be used when the response data is provided
1019 * with callbacks. In this case data must be NULL and data_size must
1020 * be 0.
1021 */
1022 SPDY_ResponseCallback rcb;
1023
1024 /**
1025 * Extra argument to rcb.
1026 */
1027 void *rcb_cls;
1028
1029 /**
1030 * Length of headers.
1031 */
1032 size_t headers_size;
1033
1034 /**
1035 * Length of data.
1036 */
1037 size_t data_size;
1038
1039 /**
1040 * The callback func will be called to get that amount of bytes to
1041 * put them into a DATA frame. It is either user preffered or
1042 * the maximum supported by the lib value.
1043 */
1044 uint32_t rcb_block_size;
1045};
1046
1047
1048/* Macros for handling data and structures */
1049
1050
1051/**
1052 * Insert an element at the head of a DLL. Assumes that head, tail and
1053 * element are structs with prev and next fields.
1054 *
1055 * @param head pointer to the head of the DLL (struct ? *)
1056 * @param tail pointer to the tail of the DLL (struct ? *)
1057 * @param element element to insert (struct ? *)
1058 */
1059#define DLL_insert(head,tail,element) do { \
1060 (element)->next = (head); \
1061 (element)->prev = NULL; \
1062 if ((tail) == NULL) \
1063 (tail) = element; \
1064 else \
1065 (head)->prev = element; \
1066 (head) = (element); } while (0)
1067
1068
1069/**
1070 * Remove an element from a DLL. Assumes
1071 * that head, tail and element are structs
1072 * with prev and next fields.
1073 *
1074 * @param head pointer to the head of the DLL (struct ? *)
1075 * @param tail pointer to the tail of the DLL (struct ? *)
1076 * @param element element to remove (struct ? *)
1077 */
1078#define DLL_remove(head,tail,element) do { \
1079 if ((element)->prev == NULL) \
1080 (head) = (element)->next; \
1081 else \
1082 (element)->prev->next = (element)->next; \
1083 if ((element)->next == NULL) \
1084 (tail) = (element)->prev; \
1085 else \
1086 (element)->next->prev = (element)->prev; \
1087 (element)->next = NULL; \
1088 (element)->prev = NULL; } while (0)
1089
1090
1091/**
1092 * Convert all integers in a SPDY control frame headers structure from
1093 * host byte order to network byte order.
1094 *
1095 * @param frame input and output structure (struct SPDY_Control_Frame *)
1096 */
1097#if HAVE_BIG_ENDIAN
1098#define SPDYF_CONTROL_FRAME_HTON(frame)
1099#else
1100#define SPDYF_CONTROL_FRAME_HTON(frame) do { \
1101 (*((uint16_t *) frame )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t *) frame ))<<8);\
1102 (frame)->type = htons((frame)->type); \
1103 (frame)->length = HTON24((frame)->length); \
1104 } while (0)
1105#endif
1106
1107
1108/**
1109 * Convert all integers in a SPDY control frame headers structure from
1110 * network byte order to host byte order.
1111 *
1112 * @param frame input and output structure (struct SPDY_Control_Frame *)
1113 */
1114#if HAVE_BIG_ENDIAN
1115#define SPDYF_CONTROL_FRAME_NTOH(frame)
1116#else
1117#define SPDYF_CONTROL_FRAME_NTOH(frame) do { \
1118 (*((uint16_t *) frame )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t *) frame ))<<8);\
1119 (frame)->type = ntohs((frame)->type); \
1120 (frame)->length = NTOH24((frame)->length); \
1121 } while (0)
1122#endif
1123
1124
1125/**
1126 * Convert all integers in a SPDY data frame headers structure from
1127 * host byte order to network byte order.
1128 *
1129 * @param frame input and output structure (struct SPDY_Data_Frame *)
1130 */
1131#if HAVE_BIG_ENDIAN
1132#define SPDYF_DATA_FRAME_HTON(frame)
1133#else
1134#define SPDYF_DATA_FRAME_HTON(frame) do { \
1135 *((uint32_t *) frame ) = htonl(*((uint32_t *) frame ));\
1136 (frame)->length = HTON24((frame)->length); \
1137 } while (0)
1138#endif
1139
1140
1141/**
1142 * Convert all integers in a SPDY data frame headers structure from
1143 * network byte order to host byte order.
1144 *
1145 * @param frame input and output structure (struct SPDY_Data_Frame *)
1146 */
1147#if HAVE_BIG_ENDIAN
1148#define SPDYF_DATA_FRAME_NTOH(frame)
1149#else
1150#define SPDYF_DATA_FRAME_NTOH(frame) do { \
1151 *((uint32_t *) frame ) = ntohl(*((uint32_t *) frame ));\
1152 (frame)->length = NTOH24((frame)->length); \
1153 } while (0)
1154#endif
1155
1156
1157/**
1158 * Creates one or more new SPDYF_Response_Queue object to be put on the
1159 * response queue.
1160 *
1161 * @param is_data whether new data frame or new control frame will be
1162 * crerated
1163 * @param data the row stream which will be used as the body of the frame
1164 * @param data_size length of data
1165 * @param response object, part of which is the frame
1166 * @param stream on which data is to be sent
1167 * @param closestream TRUE if the frame must close the stream (with flag)
1168 * @param frqcb callback to notify application layer when the frame
1169 * has been sent or discarded
1170 * @param frqcb_cls closure for frqcb
1171 * @param rrcb callback used by the application layer to notify the
1172 * application when the frame has been sent or discarded.
1173 * frqcb will call it
1174 * @param rrcb_cls closure for rrcb
1175 * @return double linked list of SPDYF_Response_Queue structures: one or
1176 * more frames are returned based on the size of the data
1177 */
1178struct SPDYF_Response_Queue *
1179SPDYF_response_queue_create(bool is_data,
1180 void *data,
1181 size_t data_size,
1182 struct SPDY_Response *response,
1183 struct SPDYF_Stream *stream,
1184 bool closestream,
1185 SPDYF_ResponseQueueResultCallback frqcb,
1186 void *frqcb_cls,
1187 SPDY_ResponseResultCallback rrcb,
1188 void *rrcb_cls);
1189
1190
1191/**
1192 * Destroys SPDYF_Response_Queue structure and whatever is in it.
1193 *
1194 * @param response_queue to destroy
1195 */
1196void
1197SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue);
1198
1199
1200/**
1201 * Checks if the container is empty, i.e. created but no values were
1202 * added to it.
1203 *
1204 * @param container
1205 * @return SPDY_YES if empty
1206 * SPDY_NO if not
1207 */
1208int
1209SPDYF_name_value_is_empty(struct SPDY_NameValue *container);
1210
1211
1212/**
1213 * Transforms raw binary decomressed stream of headers
1214 * into SPDY_NameValue, containing all of the headers and values.
1215 *
1216 * @param stream that is to be transformed
1217 * @param size length of the stream
1218 * @param container will contain the newly created SPDY_NameValue
1219 * container. Should point to NULL.
1220 * @return SPDY_YES on success
1221 * SPDY_NO on memory error
1222 * SPDY_INPUT_ERROR if the provided stream is not valid
1223 */
1224int
1225SPDYF_name_value_from_stream(void *stream,
1226 size_t size,
1227 struct SPDY_NameValue ** container);
1228
1229
1230/**
1231 * Transforms array of objects of name/values tuples, containing HTTP
1232 * headers, into raw binary stream. The resulting stream is ready to
1233 * be compressed and sent.
1234 *
1235 * @param container one or more SPDY_NameValue objects. Each object
1236 * contains multiple number of name/value tuples.
1237 * @param num_containers length of the array
1238 * @param stream will contain the resulting stream. Should point to NULL.
1239 * @return length of stream or value less than 0 indicating error
1240 */
1241ssize_t
1242SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
1243 int num_containers,
1244 void **stream);
1245
1246#endif