Beispiel #1
0
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);
	}
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #5
0
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;
}