aboutsummaryrefslogtreecommitdiff
path: root/src/examples/mhd2spdy_spdy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/examples/mhd2spdy_spdy.c')
-rw-r--r--src/examples/mhd2spdy_spdy.c908
1 files changed, 908 insertions, 0 deletions
diff --git a/src/examples/mhd2spdy_spdy.c b/src/examples/mhd2spdy_spdy.c
new file mode 100644
index 00000000..93cad507
--- /dev/null
+++ b/src/examples/mhd2spdy_spdy.c
@@ -0,0 +1,908 @@
1/*
2 * Spdylay - SPDY Library
3 *
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26/**
27 * @file spdy.c
28 * @author Tatsuhiro Tsujikawa
29 * @author Andrey Uzunov
30 */
31
32#include "mhd2spdy_structures.h"
33#include "mhd2spdy_spdy.h"
34#include "mhd2spdy_http.h"
35
36enum
37{
38 IO_NONE,
39 WANT_READ,
40 WANT_WRITE
41};
42
43
44/*
45 * Prints error containing the function name |func| and message |msg|
46 * and exit.
47 */
48static void spdy_dief(const char *func, const char *msg)
49{
50 fprintf(stderr, "FATAL: %s: %s\n", func, msg);
51 exit(EXIT_FAILURE);
52}
53
54/*
55 * Prints error containing the function name |func| and error code
56 * |error_code| and exit.
57 */
58void spdy_diec(const char *func, int error_code)
59{
60 fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
61 spdylay_strerror(error_code));
62 exit(EXIT_FAILURE);
63}
64
65
66/*
67 * The implementation of spdylay_send_callback type. Here we write
68 * |data| with size |length| to the network and return the number of
69 * bytes actually written. See the documentation of
70 * spdylay_send_callback for the details.
71 */
72static ssize_t spdy_cb_send(spdylay_session *session,
73 const uint8_t *data, size_t length, int flags,
74 void *user_data)
75{
76 //PRINT_INFO("spdy_cb_send called");
77 struct SPDY_Connection *connection;
78 ssize_t rv;
79 connection = (struct SPDY_Connection*)user_data;
80 connection->want_io = IO_NONE;
81 if(connection->is_tls)
82 {
83 ERR_clear_error();
84 rv = SSL_write(connection->ssl, data, length);
85 if(rv < 0) {
86 int err = SSL_get_error(connection->ssl, rv);
87 if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
88 connection->want_io = (err == SSL_ERROR_WANT_READ ?
89 WANT_READ : WANT_WRITE);
90 rv = SPDYLAY_ERR_WOULDBLOCK;
91 } else {
92 rv = SPDYLAY_ERR_CALLBACK_FAILURE;
93 }
94 }
95 }
96 else
97 {
98 rv = write(connection->fd,
99 data,
100 length);
101
102 if (rv < 0)
103 {
104 switch(errno)
105 {
106 case EAGAIN:
107 #if EAGAIN != EWOULDBLOCK
108 case EWOULDBLOCK:
109 #endif
110 connection->want_io = WANT_WRITE;
111 rv = SPDYLAY_ERR_WOULDBLOCK;
112 break;
113
114 default:
115 rv = SPDYLAY_ERR_CALLBACK_FAILURE;
116 }
117 }
118 }
119 return rv;
120}
121
122/*
123 * The implementation of spdylay_recv_callback type. Here we read data
124 * from the network and write them in |buf|. The capacity of |buf| is
125 * |length| bytes. Returns the number of bytes stored in |buf|. See
126 * the documentation of spdylay_recv_callback for the details.
127 */
128static ssize_t spdy_cb_recv(spdylay_session *session,
129 uint8_t *buf, size_t length, int flags,
130 void *user_data)
131{
132 struct SPDY_Connection *connection;
133 ssize_t rv;
134
135 connection = (struct SPDY_Connection*)user_data;
136 //prevent monopolizing everything
137 if(!(++connection->counter % 10)) return SPDYLAY_ERR_WOULDBLOCK;
138 connection->want_io = IO_NONE;
139 if(connection->is_tls)
140 {
141 ERR_clear_error();
142 rv = SSL_read(connection->ssl, buf, length);
143 if(rv < 0) {
144 int err = SSL_get_error(connection->ssl, rv);
145 if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
146 connection->want_io = (err == SSL_ERROR_WANT_READ ?
147 WANT_READ : WANT_WRITE);
148 rv = SPDYLAY_ERR_WOULDBLOCK;
149 } else {
150 rv = SPDYLAY_ERR_CALLBACK_FAILURE;
151 }
152 } else if(rv == 0) {
153 rv = SPDYLAY_ERR_EOF;
154 }
155 }
156 else
157 {
158 rv = read(connection->fd,
159 buf,
160 length);
161
162 if (rv < 0)
163 {
164 switch(errno)
165 {
166 case EAGAIN:
167 #if EAGAIN != EWOULDBLOCK
168 case EWOULDBLOCK:
169 #endif
170 connection->want_io = WANT_READ;
171 rv = SPDYLAY_ERR_WOULDBLOCK;
172 break;
173
174 default:
175 rv = SPDYLAY_ERR_CALLBACK_FAILURE;
176 }
177 }
178 else if(rv == 0)
179 rv = SPDYLAY_ERR_EOF;
180 }
181 return rv;
182}
183
184/*
185 * The implementation of spdylay_before_ctrl_send_callback type. We
186 * use this function to get stream ID of the request. This is because
187 * stream ID is not known when we submit the request
188 * (spdylay_spdy_submit_request).
189 */
190/*static void spdy_cb_before_ctrl_send(spdylay_session *session,
191 spdylay_frame_type type,
192 spdylay_frame *frame,
193 void *user_data)
194{
195}*/
196
197
198static void spdy_cb_on_ctrl_send(spdylay_session *session,
199 spdylay_frame_type type,
200 spdylay_frame *frame, void *user_data)
201{
202 //char **nv;
203 //const char *name = NULL;
204 int32_t stream_id;
205 //size_t i;
206 struct Proxy *proxy;
207
208 switch(type) {
209 case SPDYLAY_SYN_STREAM:
210 //nv = frame->syn_stream.nv;
211 //name = "SYN_STREAM";
212 stream_id = frame->syn_stream.stream_id;
213 proxy = spdylay_session_get_stream_user_data(session, stream_id);
214 ++glob_opt.streams_opened;
215 ++proxy->spdy_connection->streams_opened;
216 PRINT_INFO2("opening stream: str open %i; %s", glob_opt.streams_opened, proxy->url);
217 break;
218 default:
219 break;
220 }
221}
222
223void spdy_cb_on_ctrl_recv(spdylay_session *session,
224 spdylay_frame_type type,
225 spdylay_frame *frame, void *user_data)
226{
227 //struct SPDY_Request *req;
228 char **nv;
229 //const char *name = NULL;
230 int32_t stream_id;
231 struct Proxy * proxy;
232
233 switch(type) {
234 case SPDYLAY_SYN_REPLY:
235 nv = frame->syn_reply.nv;
236 //name = "SYN_REPLY";
237 stream_id = frame->syn_reply.stream_id;
238 break;
239 case SPDYLAY_HEADERS:
240 nv = frame->headers.nv;
241 //name = "HEADERS";
242 stream_id = frame->headers.stream_id;
243 break;
244 default:
245 return;
246 break;
247 }
248
249 proxy = spdylay_session_get_stream_user_data(session, stream_id);
250 PRINT_INFO2("received headers for %s", proxy->url);
251
252 http_create_response(proxy, nv);
253 glob_opt.spdy_data_received = true;
254}
255
256/*
257 * The implementation of spdylay_on_stream_close_callback type. We use
258 * this function to know the response is fully received. Since we just
259 * fetch 1 resource in this program, after reception of the response,
260 * we submit GOAWAY and close the session.
261 */
262static void spdy_cb_on_stream_close(spdylay_session *session,
263 int32_t stream_id,
264 spdylay_status_code status_code,
265 void *user_data)
266{
267 struct Proxy * proxy = spdylay_session_get_stream_user_data(session, stream_id);
268
269 assert(NULL != proxy);
270
271 --glob_opt.streams_opened;
272 --proxy->spdy_connection->streams_opened;
273 PRINT_INFO2("closing stream: str opened %i", glob_opt.streams_opened);
274
275 DLL_remove(proxy->spdy_connection->proxies_head, proxy->spdy_connection->proxies_tail, proxy);
276
277 if(proxy->http_active)
278 proxy->spdy_active = false;
279 else
280 free_proxy(proxy);
281 return;
282}
283
284#define SPDY_MAX_OUTLEN 4096
285
286/*
287 * The implementation of spdylay_on_data_chunk_recv_callback type. We
288 * use this function to print the received response body.
289 */
290static void spdy_cb_on_data_chunk_recv(spdylay_session *session, uint8_t flags,
291 int32_t stream_id,
292 const uint8_t *data, size_t len,
293 void *user_data)
294{
295 //struct SPDY_Request *req;
296 struct Proxy *proxy;
297 proxy = spdylay_session_get_stream_user_data(session, stream_id);
298
299 if(NULL == proxy->http_body)
300 proxy->http_body = au_malloc(len);
301 else
302 proxy->http_body = realloc(proxy->http_body, proxy->http_body_size + len);
303 if(NULL == proxy->http_body)
304 {
305 PRINT_INFO("not enough memory (realloc returned NULL)");
306 return ;
307 }
308
309 memcpy(proxy->http_body + proxy->http_body_size, data, len);
310 proxy->http_body_size += len;
311 PRINT_INFO2("received data for %s; %zu bytes", proxy->url, len);
312 glob_opt.spdy_data_received = true;
313}
314
315static void spdy_cb_on_data_recv(spdylay_session *session,
316 uint8_t flags, int32_t stream_id, int32_t length, void *user_data)
317{
318 if(flags & SPDYLAY_DATA_FLAG_FIN)
319 {
320 struct Proxy *proxy;
321 proxy = spdylay_session_get_stream_user_data(session, stream_id);
322 proxy->done = true;
323 PRINT_INFO2("last data frame received for %s", proxy->url);
324 }
325}
326
327/*
328 * Setup callback functions. Spdylay API offers many callback
329 * functions, but most of them are optional. The send_callback is
330 * always required. Since we use spdylay_session_recv(), the
331 * recv_callback is also required.
332 */
333static void spdy_setup_spdylay_callbacks(spdylay_session_callbacks *callbacks)
334{
335 memset(callbacks, 0, sizeof(spdylay_session_callbacks));
336 callbacks->send_callback = spdy_cb_send;
337 callbacks->recv_callback = spdy_cb_recv;
338 //callbacks->before_ctrl_send_callback = spdy_cb_before_ctrl_send;
339 callbacks->on_ctrl_send_callback = spdy_cb_on_ctrl_send;
340 callbacks->on_ctrl_recv_callback = spdy_cb_on_ctrl_recv;
341 callbacks->on_stream_close_callback = spdy_cb_on_stream_close;
342 callbacks->on_data_chunk_recv_callback = spdy_cb_on_data_chunk_recv;
343 callbacks->on_data_recv_callback = spdy_cb_on_data_recv;
344}
345
346/*
347 * Callback function for SSL/TLS NPN. Since this program only supports
348 * SPDY protocol, if server does not offer SPDY protocol the Spdylay
349 * library supports, we terminate program.
350 */
351static int spdy_cb_ssl_select_next_proto(SSL* ssl,
352 unsigned char **out, unsigned char *outlen,
353 const unsigned char *in, unsigned int inlen,
354 void *arg)
355{
356 //PRINT_INFO("spdy_cb_ssl_select_next_proto");
357 int rv;
358 uint16_t *spdy_proto_version;
359 /* spdylay_select_next_protocol() selects SPDY protocol version the
360 Spdylay library supports. */
361 rv = spdylay_select_next_protocol(out, outlen, in, inlen);
362 if(rv <= 0) {
363 PRINT_INFO("Server did not advertise spdy/2 or spdy/3 protocol.");
364 return rv;
365 }
366 spdy_proto_version = (uint16_t*)arg;
367 *spdy_proto_version = rv;
368 return SSL_TLSEXT_ERR_OK;
369}
370
371/*
372 * Setup SSL context. We pass |spdy_proto_version| to get negotiated
373 * SPDY protocol version in NPN callback.
374 */
375void spdy_ssl_init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version)
376{
377 /* Disable SSLv2 and enable all workarounds for buggy servers */
378 SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);
379 SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
380 SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
381 /* Set NPN callback */
382 SSL_CTX_set_next_proto_select_cb(ssl_ctx, spdy_cb_ssl_select_next_proto,
383 spdy_proto_version);
384}
385
386static int spdy_ssl_handshake(SSL *ssl, int fd)
387{
388 int rv;
389 if(SSL_set_fd(ssl, fd) == 0) {
390 spdy_dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
391 }
392 ERR_clear_error();
393 rv = SSL_connect(ssl);
394 if(rv <= 0) {
395 PRINT_INFO2("SSL_connect %s", ERR_error_string(ERR_get_error(), NULL));
396 }
397
398 return rv;
399}
400
401/*
402 * Connects to the host |host| and port |port|. This function returns
403 * the file descriptor of the client socket.
404 */
405static int spdy_socket_connect_to(const char *host, uint16_t port)
406{
407 struct addrinfo hints;
408 int fd = -1;
409 int rv;
410 char service[NI_MAXSERV];
411 struct addrinfo *res, *rp;
412 snprintf(service, sizeof(service), "%u", port);
413 memset(&hints, 0, sizeof(struct addrinfo));
414 hints.ai_family = AF_UNSPEC;
415 hints.ai_socktype = SOCK_STREAM;
416 rv = getaddrinfo(host, service, &hints, &res);
417 if(rv != 0) {
418 printf("%s\n",host);
419 spdy_dief("getaddrinfo", gai_strerror(rv));
420 }
421 for(rp = res; rp; rp = rp->ai_next) {
422 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
423 if(fd == -1) {
424 continue;
425 }
426 while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
427 errno == EINTR);
428 if(rv == 0) {
429 break;
430 }
431 close(fd);
432 fd = -1;
433 }
434 freeaddrinfo(res);
435 return fd;
436}
437
438static void spdy_socket_make_non_block(int fd)
439{
440 int flags, rv;
441 while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
442 if(flags == -1) {
443 spdy_dief("fcntl", strerror(errno));
444 }
445 while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
446 if(rv == -1) {
447 spdy_dief("fcntl", strerror(errno));
448 }
449}
450
451/*
452 * Setting TCP_NODELAY is not mandatory for the SPDY protocol.
453 */
454static void spdy_socket_set_tcp_nodelay(int fd)
455{
456 int val = 1;
457 int rv;
458 rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
459 if(rv == -1) {
460 spdy_dief("setsockopt", strerror(errno));
461 }
462}
463
464/*
465 * Update |pollfd| based on the state of |connection|.
466 */
467void spdy_ctl_poll(struct pollfd *pollfd, struct SPDY_Connection *connection)
468{
469 pollfd->events = 0;
470 if(spdylay_session_want_read(connection->session) ||
471 connection->want_io == WANT_READ) {
472 pollfd->events |= POLLIN;
473 }
474 if(spdylay_session_want_write(connection->session) ||
475 connection->want_io == WANT_WRITE) {
476 pollfd->events |= POLLOUT;
477 }
478}
479
480/*
481 * Update |selectfd| based on the state of |connection|.
482 */
483bool spdy_ctl_select(fd_set * read_fd_set,
484 fd_set * write_fd_set,
485 fd_set * except_fd_set,
486 struct SPDY_Connection *connection)
487{
488 bool ret = false;
489
490 if(spdylay_session_want_read(connection->session) ||
491 connection->want_io == WANT_READ) {
492 FD_SET(connection->fd, read_fd_set);
493 ret = true;
494 }
495 if(spdylay_session_want_write(connection->session) ||
496 connection->want_io == WANT_WRITE) {
497 FD_SET(connection->fd, write_fd_set);
498 ret = true;
499 }
500 return ret;
501}
502
503/*
504 * Performs the network I/O.
505 */
506int spdy_exec_io(struct SPDY_Connection *connection)
507{
508 int rv;
509 rv = spdylay_session_recv(connection->session);
510 if(rv != 0) {
511 PRINT_INFO2("spdylay_session_recv %i", rv);
512 return rv;
513 }
514 rv = spdylay_session_send(connection->session);
515 if(rv != 0) {
516 PRINT_INFO2("spdylay_session_send %i", rv);
517 }
518 return rv;
519}
520
521/*
522 * Fetches the resource denoted by |uri|.
523 */
524struct SPDY_Connection * spdy_connect(const struct URI *uri, uint16_t port, bool is_tls)
525{
526 spdylay_session_callbacks callbacks;
527 int fd;
528 //SSL_CTX *ssl_ctx;
529 SSL *ssl=NULL;
530 //struct SPDY_Request req;
531 struct SPDY_Connection * connection;
532 int rv;
533
534 spdy_setup_spdylay_callbacks(&callbacks);
535
536 /* Establish connection and setup SSL */
537 PRINT_INFO2("connecting to %s:%i", uri->host, port);
538 fd = spdy_socket_connect_to(uri->host, port);
539 if(fd == -1) {
540 PRINT_INFO("Could not open file descriptor");
541 return NULL;//glob_opt.spdy_connection;
542 }
543
544 if(is_tls)
545 {
546 /*ssl_ctx = SSL_CTX_new(SSLv23_client_method());
547 if(ssl_ctx == NULL) {
548 spdy_dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
549 }
550 spdy_ssl_init_ssl_ctx(ssl_ctx, &spdy_proto_version);
551 */
552 ssl = SSL_new(glob_opt.ssl_ctx);
553 if(ssl == NULL) {
554 spdy_dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
555 }
556
557 //TODO non-blocking
558 /* To simplify the program, we perform SSL/TLS handshake in blocking
559 I/O. */
560 glob_opt.spdy_proto_version = 0;
561 rv = spdy_ssl_handshake(ssl, fd);
562 if(rv <= 0 || (glob_opt.spdy_proto_version != 3 && glob_opt.spdy_proto_version != 2))
563 {
564 PRINT_INFO("Closing SSL");
565 //no spdy on the other side
566 SSL_shutdown(ssl);
567 close(fd);
568 SSL_free(ssl);
569
570 return NULL;
571 }
572 }
573 else
574 {
575 glob_opt.spdy_proto_version = 3;
576 }
577
578 if(NULL == (connection = au_malloc(sizeof(struct SPDY_Connection))))
579 return NULL;
580 //memset(connection, 0 , sizeof(struct SPDY_Connection));
581
582 connection->is_tls = is_tls;
583 connection->ssl = ssl;
584 connection->want_io = IO_NONE;
585 connection->host = strdup(uri->host);
586
587 /* Here make file descriptor non-block */
588 spdy_socket_make_non_block(fd);
589 spdy_socket_set_tcp_nodelay(fd);
590
591 PRINT_INFO2("[INFO] SPDY protocol version = %d\n", glob_opt.spdy_proto_version);
592 rv = spdylay_session_client_new(&(connection->session), glob_opt.spdy_proto_version,
593 &callbacks, connection);
594 if(rv != 0) {
595 spdy_diec("spdylay_session_client_new", rv);
596 }
597
598 connection->fd = fd;
599
600 return connection;
601}
602
603void
604spdy_free_connection(struct SPDY_Connection * connection)
605{
606 if(NULL != connection)
607 {
608 spdylay_session_del(connection->session);
609 SSL_free(connection->ssl);
610 free(connection->host);
611 free(connection);
612 }
613}
614
615int
616spdy_request(const char **nv, struct Proxy *proxy)
617{
618 int ret;
619 uint16_t port;
620 struct SPDY_Connection *connection;
621
622 if(glob_opt.only_proxy)
623 {
624 connection = glob_opt.spdy_connection;
625 }
626 else
627 {
628 connection = glob_opt.spdy_connections_head;
629 while(NULL != connection)
630 {
631 if(0 == strcasecmp(proxy->uri->host, connection->host))
632 break;
633 connection = connection->next;
634 }
635
636 if(NULL == connection)
637 {
638 //connect to host
639 port = proxy->uri->port;
640 if(0 == port) port = 443;
641 connection = spdy_connect(proxy->uri, port, true);
642 if(NULL != connection)
643 {
644 DLL_insert(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection);
645 glob_opt.total_spdy_connections++;
646 }
647 else
648 connection = glob_opt.spdy_connection;
649 }
650 }
651
652 if(NULL == connection)
653 {
654 PRINT_INFO("there is no proxy!");
655 return -1;
656 }
657
658 proxy->spdy_connection = connection;
659 ret = spdylay_submit_request(connection->session, 0, nv, NULL, proxy);
660 if(ret != 0) {
661 spdy_diec("spdylay_spdy_submit_request", ret);
662 }
663 DLL_insert(connection->proxies_head, connection->proxies_tail, proxy);
664
665 return ret;
666}
667
668
669void
670spdy_get_pollfdset(struct pollfd fds[], struct SPDY_Connection *connections[], int max_size, nfds_t *real_size)
671{
672 struct SPDY_Connection *connection;
673 struct Proxy *proxy;
674
675 *real_size = 0;
676 if(max_size<1) return;
677 if(NULL != glob_opt.spdy_connection)
678 {
679 spdy_ctl_poll(&(fds[*real_size]), glob_opt.spdy_connection);
680 if(!fds[*real_size].events)
681 {
682 //PRINT_INFO("TODO drop connection");
683 glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened;
684
685 for(proxy = glob_opt.spdy_connection->proxies_head; NULL != proxy; proxy=proxy->next)
686 {
687 DLL_remove(glob_opt.spdy_connection->proxies_head, glob_opt.spdy_connection->proxies_tail, proxy);
688 proxy->spdy_active = false;
689 }
690 spdy_free_connection(glob_opt.spdy_connection);
691 glob_opt.spdy_connection = NULL;
692 }
693 else
694 {
695 fds[*real_size].fd = glob_opt.spdy_connection->fd;
696 connections[*real_size] = glob_opt.spdy_connection;
697 ++(*real_size);
698 }
699 }
700
701 connection = glob_opt.spdy_connections_head;
702
703 while(NULL != connection && *real_size < max_size)
704 {
705 assert(!glob_opt.only_proxy);
706 spdy_ctl_poll(&(fds[*real_size]), connection);
707 if(!fds[*real_size].events)
708 {
709 //PRINT_INFO("TODO drop connection");
710 glob_opt.streams_opened -= connection->streams_opened;
711 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection);
712 glob_opt.total_spdy_connections--;
713
714 for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy->next)
715 {
716 DLL_remove(connection->proxies_head, connection->proxies_tail, proxy);
717 proxy->spdy_active = false;
718 }
719 spdy_free_connection(connection);
720 }
721 else
722 {
723 fds[*real_size].fd = connection->fd;
724 connections[*real_size] = connection;
725 ++(*real_size);
726 }
727 connection = connection->next;
728 }
729
730 //, "TODO max num of conn reached; close something"
731 assert(NULL == connection);
732}
733
734
735int
736spdy_get_selectfdset(fd_set * read_fd_set,
737 fd_set * write_fd_set,
738 fd_set * except_fd_set,
739 struct SPDY_Connection *connections[], int max_size, nfds_t *real_size)
740{
741 struct SPDY_Connection *connection;
742 struct Proxy *proxy;
743 bool ret;
744 int maxfd = 0;
745
746 *real_size = 0;
747 if(max_size<1) return 0;
748 if(NULL != glob_opt.spdy_connection)
749 {
750 ret = spdy_ctl_select(read_fd_set,
751 write_fd_set,
752 except_fd_set, glob_opt.spdy_connection);
753 if(!ret)
754 {
755 //PRINT_INFO("TODO drop connection");
756 glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened;
757
758 for(proxy = glob_opt.spdy_connection->proxies_head; NULL != proxy; proxy=proxy->next)
759 {
760 DLL_remove(glob_opt.spdy_connection->proxies_head, glob_opt.spdy_connection->proxies_tail, proxy);
761 proxy->spdy_active = false;
762 }
763 spdy_free_connection(glob_opt.spdy_connection);
764 glob_opt.spdy_connection = NULL;
765 }
766 else
767 {
768 connections[*real_size] = glob_opt.spdy_connection;
769 ++(*real_size);
770 if(maxfd < glob_opt.spdy_connection->fd) maxfd = glob_opt.spdy_connection->fd;
771 }
772 }
773
774 connection = glob_opt.spdy_connections_head;
775
776 while(NULL != connection && *real_size < max_size)
777 {
778 assert(!glob_opt.only_proxy);
779 ret = spdy_ctl_select(read_fd_set,
780 write_fd_set,
781 except_fd_set, connection);
782 if(!ret)
783 {
784 //PRINT_INFO("TODO drop connection");
785 glob_opt.streams_opened -= connection->streams_opened;
786 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection);
787 glob_opt.total_spdy_connections--;
788
789 for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy->next)
790 {
791 DLL_remove(connection->proxies_head, connection->proxies_tail, proxy);
792 proxy->spdy_active = false;
793 }
794 spdy_free_connection(connection);
795 }
796 else
797 {
798 connections[*real_size] = connection;
799 ++(*real_size);
800 if(maxfd < connection->fd) maxfd = connection->fd;
801 }
802 connection = connection->next;
803 }
804
805 //, "TODO max num of conn reached; close something"
806 assert(NULL == connection);
807
808 return maxfd;
809}
810
811
812void
813spdy_run(struct pollfd fds[], struct SPDY_Connection *connections[], int size)
814{
815 int i;
816 int ret;
817 struct Proxy *proxy;
818 //PRINT_INFO2("size is %i", size);
819
820 for(i=0; i<size; ++i)
821 {
822 // PRINT_INFO2("exec about to be called for %s", connections[i]->host);
823 if(fds[i].revents & (POLLIN | POLLOUT))
824 {
825 ret = spdy_exec_io(connections[i]);
826 //PRINT_INFO2("%i",ret);
827 //if((spdy_pollfds[i].revents & POLLHUP) || (spdy_pollfds[0].revents & POLLERR))
828 // PRINT_INFO("SPDY SPDY_Connection error");
829
830 //TODO POLLRDHUP
831 // always close on ret != 0?
832
833 if(0 != ret)
834 {
835 glob_opt.streams_opened -= connections[i]->streams_opened;
836 if(connections[i] == glob_opt.spdy_connection)
837 {
838 glob_opt.spdy_connection = NULL;
839 }
840 else
841 {
842 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]);
843 glob_opt.total_spdy_connections--;
844 }
845 for(proxy = connections[i]->proxies_head; NULL != proxy; proxy=proxy->next)
846 {
847 DLL_remove(connections[i]->proxies_head, connections[i]->proxies_tail, proxy);
848 proxy->spdy_active = false;
849 }
850 spdy_free_connection(connections[i]);
851 }
852 }
853 else
854 {
855 PRINT_INFO("not called");
856 }
857 }
858}
859
860void
861spdy_run_select(fd_set * read_fd_set,
862 fd_set * write_fd_set,
863 fd_set * except_fd_set, struct SPDY_Connection *connections[], int size)
864{
865 int i;
866 int ret;
867 struct Proxy *proxy;
868 //PRINT_INFO2("size is %i", size);
869
870 for(i=0; i<size; ++i)
871 {
872 // PRINT_INFO2("exec about to be called for %s", connections[i]->host);
873 if(FD_ISSET(connections[i]->fd, read_fd_set) || FD_ISSET(connections[i]->fd, write_fd_set) || FD_ISSET(connections[i]->fd, except_fd_set))
874 {
875 ret = spdy_exec_io(connections[i]);
876 //PRINT_INFO2("%i",ret);
877 //if((spdy_pollfds[i].revents & POLLHUP) || (spdy_pollfds[0].revents & POLLERR))
878 // PRINT_INFO("SPDY SPDY_Connection error");
879
880 //TODO POLLRDHUP
881 // always close on ret != 0?
882
883 if(0 != ret)
884 {
885 glob_opt.streams_opened -= connections[i]->streams_opened;
886 if(connections[i] == glob_opt.spdy_connection)
887 {
888 glob_opt.spdy_connection = NULL;
889 }
890 else
891 {
892 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]);
893 glob_opt.total_spdy_connections--;
894 }
895 for(proxy = connections[i]->proxies_head; NULL != proxy; proxy=proxy->next)
896 {
897 DLL_remove(connections[i]->proxies_head, connections[i]->proxies_tail, proxy);
898 proxy->spdy_active = false;
899 }
900 spdy_free_connection(connections[i]);
901 }
902 }
903 else
904 {
905 PRINT_INFO("not called");
906 }
907 }
908}