void SPDYF_session_close (struct SPDY_Session *session) { struct SPDY_Daemon *daemon = session->daemon; int by_client = session->read_closed ? SPDY_YES : SPDY_NO; //shutdown the tls and deinit the tls context session->fio_close_session(session); shutdown (session->socket_fd, session->read_closed ? SHUT_WR : SHUT_RDWR); session->read_closed = true; //remove session from the list DLL_remove (daemon->sessions_head, daemon->sessions_tail, session); //add the session for the list for cleaning up DLL_insert (daemon->cleanup_head, daemon->cleanup_tail, session); //call callback for closed session if(NULL != daemon->session_closed_cb) { daemon->session_closed_cb(daemon->cls, session, by_client); } }
int SPDYF_session_accept(struct SPDY_Daemon *daemon) { int new_socket_fd; int ret; struct SPDY_Session *session = NULL; socklen_t addr_len; struct sockaddr *addr; #if HAVE_INET6 struct sockaddr_in6 addr6; addr = (struct sockaddr *)&addr6; addr_len = sizeof(addr6); #else struct sockaddr_in addr4; addr = (struct sockaddr *)&addr4; addr_len = sizeof(addr6); #endif new_socket_fd = accept (daemon->socket_fd, addr, &addr_len); if(new_socket_fd < 1) return SPDY_NO; if (NULL == (session = malloc (sizeof (struct SPDY_Session)))) { goto free_and_fail; } memset (session, 0, sizeof (struct SPDY_Session)); session->daemon = daemon; session->socket_fd = new_socket_fd; session->max_num_frames = daemon->max_num_frames; ret = SPDYF_io_set_session(session, daemon->io_subsystem); SPDYF_ASSERT(SPDY_YES == ret, "Somehow daemon->io_subsystem iswrong here"); //init TLS context, handshake will be done if(SPDY_YES != session->fio_new_session(session)) { goto free_and_fail; } //read buffer session->read_buffer_size = SPDYF_BUFFER_SIZE; if (NULL == (session->read_buffer = malloc (session->read_buffer_size))) { session->fio_close_session(session); goto free_and_fail; } //address of the client if (NULL == (session->addr = malloc (addr_len))) { session->fio_close_session(session); goto free_and_fail; } memcpy (session->addr, addr, addr_len); session->addr_len = addr_len; session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; //init zlib context for the whole session if(SPDY_YES != SPDYF_zlib_deflate_init(&session->zlib_send_stream)) { session->fio_close_session(session); goto free_and_fail; } if(SPDY_YES != SPDYF_zlib_inflate_init(&session->zlib_recv_stream)) { session->fio_close_session(session); SPDYF_zlib_deflate_end(&session->zlib_send_stream); goto free_and_fail; } //add it to daemon's list DLL_insert(daemon->sessions_head,daemon->sessions_tail,session); session->last_activity = SPDYF_monotonic_time(); if(NULL != daemon->new_session_cb) daemon->new_session_cb(daemon->cls, session); return SPDY_YES; //for GOTO free_and_fail: /* something failed, so shutdown, close and free memory */ shutdown (new_socket_fd, SHUT_RDWR); (void)close (new_socket_fd); if(NULL != session) { if(NULL != session->addr) free (session->addr); if(NULL != session->read_buffer) free (session->read_buffer); free (session); } return SPDY_NO; }
int SPDYF_stream_new (struct SPDY_Session *session) { uint32_t stream_id; uint32_t assoc_stream_id; uint8_t priority; uint8_t slot; size_t buffer_pos = session->read_buffer_beginning; struct SPDYF_Stream *stream; struct SPDYF_Control_Frame *frame; if((session->read_buffer_offset - session->read_buffer_beginning) < 10) { //not all fields are received to create new stream return SPDY_NO; } frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls; //get stream id of the new stream memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4); stream_id = NTOH31(stream_id); session->read_buffer_beginning += 4; if(stream_id <= session->last_in_stream_id || 0==(stream_id % 2)) { //wrong stream id sent by client //GOAWAY with PROTOCOL_ERROR MUST be sent //TODO //ignore frame session->frame_handler = &SPDYF_handler_ignore_frame; return SPDY_NO; } else if(session->is_goaway_sent) { //the client is not allowed to create new streams anymore //we MUST ignore the frame session->frame_handler = &SPDYF_handler_ignore_frame; return SPDY_NO; } //set highest stream id for session session->last_in_stream_id = stream_id; //get assoc stream id of the new stream //this value is used with SPDY PUSH, thus nothing to do with it here memcpy(&assoc_stream_id, session->read_buffer + session->read_buffer_beginning, 4); assoc_stream_id = NTOH31(assoc_stream_id); session->read_buffer_beginning += 4; //get stream priority (3 bits) //after it there are 5 bits that are not used priority = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning) >> 5; session->read_buffer_beginning++; //get slot (see SPDY draft) slot = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning); session->read_buffer_beginning++; if(NULL == (stream = malloc(sizeof(struct SPDYF_Stream)))) { SPDYF_DEBUG("No memory"); //revert buffer state session->read_buffer_beginning = buffer_pos; return SPDY_NO; } memset(stream,0, sizeof(struct SPDYF_Stream)); stream->session = session; stream->stream_id = stream_id; stream->assoc_stream_id = assoc_stream_id; stream->priority = priority; stream->slot = slot; stream->is_in_closed = (frame->flags & SPDY_SYN_STREAM_FLAG_FIN) != 0; stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0; stream->is_out_closed = stream->flag_unidirectional; stream->is_server_initiator = false; stream->window_size = SPDYF_INITIAL_WINDOW_SIZE; //put the stream to the list of streams for the session DLL_insert(session->streams_head, session->streams_tail, stream); return SPDY_YES; }
/** * Run through the suspended connections and move any that are no * longer suspended back to the active state. * * @remark To be called only from thread that process * daemon's select()/poll()/etc. * * @param daemon daemon context * @return true if a connection was actually resumed */ bool MHD_resume_suspended_connections_ (struct MHD_Daemon *daemon) /* FIXME: rename connections -> requests? */ { struct MHD_Connection *pos; struct MHD_Connection *prev = NULL; bool ret; const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode); mhd_assert (NULL == daemon->worker_pool); ret = false; MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); if (daemon->resuming) { prev = daemon->suspended_connections_tail; /* During shutdown check for resuming is forced. */ mhd_assert((NULL != prev) || (daemon->shutdown)); } daemon->resuming = false; while (NULL != (pos = prev)) { #ifdef UPGRADE_SUPPORT struct MHD_UpgradeResponseHandle * const urh = pos->request.urh; #else /* ! UPGRADE_SUPPORT */ static const void * const urh = NULL; #endif /* ! UPGRADE_SUPPORT */ prev = pos->prev; if ( (! pos->resuming) #ifdef UPGRADE_SUPPORT || ( (NULL != urh) && ( (! urh->was_closed) || (! urh->clean_ready) ) ) #endif /* UPGRADE_SUPPORT */ ) continue; ret = true; mhd_assert (pos->suspended); DLL_remove (daemon->suspended_connections_head, daemon->suspended_connections_tail, pos); pos->suspended = false; if (NULL == urh) { DLL_insert (daemon->connections_head, daemon->connections_tail, pos); if (! used_thr_p_c) { /* Reset timeout timer on resume. */ if (0 != pos->connection_timeout) pos->last_activity = MHD_monotonic_sec_counter(); if (pos->connection_timeout == daemon->connection_default_timeout) XDLL_insert (daemon->normal_timeout_head, daemon->normal_timeout_tail, pos); else XDLL_insert (daemon->manual_timeout_head, daemon->manual_timeout_tail, pos); } #ifdef EPOLL_SUPPORT if (MHD_ELS_EPOLL == daemon->event_loop_syscall) { if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) MHD_PANIC ("Resumed connection was already in EREADY set\n"); /* we always mark resumed connections as ready, as we might have missed the edge poll event during suspension */ EDLL_insert (daemon->eready_head, daemon->eready_tail, pos); pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL | \ MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY; pos->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED; } #endif } #ifdef UPGRADE_SUPPORT else { struct MHD_Response *response = pos->request.response; /* Data forwarding was finished (for TLS connections) AND * application was closed upgraded connection. * Insert connection into cleanup list. */ if ( (NULL != response) && (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_mode) && (NULL != response->termination_cb) ) response->termination_cb (response->termination_cb_cls, MHD_REQUEST_TERMINATED_COMPLETED_OK, &pos->request.client_context); DLL_insert (daemon->cleanup_head, daemon->cleanup_tail, pos); } #endif /* UPGRADE_SUPPORT */ pos->resuming = false; } MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); if ( (used_thr_p_c) && (ret) ) { /* Wake up suspended connections. */ if (! MHD_itc_activate_(daemon->itc, "w")) { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, MHD_SC_ITC_USE_FAILED, _("Failed to signal resume of connection via inter-thread communication channel.")); #endif } } return ret; }
int spdy_request(const char **nv, struct Proxy *proxy, bool with_body) { int ret; uint16_t port; struct SPDY_Connection *connection; spdylay_data_provider post_data; if(glob_opt.only_proxy) { connection = glob_opt.spdy_connection; } else { connection = glob_opt.spdy_connections_head; while(NULL != connection) { if(0 == strcasecmp(proxy->uri->host, connection->host)) break; connection = connection->next; } if(NULL == connection) { //connect to host port = proxy->uri->port; if(0 == port) port = 443; connection = spdy_connect(proxy->uri, port, true); if(NULL != connection) { DLL_insert(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection); glob_opt.total_spdy_connections++; } else connection = glob_opt.spdy_connection; } } if(NULL == connection) { PRINT_INFO("there is no proxy!"); return -1; } proxy->spdy_connection = connection; if(with_body) { post_data.source.ptr = proxy; post_data.read_callback = &spdy_cb_data_source_read; ret = spdylay_submit_request(connection->session, 0, nv, &post_data, proxy); } else ret = spdylay_submit_request(connection->session, 0, nv, NULL, proxy); if(ret != 0) { spdy_diec("spdylay_spdy_submit_request", ret); } PRINT_INFO2("adding proxy %i", proxy->id); if(NULL != connection->proxies_head) PRINT_INFO2("before proxy %i", connection->proxies_head->id); DLL_insert(connection->proxies_head, connection->proxies_tail, proxy); return ret; }