예제 #1
0
파일: session.c 프로젝트: Chris112/sep
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);
	}
}
예제 #2
0
void
spdy_free_connection(struct SPDY_Connection * connection)
{
  struct Proxy *proxy;
  struct Proxy *proxy_next;

  if(NULL != connection)
  {
    for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy_next)
    {
      proxy_next = proxy->next;
      DLL_remove(connection->proxies_head, connection->proxies_tail, proxy);
      proxy->spdy_active = false;
      proxy->spdy_error = true;
      PRINT_INFO2("spdy_free_connection for id %i", proxy->id);
      if(!proxy->http_active)
      {
        free_proxy(proxy);
      }
    }
    spdylay_session_del(connection->session);
    SSL_free(connection->ssl);
    free(connection->host);
    free(connection);
    //connection->session = NULL;
  }
}
예제 #3
0
/*
 * The implementation of spdylay_on_stream_close_callback type. We use
 * this function to know the response is fully received. Since we just
 * fetch 1 resource in this program, after reception of the response,
 * we submit GOAWAY and close the session.
 */
static void
spdy_cb_on_stream_close(spdylay_session *session,
                       int32_t stream_id,
                       spdylay_status_code status_code,
                       void *user_data)
{
  (void)status_code;
  (void)user_data;

  struct Proxy * proxy = spdylay_session_get_stream_user_data(session, stream_id);

  assert(NULL != proxy);

  --glob_opt.streams_opened;
  --proxy->spdy_connection->streams_opened;
  PRINT_INFO2("closing stream: str opened %i; remove proxy %i", glob_opt.streams_opened, proxy->id);

  DLL_remove(proxy->spdy_connection->proxies_head, proxy->spdy_connection->proxies_tail, proxy);
  if(proxy->http_active)
  {
    proxy->spdy_active = false;
  }
  else
  {
    free_proxy(proxy);
  }
}
예제 #4
0
파일: session.c 프로젝트: Chris112/sep
void
SPDYF_session_destroy(struct SPDY_Session *session)
{
	struct SPDYF_Stream *stream;
	struct SPDYF_Response_Queue *response_queue;
	
	(void)close (session->socket_fd);
	SPDYF_zlib_deflate_end(&session->zlib_send_stream);
	SPDYF_zlib_inflate_end(&session->zlib_recv_stream);
	
	//clean up unsent data in the output queue
	while (NULL != (response_queue = session->response_queue_head))
	{
		DLL_remove (session->response_queue_head,
			session->response_queue_tail,
			response_queue);
			
		if(NULL != response_queue->frqcb)
		{
			response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_SESSION_CLOSED);
		}

		SPDYF_response_queue_destroy(response_queue);
	}

	//clean up the streams belonging to this session
	while (NULL != (stream = session->streams_head))
	{
		DLL_remove (session->streams_head,
			session->streams_tail,
			stream);
		
		SPDYF_stream_destroy(stream);
	}

	free(session->addr);
	free(session->read_buffer);
	free(session->write_buffer);
	free(session);
}
예제 #5
0
void
spdy_run_select(fd_set * read_fd_set,
                fd_set * write_fd_set,
                fd_set * except_fd_set,
                struct SPDY_Connection *connections[],
                int size)
{
  int i;
  int ret;

  for(i=0; i<size; ++i)
  {
    //  PRINT_INFO2("exec about to be called for %s", connections[i]->host);
    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))
    {
      //raise(SIGINT);
      ret = spdy_exec_io(connections[i]);

      if(0 != ret)
      {
        glob_opt.streams_opened -= connections[i]->streams_opened;
        if(connections[i] == glob_opt.spdy_connection)
        {
          glob_opt.spdy_connection = NULL;
        }
        else
        {
          DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]);
          glob_opt.total_spdy_connections--;
        }
        PRINT_INFO("in spdy_run_select");
        spdy_free_connection(connections[i]);
      }
    }
    else
    {
      PRINT_INFO("not called");
      //PRINT_INFO2("connection->want_io %i",connections[i]->want_io);
      //PRINT_INFO2("read %i",spdylay_session_want_read(connections[i]->session));
      //PRINT_INFO2("write %i",spdylay_session_want_write(connections[i]->session));
      //raise(SIGINT);
    }
  }
}
예제 #6
0
파일: session.c 프로젝트: Chris112/sep
int
SPDYF_session_write (struct SPDY_Session *session,
                     bool only_one_frame)
{
	unsigned int i;
	int bytes_written;
	struct SPDYF_Response_Queue *queue_head;
	struct SPDYF_Response_Queue *response_queue;
	
	if(SPDY_SESSION_STATUS_CLOSING == session->status)
		return SPDY_NO;
    
  if(SPDY_NO == session->fio_before_write(session))
    return SPDY_NO;
	
	for(i=0;
		only_one_frame
		? i < 1
		: i < session->max_num_frames;
		++i)
	{
		//if the buffer is not null, part of the last frame is still
		//pending to be sent
		if(NULL == session->write_buffer)
		{
			//discard frames on closed streams
			response_queue = session->response_queue_head;
			
			while(NULL != response_queue)
			{
				//if stream is closed, remove not yet sent frames
				//associated with it
				//GOAWAY frames are not associated to streams
				//and still need to be sent
				if(NULL == response_queue->stream
					|| !response_queue->stream->is_out_closed)
					break;
						
				DLL_remove(session->response_queue_head,session->response_queue_tail,response_queue);
				
				if(NULL != response_queue->frqcb)
				{
					response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_STREAM_CLOSED);
				}
				
				SPDYF_response_queue_destroy(response_queue);
				response_queue = session->response_queue_head;
			}
			
			if(NULL == session->response_queue_head)
				break;//nothing on the queue
				
			//get next data from queue and put it to the write buffer
			// to send it
			if(SPDY_NO == session->response_queue_head->process_response_handler(session))
			{
				//error occured and the handler changed or not the
				//session's status appropriately
				if(SPDY_SESSION_STATUS_CLOSING == session->status)
				{
					//try to send GOAWAY first if the current frame is different
					if(session->response_queue_head->is_data
						|| SPDY_CONTROL_FRAME_TYPES_GOAWAY
							!= session->response_queue_head->control_frame->type)
					{
						session->status = SPDY_SESSION_STATUS_FLUSHING;
						SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, true);
						SPDYF_session_write(session,true);
						session->status = SPDY_SESSION_STATUS_CLOSING;
					}
					return SPDY_YES;
				}
				
				//just return from the loop to return from this function
        ++i;
				break;
			}
			
			//check if something was prepared for writing
			//on respones with callbacks it is possible that their is no
			//data available 
			if(0 == session->write_buffer_size)//nothing to write
      {
				if(response_queue != session->response_queue_head)
				{
					//the handler modified the queue
					continue;
				}
				else
				{
					//no need to try the same frame again
          ++i;
					break;
				}
      }
		}

		session->last_activity = SPDYF_monotonic_time();
		
		//actual write to the IO
		bytes_written = session->fio_send(session,
			session->write_buffer + session->write_buffer_beginning,
			session->write_buffer_offset - session->write_buffer_beginning);
			
		switch(bytes_written)
		{
			case SPDY_IO_ERROR_CLOSED:
				//The TLS connection was closed by the other party, clean 
				//or not
				shutdown (session->socket_fd, SHUT_RD);
				session->read_closed = true;
				session->status = SPDY_SESSION_STATUS_CLOSING;
				return SPDY_YES;
				
			case SPDY_IO_ERROR_ERROR:
				//any kind of error in the TLS subsystem
				//forbid more writing
				session->status = SPDY_SESSION_STATUS_CLOSING;
				return SPDY_YES;
				
			case SPDY_IO_ERROR_AGAIN:
				//read or write should be called again; leave it for the
				//next time; return from the function as we do not now
				//whether reading or writing is needed
				return i>0 ? SPDY_YES : SPDY_NO;
				
			//default:
				//something was really read from the TLS subsystem
				//just continue
		}
		
		session->write_buffer_beginning += bytes_written;
		
		//check if the full buffer was written
		if(session->write_buffer_beginning == session->write_buffer_size)
		{
			//that response is handled, remove it from queue
      free(session->write_buffer);
			session->write_buffer = NULL;
			session->write_buffer_size = 0;
			queue_head = session->response_queue_head;
			if(NULL == queue_head->next)
			{
				session->response_queue_head = NULL;
				session->response_queue_tail = NULL;
			}
			else
			{
				session->response_queue_head = queue_head->next;
				session->response_queue_head->prev = NULL;
			}
			
			//set stream to closed if the frame's fin flag is set
			SPDYF_stream_set_flags_on_write(queue_head);
			
			if(NULL != queue_head->frqcb)
			{
				//application layer callback to notify sending of the response
				queue_head->frqcb(queue_head->frqcb_cls, queue_head, SPDY_RESPONSE_RESULT_SUCCESS);
			}
			
			SPDYF_response_queue_destroy(queue_head);
		}
	}

	if(SPDY_SESSION_STATUS_FLUSHING == session->status
		&& NULL == session->response_queue_head)
		session->status = SPDY_SESSION_STATUS_CLOSING;
	
	//return i>0 ? SPDY_YES : SPDY_NO;
	return session->fio_after_write(session, i>0 ? SPDY_YES : SPDY_NO);
}
예제 #7
0
/**
 * 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;
}
예제 #8
0
int
spdy_get_selectfdset(fd_set * read_fd_set,
                      fd_set * write_fd_set,
                      fd_set * except_fd_set,
                      struct SPDY_Connection *connections[],
                      unsigned int max_size,
                      nfds_t *real_size)
{
  struct SPDY_Connection *connection;
  struct SPDY_Connection *next_connection;
  bool ret;
  int maxfd = 0;

  *real_size = 0;
  if(max_size<1)
    return 0;

  if(NULL != glob_opt.spdy_connection)
  {
    ret = spdy_ctl_select(read_fd_set,
				 write_fd_set,
				 except_fd_set, glob_opt.spdy_connection);
    if(!ret)
    {
      glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened;

      PRINT_INFO("spdy_free_connection in spdy_get_selectfdset");
      spdy_free_connection(glob_opt.spdy_connection);
      glob_opt.spdy_connection = NULL;
    }
    else
    {
      connections[*real_size] = glob_opt.spdy_connection;
      ++(*real_size);
      if(maxfd < glob_opt.spdy_connection->fd) maxfd = glob_opt.spdy_connection->fd;
    }
  }

  connection = glob_opt.spdy_connections_head;

  while(NULL != connection && *real_size < max_size)
  {
    assert(!glob_opt.only_proxy);
    ret = spdy_ctl_select(read_fd_set,
				 write_fd_set,
				 except_fd_set, connection);

    next_connection = connection->next;
    if(!ret)
    {
      glob_opt.streams_opened -= connection->streams_opened;
      DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection);
      glob_opt.total_spdy_connections--;

      PRINT_INFO("spdy_free_connection in spdy_get_selectfdset");
      spdy_free_connection(connection);
    }
    else
    {
      connections[*real_size] = connection;
      ++(*real_size);
      if(maxfd < connection->fd) maxfd = connection->fd;
    }
    connection = next_connection;
  }

  //, "TODO max num of conn reached; close something"
  assert(NULL == connection);

  return maxfd;
}