aboutsummaryrefslogtreecommitdiff
path: root/src/microspdy/structures.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microspdy/structures.c')
-rw-r--r--src/microspdy/structures.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/src/microspdy/structures.c b/src/microspdy/structures.c
new file mode 100644
index 00000000..b3760be3
--- /dev/null
+++ b/src/microspdy/structures.c
@@ -0,0 +1,612 @@
1/*
2 This file is part of libmicrospdy
3 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
31
32struct SPDY_NameValue *
33SPDY_name_value_create ()
34{
35 struct SPDY_NameValue *pair;
36
37 if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
38 return NULL;
39
40 memset (pair, 0, sizeof (struct SPDY_NameValue));
41
42 return pair;
43}
44
45
46int
47SPDY_name_value_add (struct SPDY_NameValue *container,
48 const char *name,
49 const char *value)
50{
51 uint i;
52 uint len;
53 struct SPDY_NameValue *pair;
54 struct SPDY_NameValue *temp;
55 char **temp_value;
56 char *temp_string;
57
58 if(NULL == container || NULL == name || 0 == (len = strlen(name)))
59 return SPDY_INPUT_ERROR;
60
61 for(i=0; i<len; ++i)
62 {
63 if(isupper(name[i]))
64 return SPDY_INPUT_ERROR;
65 }
66
67 if(NULL == container->name && NULL == container->value)
68 {
69 //container is empty/just created
70 if (NULL == (container->name = strdup (name)))
71 {
72 return SPDY_NO;
73 }
74 if (NULL == (container->value = malloc(sizeof(char *))))
75 {
76 free(container->name);
77 return SPDY_NO;
78 }
79 if (NULL == (container->value[0] = strdup (value)))
80 {
81 free(container->value);
82 free(container->name);
83 return SPDY_NO;
84 }
85 container->num_values = 1;
86 return SPDY_YES;
87 }
88
89 pair = container;
90 while(NULL != pair)
91 {
92 if(0 == strcmp(pair->name, name))
93 {
94 //the value will be added to this pair
95 break;
96 }
97 pair = pair->next;
98 }
99
100 if(NULL == pair)
101 {
102 //the name doesn't exist in container, add new pair
103 if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
104 return SPDY_NO;
105
106 memset(pair, 0, sizeof(struct SPDY_NameValue));
107
108 if (NULL == (pair->name = strdup (name)))
109 {
110 free(pair);
111 return SPDY_NO;
112 }
113 if (NULL == (pair->value = malloc(sizeof(char *))))
114 {
115 free(pair->name);
116 free(pair);
117 return SPDY_NO;
118 }
119 if (NULL == (pair->value[0] = strdup (value)))
120 {
121 free(pair->value);
122 free(pair->name);
123 free(pair);
124 return SPDY_NO;
125 }
126 pair->num_values = 1;
127
128 temp = container;
129 while(NULL != temp->next)
130 temp = temp->next;
131 temp->next = pair;
132 pair->prev = temp;
133
134 return SPDY_YES;
135 }
136
137 //check for duplication (case sensitive)
138 for(i=0; i<pair->num_values; ++i)
139 if(0 == strcmp(pair->value[i], value))
140 return SPDY_NO;
141
142 if(strlen(pair->value[0]) > 0)
143 {
144 //the value will be appended to the others for this name
145 if (NULL == (temp_value = malloc((pair->num_values + 1) * sizeof(char *))))
146 {
147 return SPDY_NO;
148 }
149 memcpy(temp_value, pair->value, pair->num_values * sizeof(char *));
150 if (NULL == (temp_value[pair->num_values] = strdup (value)))
151 {
152 free(temp_value);
153 return SPDY_NO;
154 }
155 free(pair->value);
156 pair->value = temp_value;
157 ++pair->num_values;
158 return SPDY_YES;
159 }
160
161 //just replace the empty value
162
163 if (NULL == (temp_string = strdup (value)))
164 {
165 return SPDY_NO;
166 }
167 free(pair->value[0]);
168 pair->value[0] = temp_string;
169
170 return SPDY_YES;
171}
172
173
174const char * const *
175SPDY_name_value_lookup (struct SPDY_NameValue *container,
176 const char *name,
177 int *num_values)
178{
179 struct SPDY_NameValue *temp = container;
180
181 if(NULL == container || NULL == name || NULL == num_values)
182 return NULL;
183 if(NULL == container->name && NULL == container->value)
184 return NULL;
185
186 do
187 {
188 if(strcmp(name, temp->name) == 0)
189 {
190 *num_values = temp->num_values;
191 return (const char * const *)temp->value;
192 }
193
194 temp = temp->next;
195 }
196 while(NULL != temp);
197
198 return NULL;
199}
200
201
202void
203SPDY_name_value_destroy (struct SPDY_NameValue *container)
204{
205 uint i;
206 struct SPDY_NameValue *temp = container;
207
208 while(NULL != temp)
209 {
210 container = container->next;
211 free(temp->name);
212 for(i=0; i<temp->num_values; ++i)
213 free(temp->value[i]);
214 free(temp->value);
215 free(temp);
216 temp=container;
217 }
218}
219
220
221int
222SPDY_name_value_iterate (struct SPDY_NameValue *container,
223 SPDY_NameValueIterator iterator,
224 void *iterator_cls)
225{
226 int count;
227 int ret;
228 struct SPDY_NameValue *temp = container;
229
230 if(NULL == container)
231 return SPDY_INPUT_ERROR;
232
233 //check if container is an empty struct
234 if(NULL == container->name && NULL == container->value)
235 return 0;
236
237 count = 0;
238
239 if(NULL == iterator)
240 {
241 do
242 {
243 ++count;
244 temp=temp->next;
245 }
246 while(NULL != temp);
247
248 return count;
249 }
250
251 //code duplication for avoiding if here
252 do
253 {
254 ++count;
255 ret = iterator(iterator_cls, temp->name, (const char * const *)temp->value, temp->num_values);
256 temp=temp->next;
257 }
258 while(NULL != temp && SPDY_YES == ret);
259
260 return count;
261}
262
263void
264SPDY_destroy_response(struct SPDY_Response *response)
265{
266 free(response->data);
267 free(response->headers);
268 free(response);
269}
270
271
272struct SPDYF_Response_Queue *
273SPDYF_response_queue_create(bool is_data,
274 void *data,
275 size_t data_size,
276 struct SPDY_Response *response,
277 struct SPDYF_Stream *stream,
278 bool closestream,
279 SPDYF_ResponseQueueResultCallback frqcb,
280 void *frqcb_cls,
281 SPDY_ResponseResultCallback rrcb,
282 void *rrcb_cls)
283{
284 struct SPDYF_Response_Queue *head = NULL;
285 struct SPDYF_Response_Queue *prev;
286 struct SPDYF_Response_Queue *response_to_queue;
287 struct SPDYF_Control_Frame *control_frame;
288 struct SPDYF_Data_Frame *data_frame;
289 uint i;
290 bool is_last;
291
292 SPDYF_ASSERT(!is_data
293 || 0 == data_size && NULL != response->rcb
294 || 0 < data_size && NULL == response->rcb,
295 "either data or request->rcb must not be null");
296
297 if(is_data && data_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)
298 {
299 //separate the data in more frames and add them to the queue
300
301 prev=NULL;
302 for(i = 0; i < data_size; i += SPDY_MAX_SUPPORTED_FRAME_SIZE)
303 {
304 is_last = (i + SPDY_MAX_SUPPORTED_FRAME_SIZE) >= data_size;
305
306 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
307 goto free_and_fail;
308
309 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
310 if(0 == i)
311 head = response_to_queue;
312
313 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
314 {
315 free(response_to_queue);
316 goto free_and_fail;
317 }
318 memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
319 data_frame->control_bit = 0;
320 data_frame->stream_id = stream->stream_id;
321 if(is_last && closestream)
322 data_frame->flags |= SPDY_DATA_FLAG_FIN;
323
324 response_to_queue->data_frame = data_frame;
325 response_to_queue->process_response_handler = &SPDYF_handler_write_data;
326 response_to_queue->is_data = is_data;
327 response_to_queue->stream = stream;
328 if(is_last)
329 {
330 response_to_queue->frqcb = frqcb;
331 response_to_queue->frqcb_cls = frqcb_cls;
332 response_to_queue->rrcb = rrcb;
333 response_to_queue->rrcb_cls = rrcb_cls;
334 }
335 response_to_queue->data = data + i;
336 response_to_queue->data_size = is_last
337 ? (data_size - 1) % SPDY_MAX_SUPPORTED_FRAME_SIZE + 1
338 : SPDY_MAX_SUPPORTED_FRAME_SIZE;
339 response_to_queue->response = response;
340
341 response_to_queue->prev = prev;
342 if(NULL != prev)
343 prev->next = response_to_queue;
344 prev = response_to_queue;
345 }
346
347 return head;
348
349 //for GOTO
350 free_and_fail:
351 while(NULL != head)
352 {
353 response_to_queue = head;
354 head = head->next;
355 free(response_to_queue->data_frame);
356 free(response_to_queue);
357 }
358 return NULL;
359 }
360
361 //create only one frame for data, data with callback or control frame
362
363 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
364 {
365 return NULL;
366 }
367 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
368
369 if(is_data)
370 {
371 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
372 {
373 free(response_to_queue);
374 return NULL;
375 }
376 memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
377 data_frame->control_bit = 0;
378 data_frame->stream_id = stream->stream_id;
379 if(closestream && NULL == response->rcb)
380 data_frame->flags |= SPDY_DATA_FLAG_FIN;
381
382 response_to_queue->data_frame = data_frame;
383 response_to_queue->process_response_handler = &SPDYF_handler_write_data;
384 }
385 else
386 {
387 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
388 {
389 free(response_to_queue);
390 return NULL;
391 }
392 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
393 control_frame->control_bit = 1;
394 control_frame->version = SPDY_VERSION;
395 control_frame->type = SPDY_CONTROL_FRAME_TYPES_SYN_REPLY;
396 if(closestream)
397 control_frame->flags |= SPDY_SYN_REPLY_FLAG_FIN;
398
399 response_to_queue->control_frame = control_frame;
400 response_to_queue->process_response_handler = &SPDYF_handler_write_syn_reply;
401 }
402
403 response_to_queue->is_data = is_data;
404 response_to_queue->stream = stream;
405 response_to_queue->frqcb = frqcb;
406 response_to_queue->frqcb_cls = frqcb_cls;
407 response_to_queue->rrcb = rrcb;
408 response_to_queue->rrcb_cls = rrcb_cls;
409 response_to_queue->data = data;
410 response_to_queue->data_size = data_size;
411 response_to_queue->response = response;
412
413 return response_to_queue;
414}
415
416
417void
418SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue)
419{
420 //data is not copied to the struct but only linked
421 //but this is not valid for GOAWAY and RST_STREAM
422 if(!response_queue->is_data
423 && (SPDY_CONTROL_FRAME_TYPES_RST_STREAM == response_queue->control_frame->type
424 || SPDY_CONTROL_FRAME_TYPES_GOAWAY == response_queue->control_frame->type))
425 {
426 free(response_queue->data);
427 }
428 if(response_queue->is_data)
429 free(response_queue->data_frame);
430 else
431 free(response_queue->control_frame);
432
433 free(response_queue);
434}
435
436
437ssize_t
438SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
439 int num_containers,
440 void **stream)
441{
442 size_t size;
443 int32_t num_pairs = 0;
444 int32_t value_size;
445 int32_t name_size;
446 int32_t temp;
447 uint i;
448 uint offset;
449 uint value_offset;
450 struct SPDY_NameValue * iterator;
451 int j;
452
453 size = 4; //for num pairs
454
455 for(j=0; j<num_containers; ++j)
456 {
457 iterator = container[j];
458 while(iterator != NULL)
459 {
460 ++num_pairs;
461 size += 4 + strlen(iterator->name); //length + string
462
463 SPDYF_ASSERT(iterator->num_values>0, "num_values is 0");
464
465 size += 4; //value length
466
467 for(i=0; i<iterator->num_values; ++i)
468 {
469 size += strlen(iterator->value[i]); // string
470 if(i/* || !strlen(iterator->value[i])*/) ++size; //NULL separator
471 }
472
473 iterator = iterator->next;
474 }
475}
476
477 if(NULL == (*stream = malloc(size)))
478 {
479 return -1;
480 }
481
482 //put num_pairs to the stream
483 num_pairs = htonl(num_pairs);
484 memcpy(*stream, &num_pairs, 4);
485 offset = 4;
486
487 //put all other headers to the stream
488 for(j=0; j<num_containers; ++j)
489 {
490 iterator = container[j];
491 while(iterator != NULL)
492 {
493 name_size = strlen(iterator->name);
494 temp = htonl(name_size);
495 memcpy(*stream + offset, &temp, 4);
496 offset += 4;
497 strncpy(*stream + offset, iterator->name, name_size);
498 offset += name_size;
499
500 value_offset = offset;
501 offset += 4;
502 for(i=0; i<iterator->num_values; ++i)
503 {
504 if(i /*|| !strlen(iterator->value[0])*/)
505 {
506 memset(*stream + offset, 0, 1);
507 ++offset;
508 if(!i) continue;
509 }
510 strncpy(*stream + offset, iterator->value[i], strlen(iterator->value[i]));
511 offset += strlen(iterator->value[i]);
512 }
513 value_size = offset - value_offset - 4;
514 value_size = htonl(value_size);
515 memcpy(*stream + value_offset, &value_size, 4);
516
517 iterator = iterator->next;
518 }
519}
520
521 SPDYF_ASSERT(offset == size,"offset is wrong");
522
523 return size;
524}
525
526
527int
528SPDYF_name_value_from_stream(void *stream,
529 size_t size,
530 struct SPDY_NameValue ** container)
531{
532 int32_t num_pairs;
533 int32_t value_size;
534 int32_t name_size;
535 int i;
536 uint offset = 0;
537 uint value_end_offset;
538 char *name;
539 char *value;
540
541 if(NULL == (*container = SPDY_name_value_create ()))
542 {
543 return SPDY_NO;
544 }
545
546 //get number of pairs
547 memcpy(&num_pairs, stream, 4);
548 offset = 4;
549 num_pairs = ntohl(num_pairs);
550
551 if(num_pairs > 0)
552 {
553 for(i = 0; i < num_pairs; ++i)
554 {
555 //get name size
556 memcpy(&name_size, stream + offset, 4);
557 offset += 4;
558 name_size = ntohl(name_size);
559 //get name
560 if(NULL == (name = strndup(stream + offset, name_size)))
561 {
562 SPDY_name_value_destroy(*container);
563 return SPDY_NO;
564 }
565 offset+=name_size;
566
567 //get value size
568 memcpy(&value_size, stream + offset, 4);
569 offset += 4;
570 value_size = ntohl(value_size);
571 value_end_offset = offset + value_size;
572 //get value
573 do
574 {
575 if(NULL == (value = strndup(stream + offset, value_size)))
576 {
577 free(name);
578 SPDY_name_value_destroy(*container);
579 return SPDY_NO;
580 }
581 offset += strlen(value);
582 if(offset < value_end_offset)
583 ++offset; //NULL separator
584
585 //add name/value to the struct
586 if(SPDY_YES != SPDY_name_value_add(*container, name, value))
587 {
588 free(name);
589 free(value);
590 SPDY_name_value_destroy(*container);
591 return SPDY_NO;
592 }
593 free(value);
594 }
595 while(offset < value_end_offset);
596
597 free(name);
598
599 if(offset != value_end_offset)
600 {
601 SPDY_name_value_destroy(*container);
602 return SPDY_INPUT_ERROR;
603 }
604 }
605 }
606
607 if(offset == size)
608 return SPDY_YES;
609
610 SPDY_name_value_destroy(*container);
611 return SPDY_INPUT_ERROR;
612}