GNU libmicrohttpd  0.9.29
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
daemon.c
Go to the documentation of this file.
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 
25 #include "platform.h"
26 #include "structures.h"
27 #include "internal.h"
28 #include "session.h"
29 #include "io.h"
30 
31 
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 
59 
60 
65 
66 
73 static void
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 
94 static void
96 {
97  struct SPDY_Session *session;
98 
99  while (NULL != (session = daemon->sessions_head))
100  {
101  //prepare GOAWAY frame
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 
119 static int
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  {
137  daemon->session_timeout = va_arg (valist, unsigned int) * 1000;
138  break;
140  daemon->address = va_arg (valist, struct sockaddr *);
141  break;
143  daemon->flags = va_arg (valist, enum SPDY_DAEMON_FLAG);
144  break;
146  daemon->io_subsystem = va_arg (valist, enum SPDY_IO_SUBSYSTEM);
147  break;
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
162  void *cls)
163 {
164  spdyf_panic = cb;
165  spdyf_panic_cls = cls;
166 }
167 
168 
169 struct SPDY_Daemon *
171  const char *certfile,
172  const char *keyfile,
176  SPDY_NewDataCallback npdcb,
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)
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)
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)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
374 {
375  daemon->fio_deinit(daemon);
376 
377  shutdown (daemon->socket_fd, SHUT_RDWR);
378  spdyf_close_all_sessions (daemon);
379  (void)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
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
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
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 }
SPDY_NewSessionCallback new_session_cb
Definition: structures.h:909
struct SPDY_Daemon * SPDYF_start_daemon_va(uint16_t port, const char *certfile, const char *keyfile, SPDY_NewSessionCallback nscb, SPDY_SessionClosedCallback sccb, SPDY_NewRequestCallback nrcb, SPDY_NewDataCallback npdcb, SPDYF_NewStreamCallback fnscb, SPDYF_NewDataCallback fndcb, void *cls, void *fcls, va_list valist)
Definition: daemon.c:170
static int spdyf_parse_options_va(struct SPDY_Daemon *daemon, va_list valist)
Definition: daemon.c:120
uint16_t port
Definition: structures.h:996
int SPDYF_get_fdset(struct SPDY_Daemon *daemon, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, bool all)
Definition: daemon.c:432
int SPDYF_get_timeout(struct SPDY_Daemon *daemon, unsigned long long *timeout)
Definition: daemon.c:392
SPDY_DAEMON_OPTION
Definition: microspdy.h:346
SPDY_PanicCallback spdyf_panic
Definition: daemon.c:58
#define NULL
Definition: reason_phrase.c:31
struct SPDY_Daemon * daemon
Definition: structures.h:633
#define SPDY_YES
Definition: microspdy.h:93
unsigned long long session_timeout
Definition: structures.h:961
void * cls
Definition: structures.h:935
struct SPDY_Session * next
Definition: structures.h:623
#define DLL_remove(head, tail, element)
Definition: internal.h:1306
int SPDYF_session_read(struct SPDY_Session *session)
Definition: session.c:866
void * fcls
Definition: structures.h:945
SPDYF_IODeinit fio_deinit
Definition: structures.h:955
struct SPDYF_Response_Queue * response_queue_head
Definition: structures.h:660
int SPDYF_prepare_goaway(struct SPDY_Session *session, enum SPDY_GOAWAY_STATUS status, bool in_front)
Definition: session.c:1617
TCP connection/SPDY session handling.
SPDY_NewRequestCallback new_request_cb
Definition: structures.h:919
void(* SPDY_NewSessionCallback)(void *cls, struct SPDY_Session *session)
Definition: microspdy.h:606
void(* SPDY_PanicCallback)(void *cls, const char *file, unsigned int line, const char *reason)
Definition: microspdy.h:592
SPDYF_IOInit fio_init
Definition: structures.h:950
struct sockaddr * address
Definition: structures.h:903
internal functions and macros for the framing layer
void(* SPDY_NewRequestCallback)(void *cls, struct SPDY_Request *request, uint8_t priority, const char *method, const char *path, const char *version, const char *host, const char *scheme, struct SPDY_NameValue *headers, bool more)
Definition: microspdy.h:670
void * write_buffer
Definition: structures.h:675
SPDY_SessionClosedCallback session_closed_cb
Definition: structures.h:914
platform-specific includes for libmicrohttpd
uint32_t max_num_frames
Definition: structures.h:976
unsigned long long last_activity
Definition: structures.h:776
internal and public structures – most of the structs used by the library are defined here ...
Signatures for IO functions.
enum SPDY_IO_SUBSYSTEM io_subsystem
Definition: structures.h:991
char * keyfile
Definition: structures.h:897
#define SPDYF_NUM_SENT_FRAMES_AT_ONCE
Definition: internal.h:49
#define SPDY_NO
Definition: microspdy.h:98
void SPDYF_session_close(struct SPDY_Session *session)
Definition: session.c:1360
int(* SPDYF_NewStreamCallback)(void *cls, struct SPDYF_Stream *stream)
Definition: structures.h:352
struct SPDY_Session * cleanup_head
Definition: structures.h:876
unsigned long long SPDYF_monotonic_time(void)
Definition: internal.c:30
void(* SPDY_SessionClosedCallback)(void *cls, struct SPDY_Session *session, int by_client)
Definition: microspdy.h:623
int SPDYF_session_write(struct SPDY_Session *session, bool only_one_frame)
Definition: session.c:981
void * spdyf_panic_cls
Definition: daemon.c:64
static void spdyf_panic_std(void *cls, const char *file, unsigned int line, const char *reason)
Definition: daemon.c:42
char * certfile
Definition: structures.h:891
void SPDYF_session_destroy(struct SPDY_Session *session)
Definition: session.c:1575
int(* SPDY_NewDataCallback)(void *cls, struct SPDY_Request *request, const void *buf, size_t size, bool more)
Definition: microspdy.h:698
void SPDYF_stop_daemon(struct SPDY_Daemon *daemon)
Definition: daemon.c:373
enum SPDY_DAEMON_OPTION options
Definition: structures.h:981
struct SPDY_Session * sessions_head
Definition: structures.h:866
void SPDY_set_panic_func(SPDY_PanicCallback cb, void *cls)
Definition: daemon.c:161
#define SPDYF_DEBUG(fmt,...)
Definition: internal.h:154
SPDYF_NewStreamCallback fnew_stream_cb
Definition: structures.h:940
static void spdyf_cleanup_sessions(struct SPDY_Daemon *daemon)
Definition: daemon.c:74
size_t read_buffer_beginning
Definition: structures.h:753
enum SPDY_SESSION_STATUS status
Definition: structures.h:831
struct SPDY_Session * cleanup_tail
Definition: structures.h:881
void SPDYF_run(struct SPDY_Daemon *daemon)
Definition: daemon.c:474
int SPDYF_session_accept(struct SPDY_Daemon *daemon)
Definition: session.c:1389
SPDY_DAEMON_FLAG
Definition: microspdy.h:401
int SPDYF_io_set_daemon(struct SPDY_Daemon *daemon, enum SPDY_IO_SUBSYSTEM io_subsystem)
Definition: io.c:32
static void spdyf_close_all_sessions(struct SPDY_Daemon *daemon)
Definition: daemon.c:95
int(* SPDYF_NewDataCallback)(void *cls, struct SPDYF_Stream *stream, const void *buf, size_t size, bool more)
Definition: structures.h:335
enum SPDY_DAEMON_FLAG flags
Definition: structures.h:986
SPDYF_IOIsPending fio_is_pending
Definition: structures.h:716
size_t read_buffer_offset
Definition: structures.h:748
SPDY_IO_SUBSYSTEM
Definition: microspdy.h:318
int SPDYF_session_idle(struct SPDY_Session *session)
Definition: session.c:1155
SPDYF_NewDataCallback freceived_data_cb
Definition: structures.h:930
SPDY_NewDataCallback received_data_cb
Definition: structures.h:925