diff options
Diffstat (limited to 'src/microspdy')
-rw-r--r-- | src/microspdy/Makefile.am | 40 | ||||
-rw-r--r-- | src/microspdy/alstructures.c | 41 | ||||
-rw-r--r-- | src/microspdy/alstructures.h | 79 | ||||
-rw-r--r-- | src/microspdy/applicationlayer.c | 748 | ||||
-rw-r--r-- | src/microspdy/applicationlayer.h | 31 | ||||
-rw-r--r-- | src/microspdy/compression.c | 441 | ||||
-rw-r--r-- | src/microspdy/compression.h | 117 | ||||
-rw-r--r-- | src/microspdy/daemon.c | 544 | ||||
-rw-r--r-- | src/microspdy/daemon.h | 130 | ||||
-rw-r--r-- | src/microspdy/internal.c | 40 | ||||
-rw-r--r-- | src/microspdy/internal.h | 199 | ||||
-rw-r--r-- | src/microspdy/io.c | 90 | ||||
-rw-r--r-- | src/microspdy/io.h | 216 | ||||
-rw-r--r-- | src/microspdy/io_openssl.c | 280 | ||||
-rw-r--r-- | src/microspdy/io_openssl.h | 166 | ||||
-rw-r--r-- | src/microspdy/io_raw.c | 194 | ||||
-rw-r--r-- | src/microspdy/io_raw.h | 158 | ||||
-rw-r--r-- | src/microspdy/session.c | 1769 | ||||
-rw-r--r-- | src/microspdy/session.h | 281 | ||||
-rw-r--r-- | src/microspdy/stream.c | 169 | ||||
-rw-r--r-- | src/microspdy/stream.h | 76 | ||||
-rw-r--r-- | src/microspdy/structures.c | 638 | ||||
-rw-r--r-- | src/microspdy/structures.h | 1246 |
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 | ||
2 | AM_CPPFLAGS = \ | ||
3 | -I$(top_srcdir)/src/include \ | ||
4 | -I$(top_srcdir)/src/microspdy | ||
5 | |||
6 | AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS) | ||
7 | |||
8 | |||
9 | lib_LTLIBRARIES = \ | ||
10 | libmicrospdy.la | ||
11 | |||
12 | libmicrospdy_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 | ||
24 | libmicrospdy_la_LIBADD = \ | ||
25 | $(SPDY_LIBDEPS) | ||
26 | |||
27 | libmicrospdy_la_LDFLAGS = \ | ||
28 | $(SPDY_LIB_LDFLAGS) | ||
29 | |||
30 | libmicrospdy_la_CPPFLAGS = \ | ||
31 | $(AM_CPPFLAGS) $(SPDY_LIB_CPPFLAGS) \ | ||
32 | -DBUILDING_MHD_LIB=1 | ||
33 | |||
34 | libmicrospdy_la_CFLAGS = -Wextra \ | ||
35 | $(AM_CFLAGS) $(SPDY_LIB_CFLAGS) | ||
36 | |||
37 | |||
38 | if USE_COVERAGE | ||
39 | AM_CFLAGS += --coverage | ||
40 | endif | ||
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 | |||
29 | void | ||
30 | SPDY_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 | */ | ||
34 | struct 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 | |||
34 | void | ||
35 | spdy_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 | */ | ||
58 | static int | ||
59 | spdy_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 | */ | ||
186 | static int | ||
187 | spdy_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 | */ | ||
211 | static void | ||
212 | spdy_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 | |||
231 | int | ||
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 | |||
259 | void | ||
260 | SPDY_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 | |||
274 | void | ||
275 | SPDY_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 | |||
287 | int | ||
288 | SPDY_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 | |||
301 | int | ||
302 | SPDY_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 | |||
324 | struct SPDY_Daemon * | ||
325 | SPDY_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 | |||
377 | void | ||
378 | SPDY_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 | |||
390 | struct SPDY_Response * | ||
391 | SPDY_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 | |||
479 | struct SPDY_Response * | ||
480 | SPDY_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 | |||
524 | int | ||
525 | SPDY_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 | |||
668 | socklen_t | ||
669 | SPDY_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 | |||
684 | struct SPDY_Session * | ||
685 | SPDY_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 | |||
697 | void * | ||
698 | SPDY_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 | |||
710 | void | ||
711 | SPDY_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 | |||
724 | void * | ||
725 | SPDY_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 | |||
737 | void | ||
738 | SPDY_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 */ | ||
31 | static const unsigned char | ||
32 | spdyf_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 | |||
214 | int | ||
215 | SPDYF_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 | |||
243 | void | ||
244 | SPDYF_zlib_deflate_end(z_stream *strm) | ||
245 | { | ||
246 | deflateEnd(strm); | ||
247 | } | ||
248 | |||
249 | int | ||
250 | SPDYF_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 | |||
319 | int | ||
320 | SPDYF_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 | |||
342 | void | ||
343 | SPDYF_zlib_inflate_end(z_stream *strm) | ||
344 | { | ||
345 | inflateEnd(strm); | ||
346 | } | ||
347 | |||
348 | |||
349 | int | ||
350 | SPDYF_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 | */ | ||
41 | int | ||
42 | SPDYF_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 | */ | ||
51 | void | ||
52 | SPDYF_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 | */ | ||
68 | int | ||
69 | SPDYF_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 | */ | ||
84 | int | ||
85 | SPDYF_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 | */ | ||
94 | void | ||
95 | SPDYF_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 | */ | ||
110 | int | ||
111 | SPDYF_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 | */ | ||
41 | static void | ||
42 | spdyf_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 | */ | ||
58 | SPDY_PanicCallback spdyf_panic = &spdyf_panic_std; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Global closure argument for "spdyf_panic". | ||
63 | */ | ||
64 | void *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 | */ | ||
73 | static void | ||
74 | spdyf_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 | */ | ||
94 | static void | ||
95 | spdyf_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 | */ | ||
119 | static int | ||
120 | spdyf_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 | |||
160 | void | ||
161 | SPDY_set_panic_func (SPDY_PanicCallback cb, | ||
162 | void *cls) | ||
163 | { | ||
164 | spdyf_panic = cb; | ||
165 | spdyf_panic_cls = cls; | ||
166 | } | ||
167 | |||
168 | |||
169 | struct SPDY_Daemon * | ||
170 | SPDYF_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 | |||
372 | void | ||
373 | SPDYF_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 | |||
391 | int | ||
392 | SPDYF_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 | |||
431 | int | ||
432 | SPDYF_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 | |||
473 | void | ||
474 | SPDYF_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 | */ | ||
34 | enum 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 | */ | ||
60 | struct SPDY_Daemon * | ||
61 | SPDYF_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 | */ | ||
82 | void | ||
83 | SPDYF_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 | */ | ||
96 | int | ||
97 | SPDYF_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 | */ | ||
114 | int | ||
115 | SPDYF_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 | */ | ||
127 | void | ||
128 | SPDYF_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 | |||
29 | unsigned long long | ||
30 | SPDYF_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 | */ | ||
56 | extern SPDY_PanicCallback spdyf_panic; | ||
57 | |||
58 | |||
59 | /** | ||
60 | * Closure argument for "mhd_panic". | ||
61 | */ | ||
62 | extern 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 | */ | ||
196 | unsigned long long | ||
197 | SPDYF_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 | |||
31 | int | ||
32 | SPDYF_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 | |||
57 | int | ||
58 | SPDYF_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 | */ | ||
36 | enum 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 | */ | ||
62 | typedef 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 | */ | ||
71 | typedef 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 | */ | ||
83 | typedef 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 | */ | ||
93 | typedef 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 | */ | ||
104 | typedef 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 | */ | ||
114 | typedef 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 | */ | ||
129 | typedef 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 | */ | ||
147 | typedef 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 | */ | ||
161 | typedef 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 | */ | ||
173 | typedef 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 | */ | ||
186 | typedef 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 | */ | ||
199 | int | ||
200 | SPDYF_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 | */ | ||
212 | int | ||
213 | SPDYF_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 | */ | ||
41 | static int | ||
42 | spdyf_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 | |||
55 | void | ||
56 | SPDYF_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 | |||
67 | void | ||
68 | SPDYF_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 | |||
77 | int | ||
78 | SPDYF_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 | |||
126 | void | ||
127 | SPDYF_openssl_deinit(struct SPDY_Daemon *daemon) | ||
128 | { | ||
129 | SSL_CTX_free(daemon->io_context); | ||
130 | } | ||
131 | |||
132 | |||
133 | int | ||
134 | SPDYF_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 | |||
169 | void | ||
170 | SPDYF_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 | |||
183 | int | ||
184 | SPDYF_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 | |||
218 | int | ||
219 | SPDYF_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 | |||
254 | int | ||
255 | SPDYF_openssl_is_pending(struct SPDY_Session *session) | ||
256 | { | ||
257 | /* From openssl docs: | ||
258 | * BUGS | ||
259 | SSL_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 | |||
265 | int | ||
266 | SPDYF_openssl_before_write(struct SPDY_Session *session) | ||
267 | { | ||
268 | (void)session; | ||
269 | |||
270 | return SPDY_YES; | ||
271 | } | ||
272 | |||
273 | |||
274 | int | ||
275 | SPDYF_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 | */ | ||
41 | void | ||
42 | SPDYF_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 | */ | ||
50 | void | ||
51 | SPDYF_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 | */ | ||
62 | int | ||
63 | SPDYF_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 | */ | ||
72 | void | ||
73 | SPDYF_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 | */ | ||
83 | int | ||
84 | SPDYF_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 | */ | ||
93 | void | ||
94 | SPDYF_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 | */ | ||
108 | int | ||
109 | SPDYF_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 | */ | ||
126 | int | ||
127 | SPDYF_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 | */ | ||
139 | int | ||
140 | SPDYF_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 | */ | ||
150 | int | ||
151 | SPDYF_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 | */ | ||
162 | int | ||
163 | SPDYF_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 | |||
33 | void | ||
34 | SPDYF_raw_global_init() | ||
35 | { | ||
36 | } | ||
37 | |||
38 | |||
39 | void | ||
40 | SPDYF_raw_global_deinit() | ||
41 | { | ||
42 | } | ||
43 | |||
44 | |||
45 | int | ||
46 | SPDYF_raw_init(struct SPDY_Daemon *daemon) | ||
47 | { | ||
48 | (void)daemon; | ||
49 | |||
50 | return SPDY_YES; | ||
51 | } | ||
52 | |||
53 | |||
54 | void | ||
55 | SPDYF_raw_deinit(struct SPDY_Daemon *daemon) | ||
56 | { | ||
57 | (void)daemon; | ||
58 | } | ||
59 | |||
60 | |||
61 | int | ||
62 | SPDYF_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 | |||
85 | void | ||
86 | SPDYF_raw_close_session(struct SPDY_Session *session) | ||
87 | { | ||
88 | (void)session; | ||
89 | } | ||
90 | |||
91 | |||
92 | int | ||
93 | SPDYF_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 | |||
121 | int | ||
122 | SPDYF_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 | |||
150 | int | ||
151 | SPDYF_raw_is_pending(struct SPDY_Session *session) | ||
152 | { | ||
153 | (void)session; | ||
154 | |||
155 | return SPDY_NO; | ||
156 | } | ||
157 | |||
158 | |||
159 | int | ||
160 | SPDYF_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 | |||
178 | int | ||
179 | SPDYF_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 | */ | ||
35 | void | ||
36 | SPDYF_raw_global_init(); | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Should be called | ||
41 | * at the end of the program. | ||
42 | * | ||
43 | */ | ||
44 | void | ||
45 | SPDYF_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 | */ | ||
54 | int | ||
55 | SPDYF_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 | */ | ||
64 | void | ||
65 | SPDYF_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 | */ | ||
75 | int | ||
76 | SPDYF_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 | */ | ||
85 | void | ||
86 | SPDYF_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 | */ | ||
100 | int | ||
101 | SPDYF_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 | */ | ||
118 | int | ||
119 | SPDYF_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 | */ | ||
132 | int | ||
133 | SPDYF_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 | */ | ||
143 | int | ||
144 | SPDYF_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 | */ | ||
155 | int | ||
156 | SPDYF_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 | */ | ||
43 | static void | ||
44 | spdyf_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 | */ | ||
180 | static void | ||
181 | spdyf_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 | */ | ||
259 | static void | ||
260 | spdyf_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 | */ | ||
331 | static void | ||
332 | spdyf_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 | |||
421 | int | ||
422 | SPDYF_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 | |||
516 | int | ||
517 | SPDYF_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 | |||
569 | int | ||
570 | SPDYF_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 | |||
741 | int | ||
742 | SPDYF_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 | |||
786 | int | ||
787 | SPDYF_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 | |||
829 | void | ||
830 | SPDYF_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 | |||
865 | int | ||
866 | SPDYF_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 | |||
980 | int | ||
981 | SPDYF_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 | |||
1154 | int | ||
1155 | SPDYF_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 | |||
1359 | void | ||
1360 | SPDYF_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 | |||
1388 | int | ||
1389 | SPDYF_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 | |||
1493 | void | ||
1494 | SPDYF_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 | |||
1574 | void | ||
1575 | SPDYF_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 | |||
1616 | int | ||
1617 | SPDYF_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 | |||
1664 | int | ||
1665 | SPDYF_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 | |||
1720 | int | ||
1721 | SPDYF_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 | */ | ||
43 | int | ||
44 | SPDYF_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 | */ | ||
67 | int | ||
68 | SPDYF_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 | */ | ||
85 | int | ||
86 | SPDYF_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 | */ | ||
95 | void | ||
96 | SPDYF_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 | */ | ||
107 | int | ||
108 | SPDYF_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 | */ | ||
125 | void | ||
126 | SPDYF_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 | */ | ||
137 | void | ||
138 | SPDYF_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 | */ | ||
152 | int | ||
153 | SPDYF_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 | */ | ||
170 | int | ||
171 | SPDYF_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 | */ | ||
187 | int | ||
188 | SPDYF_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 | */ | ||
207 | int | ||
208 | SPDYF_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 | */ | ||
222 | int | ||
223 | SPDYF_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 | */ | ||
236 | int | ||
237 | SPDYF_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 | */ | ||
250 | int | ||
251 | SPDYF_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 | */ | ||
264 | int | ||
265 | SPDYF_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 | */ | ||
278 | void | ||
279 | SPDYF_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 | |||
31 | int | ||
32 | SPDYF_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 | |||
116 | void | ||
117 | SPDYF_stream_destroy(struct SPDYF_Stream *stream) | ||
118 | { | ||
119 | SPDY_name_value_destroy(stream->headers); | ||
120 | free(stream); | ||
121 | stream = NULL; | ||
122 | } | ||
123 | |||
124 | |||
125 | void | ||
126 | SPDYF_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 | |||
158 | struct SPDYF_Stream * | ||
159 | SPDYF_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 | */ | ||
43 | int | ||
44 | SPDYF_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 | */ | ||
52 | void | ||
53 | SPDYF_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 | */ | ||
62 | void | ||
63 | SPDYF_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 | */ | ||
73 | struct SPDYF_Stream * | ||
74 | SPDYF_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 | |||
34 | int | ||
35 | SPDYF_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 | |||
41 | struct SPDY_NameValue * | ||
42 | SPDY_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 | |||
55 | int | ||
56 | SPDY_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 | |||
189 | const char * const * | ||
190 | SPDY_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 | |||
217 | void | ||
218 | SPDY_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 | |||
236 | int | ||
237 | SPDY_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 | |||
278 | void | ||
279 | SPDY_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 | |||
289 | struct SPDYF_Response_Queue * | ||
290 | SPDYF_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 | |||
434 | void | ||
435 | SPDYF_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 | ||
457 | SPDYF_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 | ||
554 | SPDYF_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 | */ | ||
38 | enum 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 | */ | ||
129 | enum 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 | */ | ||
172 | enum 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 | */ | ||
189 | enum 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 | */ | ||
201 | enum 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 | */ | ||
219 | enum 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 | */ | ||
295 | enum 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 | |||
316 | struct SPDYF_Stream; | ||
317 | |||
318 | struct 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 | */ | ||
334 | typedef 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 | */ | ||
351 | typedef 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 | */ | ||
369 | typedef 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 | */ | ||
379 | struct __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 | */ | ||
392 | struct __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 | */ | ||
404 | struct 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 | */ | ||
486 | struct 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 | */ | ||
519 | struct 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 | */ | ||
602 | struct 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 | */ | ||
860 | struct 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 | */ | ||
1003 | struct 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 | */ | ||
1178 | struct SPDYF_Response_Queue * | ||
1179 | SPDYF_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 | */ | ||
1196 | void | ||
1197 | SPDYF_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 | */ | ||
1208 | int | ||
1209 | SPDYF_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 | */ | ||
1224 | int | ||
1225 | SPDYF_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 | */ | ||
1241 | ssize_t | ||
1242 | SPDYF_name_value_to_stream(struct SPDY_NameValue * container[], | ||
1243 | int num_containers, | ||
1244 | void **stream); | ||
1245 | |||
1246 | #endif | ||