示例#1
0
static void
spdy_cb_before_ctrl_send(spdylay_session *session,
                    spdylay_frame_type type,
                    spdylay_frame *frame,
                    void *user_data)
{
  (void)user_data;

  int32_t stream_id;
  struct Proxy *proxy;

  switch(type) {
    case SPDYLAY_SYN_STREAM:
      stream_id = frame->syn_stream.stream_id;
      proxy = spdylay_session_get_stream_user_data(session, stream_id);
      proxy->stream_id = stream_id;
      ++glob_opt.streams_opened;
      ++proxy->spdy_connection->streams_opened;
      PRINT_INFO2("opening stream: str open %i; %s", glob_opt.streams_opened, proxy->url);
      break;
    case SPDYLAY_RST_STREAM:
      //try to ignore duplicate RST_STREAMs
      //TODO this will ignore RST_STREAMs also for bogus data
      glob_opt.ignore_rst_stream = NULL==spdylay_session_get_stream_user_data(session, frame->rst_stream.stream_id);
      PRINT_INFO2("sending RST_STREAM for %i; ignore %i; status %i",
        frame->rst_stream.stream_id,
        glob_opt.ignore_rst_stream,
        frame->rst_stream.status_code);
    break;
    default:
      break;
  }
}
示例#2
0
void
spdy_cb_on_ctrl_recv(spdylay_session *session,
                    spdylay_frame_type type,
                    spdylay_frame *frame,
                    void *user_data)
{
  (void)user_data;

  char **nv;
  int32_t stream_id;
  struct Proxy * proxy;

  switch(type) {
    case SPDYLAY_SYN_REPLY:
      nv = frame->syn_reply.nv;
      stream_id = frame->syn_reply.stream_id;
    break;
    case SPDYLAY_RST_STREAM:
      stream_id = frame->rst_stream.stream_id;
    break;
    case SPDYLAY_HEADERS:
      nv = frame->headers.nv;
      stream_id = frame->headers.stream_id;
    break;
    default:
      return;
    break;
  }

  proxy = spdylay_session_get_stream_user_data(session, stream_id);
  if(NULL == proxy)
  {
    PRINT_INFO2("received frame type %i for unkonwn stream id %i", type, stream_id);
    return;
    //DIE("no proxy obj");
  }

  switch(type) {
    case SPDYLAY_SYN_REPLY:
      PRINT_INFO2("received headers for %s", proxy->url);
      http_create_response(proxy, nv);
    break;
    case SPDYLAY_RST_STREAM:
      PRINT_INFO2("received reset stream for %s", proxy->url);
      proxy->spdy_error = true;
    break;
    case SPDYLAY_HEADERS:
      PRINT_INFO2("received headers for %s", proxy->url);
      http_create_response(proxy, nv);
    break;
    default:
      return;
    break;
  }

  glob_opt.spdy_data_received = true;
}
示例#3
0
void
http_cb_request_completed (void *cls,
                                   struct MHD_Connection *connection,
                                   void **con_cls,
                                   enum MHD_RequestTerminationCode toe)
{
  (void)cls;
  (void)connection;
  struct HTTP_URI *http_uri;
  struct Proxy *proxy;
  
  http_uri = (struct HTTP_URI *)*con_cls;
  if(NULL == http_uri)
    return;
  proxy = (struct Proxy *)http_uri->proxy;
  assert(NULL != proxy);
  
  PRINT_INFO2("http_cb_request_completed %i for %s; id %i",toe, http_uri->uri, proxy->id);
  
  if(NULL != proxy->http_response)
  {
    MHD_destroy_response (proxy->http_response);
    proxy->http_response = NULL;
  }
  
  if(proxy->spdy_active)
  {
    proxy->http_active = false;
    if(MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
    {
      proxy->http_error = true;
      if(proxy->stream_id > 0 /*&& NULL != proxy->spdy_connection->session*/)
      {
        //send RST_STREAM_STATUS_CANCEL
        PRINT_INFO2("send rst_stream %i %i",proxy->spdy_active, proxy->stream_id );
        spdylay_submit_rst_stream(proxy->spdy_connection->session, proxy->stream_id, 5);
      }
      /*else
      {
        DLL_remove(proxy->spdy_connection->proxies_head, proxy->spdy_connection->proxies_tail, proxy); 
        free_proxy(proxy);
      }*/
    }
  }
  else
  {
    PRINT_INFO2("proxy free http id %i ", proxy->id);
    free_proxy(proxy);
  }
    
  --glob_opt.responses_pending;
}
示例#4
0
static void
response_done_callback(void *cls,
						struct SPDY_Response *response,
						struct SPDY_Request *request,
						enum SPDY_RESPONSE_RESULT status,
						bool streamopened)
{
	(void)streamopened;
	struct Proxy *proxy = (struct Proxy *)cls;
	int ret;
	
	if(SPDY_RESPONSE_RESULT_SUCCESS != status)
	{
		printf("answer was NOT sent, %i\n",status);
	}
	if(CURLM_OK != (ret = curl_multi_remove_handle(multi_handle, proxy->curl_handle)))
	{
		PRINT_INFO2("curl_multi_remove_handle failed (%i)", ret);
	}
	curl_slist_free_all(proxy->curl_headers);
	curl_easy_cleanup(proxy->curl_handle);
	
	SPDY_destroy_request(request);
	SPDY_destroy_response(response);
	free(proxy->url);
	free(proxy);
}
示例#5
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);
  }
}
示例#6
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;
  }
}
示例#7
0
void
http_create_response(struct Proxy* proxy,
                     char **nv)
{
  size_t i;
  
  if(!proxy->http_active)
    return;
  
  for(i = 0; nv[i]; i += 2) {
    if(0 == strcmp(":status", nv[i]))
    {
      char tmp[4];
      memcpy(&tmp,nv[i+1],3);
      tmp[3]=0;
      proxy->status = atoi(tmp);
      continue;
    }
    else if(0 == strcmp(":version", nv[i]))
    {
      proxy->version = nv[i+1];
      continue;
    }
    else if(0 == strcmp("content-length", nv[i]))
    {
      continue;
    }

    char *header = *(nv+i);
    if(MHD_NO == MHD_add_response_header (proxy->http_response,
                   header, nv[i+1]))
    {
      PRINT_INFO2("SPDY_name_value_add failed: '%s' '%s'", header, nv[i+1]);
    }
    PRINT_INFO2("adding '%s: %s'",header, nv[i+1]);
  }
  
  if(MHD_NO == MHD_queue_response (proxy->http_connection, proxy->status, proxy->http_response)){
    PRINT_INFO("No queue");
    //TODO
    //abort();
    proxy->http_error = true;
  }
  
  MHD_destroy_response (proxy->http_response);
  proxy->http_response = NULL;
}
示例#8
0
/*
 * Performs the network I/O.
 */
int
spdy_exec_io(struct SPDY_Connection *connection)
{
  int rv;

  rv = spdylay_session_recv(connection->session);
  if(rv != 0)
  {
    PRINT_INFO2("spdylay_session_recv %i", rv);
    return rv;
  }
  rv = spdylay_session_send(connection->session);
  if(rv != 0)
    PRINT_INFO2("spdylay_session_send %i", rv);

  return rv;
}
示例#9
0
void *
http_cb_log(void * cls,
const char * uri)
{
  (void)cls;
  
  struct HTTP_URI * http_uri;
  
  PRINT_INFO2("log uri '%s'\n", uri);
  
  //TODO not freed once in a while
  if(NULL == (http_uri = au_malloc(sizeof(struct HTTP_URI ))))
    return NULL;
  http_uri->uri = strdup(uri);
  return http_uri;
}
示例#10
0
static int
spdy_ssl_handshake(SSL *ssl,
                   int fd)
{
  int rv;

  if(SSL_set_fd(ssl, fd) == 0)
    spdy_dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));

  ERR_clear_error();
  rv = SSL_connect(ssl);
  if(rv <= 0)
    PRINT_INFO2("SSL_connect %s", ERR_error_string(ERR_get_error(), NULL));

  return rv;
}
示例#11
0
static void
spdy_cb_on_data_recv(spdylay_session *session,
		                 uint8_t flags,
                     int32_t stream_id,
                     int32_t length,
                     void *user_data)
{
  (void)length;
  (void)user_data;

	if(flags & SPDYLAY_DATA_FLAG_FIN)
	{
    struct Proxy *proxy;
    proxy = spdylay_session_get_stream_user_data(session, stream_id);
    proxy->done = true;
    PRINT_INFO2("last data frame received for %s", proxy->url);
	}
}
示例#12
0
/*
 * The implementation of spdylay_on_data_chunk_recv_callback type. We
 * use this function to print the received response body.
 */
static void
spdy_cb_on_data_chunk_recv(spdylay_session *session,
                          uint8_t flags,
                          int32_t stream_id,
                          const uint8_t *data,
                          size_t len,
                          void *user_data)
{
  (void)flags;
  (void)user_data;

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

  if(NULL == proxy)
  {
    PRINT_INFO("proxy in spdy_cb_on_data_chunk_recv is NULL)");
    return;
	}

  if(!copy_buffer(data, len, &proxy->http_body, &proxy->http_body_size))
  {
    //TODO handle it better?
    PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
    return;
  }
  /*
	if(NULL == proxy->http_body)
		proxy->http_body = au_malloc(len);
  else
		proxy->http_body = realloc(proxy->http_body, proxy->http_body_size + len);
	if(NULL == proxy->http_body)
	{
		PRINT_INFO("not enough memory (realloc returned NULL)");
		return ;
	}

	memcpy(proxy->http_body + proxy->http_body_size, data, len);
	proxy->http_body_size += len;
  */
  PRINT_INFO2("received data for %s; %zu bytes", proxy->url, len);
  glob_opt.spdy_data_received = true;
}
示例#13
0
/*
 * Fetches the resource denoted by |uri|.
 */
struct SPDY_Connection *
spdy_connect(const struct URI *uri,
             uint16_t port,
             bool is_tls)
{
  spdylay_session_callbacks callbacks;
  int fd;
  SSL *ssl=NULL;
  struct SPDY_Connection * connection = NULL;
  int rv;

  spdy_setup_spdylay_callbacks(&callbacks);

  /* Establish connection and setup SSL */
  PRINT_INFO2("connecting to %s:%i", uri->host, port);
  fd = spdy_socket_connect_to(uri->host, port);
  if(fd == -1)
  {
    PRINT_INFO("Could not open file descriptor");
    return NULL;
  }

  if(is_tls)
  {
    ssl = SSL_new(glob_opt.ssl_ctx);
    if(ssl == NULL) {
      spdy_dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
    }

    //TODO non-blocking
    /* To simplify the program, we perform SSL/TLS handshake in blocking
       I/O. */
    glob_opt.spdy_proto_version = 0;
    rv = spdy_ssl_handshake(ssl, fd);
    if(rv <= 0 || (glob_opt.spdy_proto_version != 3 && glob_opt.spdy_proto_version != 2))
    {
      PRINT_INFO("Closing SSL");
      //no spdy on the other side
      goto free_and_fail;
    }
  }
  else
  {
    glob_opt.spdy_proto_version = 3;
  }

  if(NULL == (connection = au_malloc(sizeof(struct SPDY_Connection))))
    goto free_and_fail;

  connection->is_tls = is_tls;
  connection->ssl = ssl;
  connection->want_io = IO_NONE;
  if(NULL == (connection->host = strdup(uri->host)))
    goto free_and_fail;

  /* Here make file descriptor non-block */
  spdy_socket_make_non_block(fd);
  spdy_socket_set_tcp_nodelay(fd);

  PRINT_INFO2("[INFO] SPDY protocol version = %d\n", glob_opt.spdy_proto_version);
  rv = spdylay_session_client_new(&(connection->session), glob_opt.spdy_proto_version,
                                  &callbacks, connection);
  if(rv != 0) {
    spdy_diec("spdylay_session_client_new", rv);
  }

  connection->fd = fd;

	return connection;

	//for GOTO
	free_and_fail:
  if(NULL != connection)
  {
    free(connection->host);
    free(connection);
  }

  if(is_tls)
    SSL_shutdown(ssl);

  MHD_socket_close_ (fd);

  if(is_tls)
    SSL_free(ssl);

  return NULL;
}
示例#14
0
int
http_cb_request (void *cls,
                struct MHD_Connection *connection,
                const char *url,
                const char *method,
                const char *version,
                const char *upload_data,
                size_t *upload_data_size,
                void **ptr)
{
  (void)cls;
  (void)url;
  (void)upload_data;
  (void)upload_data_size;
  
  int ret;
  struct Proxy *proxy;
  struct SPDY_Headers spdy_headers;
  bool with_body = false;
  struct HTTP_URI *http_uri;
  const char *header_value;

  if (NULL == ptr || NULL == *ptr)
    return MHD_NO;
    
  http_uri = (struct HTTP_URI *)*ptr;
    
  if(NULL == http_uri->proxy)
  {
    //first call for this request
    if (0 != strcmp (method, MHD_HTTP_METHOD_GET) && 0 != strcmp (method, MHD_HTTP_METHOD_POST))
    {
      free(http_uri->uri);
      free(http_uri);
      PRINT_INFO2("unexpected method %s", method);
      return MHD_NO;
    }
    
    if(NULL == (proxy = au_malloc(sizeof(struct Proxy))))
    {
      free(http_uri->uri);
      free(http_uri);
      PRINT_INFO("No memory");
      return MHD_NO; 
    }
    
    ++glob_opt.responses_pending;
    proxy->id = rand();
    proxy->http_active = true;
    proxy->http_connection = connection;
    http_uri->proxy = proxy;
    return MHD_YES;
  }
  
  proxy = http_uri->proxy;
  
  if(proxy->spdy_error || proxy->http_error)
    return MHD_NO; // handled at different place TODO? leaks?

  if(proxy->spdy_active)
  {
    if(0 == strcmp (method, MHD_HTTP_METHOD_POST))
    {
      PRINT_INFO("POST processing");
        
      int rc= spdylay_session_resume_data(proxy->spdy_connection->session, proxy->stream_id);
      PRINT_INFO2("rc is %i stream is %i", rc, proxy->stream_id);
      proxy->spdy_connection->want_io |= WANT_WRITE;
      
      if(0 == *upload_data_size)
      {
      PRINT_INFO("POST http EOF");
        proxy->receiving_done = true;
        return MHD_YES;
      }
      
      if(!copy_buffer(upload_data, *upload_data_size, &proxy->received_body, &proxy->received_body_size))
      {
        //TODO handle it better?
        PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
        return MHD_NO;
      }
      
      *upload_data_size = 0;
                               
      return MHD_YES;
    }
  
    //already handled
    PRINT_INFO("unnecessary call to http_cb_request");
    return MHD_YES;
  }
  
  //second call for this request

  PRINT_INFO2("received request for '%s %s %s'", method, http_uri->uri, version);

  proxy->url = http_uri->uri;
  
  header_value = MHD_lookup_connection_value(connection,
    MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
  
  with_body = 0 == strcmp (method, MHD_HTTP_METHOD_POST)
    && (NULL == header_value || 0 != strcmp ("0", header_value));
    
  PRINT_INFO2("body will be sent %i", with_body);
    
  ret = parse_uri(&glob_opt.uri_preg, proxy->url, &proxy->uri);
  if(ret != 0)
    DIE("parse_uri failed");
  proxy->http_uri = http_uri;

  spdy_headers.num = MHD_get_connection_values (connection,
                       MHD_HEADER_KIND,
                       NULL,
                       NULL);
  if(NULL == (spdy_headers.nv = au_malloc(((spdy_headers.num + 5) * 2 + 1) * sizeof(char *))))
    DIE("no memory");
  spdy_headers.nv[0] = ":method";     spdy_headers.nv[1] = method;
  spdy_headers.nv[2] = ":path";       spdy_headers.nv[3] = proxy->uri->path_and_more;
  spdy_headers.nv[4] = ":version";    spdy_headers.nv[5] = (char *)version;
  spdy_headers.nv[6] = ":scheme";     spdy_headers.nv[7] = proxy->uri->scheme;
  spdy_headers.nv[8] = ":host";       spdy_headers.nv[9] = NULL;
  //nv[14] = NULL;
  spdy_headers.cnt = 10;
  MHD_get_connection_values (connection,
                       MHD_HEADER_KIND,
                       &http_cb_iterate,
                       &spdy_headers);
                       
  spdy_headers.nv[spdy_headers.cnt] = NULL;
  if(NULL == spdy_headers.nv[9])
    spdy_headers.nv[9] = proxy->uri->host_and_port;

  if(0 != spdy_request(spdy_headers.nv, proxy, with_body))
  {
    free(spdy_headers.nv);
    //free_proxy(proxy);
    
    return MHD_NO;
  }
  free(spdy_headers.nv);
  
  proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                         4096,
                         &http_cb_response,
                         proxy,
                         &http_cb_response_done);

  if (NULL == proxy->http_response)
    DIE("no response");
  
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Proxy-Connection", "keep-alive"))
    PRINT_INFO("SPDY_name_value_add failed: ");
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Connection", "Keep-Alive"))
    PRINT_INFO("SPDY_name_value_add failed: ");
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Keep-Alive", "timeout=5, max=100"))
    PRINT_INFO("SPDY_name_value_add failed: ");
    
  proxy->spdy_active = true;
  
  return MHD_YES;
}
示例#15
0
static int
run ()
{
  unsigned long long timeoutlong = 0;
  unsigned long long timeout_spdy = 0;
  long timeout_curl = -1;
	struct timeval timeout;
	int ret;
	int ret_curl;
	int ret_spdy;
	fd_set rs;
	fd_set ws;
	fd_set es;
	int maxfd = -1;
	int maxfd_curl = -1;
	struct SPDY_Daemon *daemon;
  CURLMsg *msg;
  int msgs_left;
  struct Proxy *proxy;
  struct sockaddr_in *addr;
  struct addrinfo hints;
  char service[NI_MAXSERV];
  struct addrinfo *gai;
  enum SPDY_IO_SUBSYSTEM io = glob_opt.notls ? SPDY_IO_SUBSYSTEM_RAW : SPDY_IO_SUBSYSTEM_OPENSSL;
  enum SPDY_DAEMON_FLAG flags = SPDY_DAEMON_FLAG_NO;
  
	signal(SIGPIPE, SIG_IGN);
	
  if (signal(SIGINT, catch_signal) == SIG_ERR)
    PRINT_VERBOSE("signal failed");
    
  srand(time(NULL));
  if(init_parse_uri(&uri_preg))
    DIE("Regexp compilation failed");
    
	SPDY_init();
  
  if(glob_opt.nodelay)
    flags |= SPDY_DAEMON_FLAG_NO_DELAY;
  
  if(NULL == glob_opt.listen_host)
	{
    daemon = SPDY_start_daemon(glob_opt.listen_port,
								glob_opt.cert,
								glob_opt.cert_key,
								&new_session_cb,
								&session_closed_cb,
								&standard_request_handler,
								NULL,
								NULL,
								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
								1800,
                SPDY_DAEMON_OPTION_IO_SUBSYSTEM,
                io,
                SPDY_DAEMON_OPTION_FLAGS,
                flags,
								SPDY_DAEMON_OPTION_END);
  }
  else
  {
    snprintf (service, sizeof(service), "%u", glob_opt.listen_port);
    memset (&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    
    ret = getaddrinfo(glob_opt.listen_host, service, &hints, &gai);
    if(ret != 0)
      DIE("problem with specified host");
    
    addr = (struct sockaddr_in *) gai->ai_addr;
    
    daemon = SPDY_start_daemon(0,
								glob_opt.cert,
								glob_opt.cert_key,
								&new_session_cb,
								&session_closed_cb,
								&standard_request_handler,
								NULL,
								NULL,
								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
								1800,
                SPDY_DAEMON_OPTION_IO_SUBSYSTEM,
                io,
                SPDY_DAEMON_OPTION_FLAGS,
                flags,
                SPDY_DAEMON_OPTION_SOCK_ADDR,
                addr,
								SPDY_DAEMON_OPTION_END);
  }
	
	if(NULL==daemon){
		printf("no daemon\n");
		return 1;
	}
	
	multi_handle = curl_multi_init();
	if(NULL==multi_handle)
		DIE("no multi_handle");
  
	timeout.tv_usec = 0;

	do
	{
		FD_ZERO(&rs);
		FD_ZERO(&ws);
		FD_ZERO(&es);
    
    ret_spdy = SPDY_get_timeout(daemon, &timeout_spdy);
    if(SPDY_NO == ret_spdy || timeout_spdy > 5000)
      timeoutlong = 5000;
    else
      timeoutlong = timeout_spdy;
    PRINT_VERBOSE2("SPDY timeout %i; %i", timeout_spdy, ret_spdy);
    
    if(CURLM_OK != (ret_curl = curl_multi_timeout(multi_handle, &timeout_curl)))
    {
      PRINT_VERBOSE2("curl_multi_timeout failed (%i)", ret_curl);
      //curl_timeo = timeoutlong;
    }
    else if(timeoutlong > timeout_curl)
      timeoutlong = timeout_curl;
      
    PRINT_VERBOSE2("curl timeout %i", timeout_curl);
      
    timeout.tv_sec = timeoutlong / 1000;
		timeout.tv_usec = (timeoutlong % 1000) * 1000;
    
		maxfd = SPDY_get_fdset (daemon,
								&rs,
								&ws, 
								&es);	
		assert(-1 != maxfd);

		if(CURLM_OK != (ret = curl_multi_fdset(multi_handle, &rs,
								&ws, 
								&es, &maxfd_curl)))
		{
			PRINT_INFO2("curl_multi_fdset failed (%i)", ret);
			abort();
		}
    
    if(maxfd_curl > maxfd)
      maxfd = maxfd_curl;
      
    PRINT_VERBOSE2("timeout before %i %i", timeout.tv_sec, timeout.tv_usec);
    ret = select(maxfd+1, &rs, &ws, &es, &timeout);
    PRINT_VERBOSE2("timeout after %i %i; ret is %i", timeout.tv_sec, timeout.tv_usec, ret);
		
		/*switch(ret) {
			case -1:
				PRINT_INFO2("select error: %i", errno);
				break;
			case 0:
				break;
			default:*/
      
      //the second part should not happen with current implementation
      if(ret > 0 || (SPDY_YES == ret_spdy && 0 == timeout_spdy))
      {
				PRINT_VERBOSE("run spdy");
				SPDY_run(daemon);
        call_spdy_run = false;
      }
        
      if(ret > 0 || (CURLM_OK == ret_curl && 0 == timeout_curl) || call_curl_run)
      {
				PRINT_VERBOSE("run curl");
				if(CURLM_OK != (ret = curl_multi_perform(multi_handle, &still_running))
					&& CURLM_CALL_MULTI_PERFORM != ret)
				{
					PRINT_INFO2("curl_multi_perform failed (%i)", ret);
					abort();
				}
        call_curl_run = false;
      }
			/*break;
		}*/
    
    while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
      if (msg->msg == CURLMSG_DONE) {
        if(CURLE_OK == msg->data.result)
        {
          if(CURLE_OK != (ret = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &proxy)))
          {
            PRINT_INFO2("err %i",ret);
            abort();
          }

          proxy->done = true;
          call_spdy_run = true;
        }
        else
        {
          PRINT_VERBOSE2("bad curl result for '%s'", proxy->url);
          proxy->done = true;
          call_spdy_run = true;
          //TODO spdy should be notified to send RST_STREAM
        }
      }
      else PRINT_INFO("shouldn't happen");
    }
    
    if(call_spdy_run)
    {
      PRINT_VERBOSE("second call to SPDY_run");
      SPDY_run(daemon);
      call_spdy_run = false;
    }
    
    if(glob_opt.verbose)
    {
      
    struct timespec ts;
    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
    PRINT_VERBOSE2("time now %i %i", ts.tv_sec, ts.tv_nsec);
    }
  }
  while(loop);
	
	curl_multi_cleanup(multi_handle);

	SPDY_stop_daemon(daemon);
	
	SPDY_deinit();
  
  deinit_parse_uri(&uri_preg);
	
	return 0;
}
示例#16
0
static void
standard_request_handler(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)
{
	(void)cls;
	(void)priority;
	(void)host;
	(void)scheme;
	
	struct Proxy *proxy;
	int ret;
  struct URI *uri;
  struct SPDY_Session *session;
	
	PRINT_VERBOSE2("received request for '%s %s %s'\n", method, path, version);
  
	if(NULL == (proxy = malloc(sizeof(struct Proxy))))
        DIE("No memory");
	memset(proxy, 0, sizeof(struct Proxy));
  
  session = SPDY_get_session_for_request(request);
  assert(NULL != session);
  proxy->session_alive = SPDY_get_cls_from_session(session);
  assert(NULL != proxy->session_alive);
  
	proxy->request = request;
	if(NULL == (proxy->headers = SPDY_name_value_create()))
        DIE("No memory");
  
  if(glob_opt.transparent)
  {
    if(NULL != glob_opt.http_backend) //use always same host
      ret = asprintf(&(proxy->url),"%s://%s%s", scheme, glob_opt.http_backend, path);
    else //use host header
      ret = asprintf(&(proxy->url),"%s://%s%s", scheme, host, path);
    if(-1 == ret)
        DIE("No memory");
        
    ret = parse_uri(&uri_preg, proxy->url, &uri);
    if(ret != 0)
      DIE("parsing built uri failed");
  }
  else
  {
    ret = parse_uri(&uri_preg, path, &uri);
    PRINT_INFO2("path %s '%s' '%s'", path, uri->scheme, uri->host);
    if(ret != 0 || !strlen(uri->scheme) || !strlen(uri->host))
      DIE("parsing received uri failed");
      
    if(NULL != glob_opt.http_backend) //use backend host
    {
      ret = asprintf(&(proxy->url),"%s://%s%s", uri->scheme, glob_opt.http_backend, uri->path_and_more);
      if(-1 == ret)
        DIE("No memory");
    }
    else //use request path
      if(NULL == (proxy->url = strdup(path)))
        DIE("No memory");
  }
  
  free_uri(uri);
  
  PRINT_VERBOSE2("curl will request '%s'", proxy->url);
    
  SPDY_name_value_iterate(headers, &iterate_cb, proxy);
	
	if(NULL == (proxy->curl_handle = curl_easy_init()))
    {
		PRINT_INFO("curl_easy_init failed");
		abort();
	}
	
	if(glob_opt.curl_verbose)
    CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1);
	CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, proxy->url);
	if(glob_opt.http10)
		CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
	CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
	CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy);
	CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERFUNCTION, curl_header_cb);
	CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERDATA, proxy);
	CURL_SETOPT(proxy->curl_handle, CURLOPT_PRIVATE, proxy);
	CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTPHEADER, proxy->curl_headers);
  CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
  CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
  if(glob_opt.ipv4 && !glob_opt.ipv6)
    CURL_SETOPT(proxy->curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  else if(glob_opt.ipv6 && !glob_opt.ipv4)
    CURL_SETOPT(proxy->curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
	
	if(CURLM_OK != (ret = curl_multi_add_handle(multi_handle, proxy->curl_handle)))
	{
		PRINT_INFO2("curl_multi_add_handle failed (%i)", ret);
		abort();
	}
    
  //~5ms additional latency for calling this
	if(CURLM_OK != (ret = curl_multi_perform(multi_handle, &still_running))
		&& CURLM_CALL_MULTI_PERFORM != ret)
	{
		PRINT_INFO2("curl_multi_perform failed (%i)", ret);
		abort();
	}
  
  call_curl_run = true;
}
示例#17
0
static size_t
curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp)
{
	size_t realsize = size * nmemb;
	struct Proxy *proxy = (struct Proxy *)userp;
	char *line = (char *)ptr;
	char *name;
	char *value;
	char *status;
	int i;
	int pos;
	int ret;
  int num_values;
  const char * const * values;
  bool abort_it;
	
	//printf("curl_header_cb %s\n", line);
  if(!*(proxy->session_alive))
  {
    PRINT_VERBOSE("headers received, but session is dead");
    return 0;
  }
  
  //trailer
  if(NULL != proxy->response) return 0;

	if('\r' == line[0])
	{
		//all headers were already handled; prepare spdy frames
		if(NULL == (proxy->response = SPDY_build_response_with_callback(proxy->status,
							proxy->status_msg,
							proxy->version,
							proxy->headers,
							&response_callback,
							proxy,
							0)))
			DIE("no response");
    
		SPDY_name_value_destroy(proxy->headers);
		free(proxy->status_msg);
		free(proxy->version);
		
		if(SPDY_YES != SPDY_queue_response(proxy->request,
							proxy->response,
							true,
							false,
							&response_done_callback,
							proxy))
			DIE("no queue");
		
    call_spdy_run = true;
    
		return realsize;
	}
	
	pos = 0;
	if(NULL == proxy->version)
	{
		//first line from headers
		//version
		for(i=pos; i<realsize && ' '!=line[i]; ++i);
		if(i == realsize)
			DIE("error on parsing headers");
		if(NULL == (proxy->version = strndup(line, i - pos)))
        DIE("No memory");
		pos = i+1;
		
		//status (number)
		for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i]; ++i);
		if(NULL == (status = strndup(&(line[pos]), i - pos)))
        DIE("No memory");
		proxy->status = atoi(status);
		free(status);
		if(i<realsize && '\r'!=line[i])
		{
			//status (message)
			pos = i+1;
			for(i=pos; i<realsize && '\r'!=line[i]; ++i);
			if(NULL == (proxy->status_msg = strndup(&(line[pos]), i - pos)))
        DIE("No memory");
		}
    PRINT_VERBOSE2("Header line received '%s' '%i' '%s' ", proxy->version, proxy->status, proxy->status_msg);
		return realsize;
	}
	
	//other lines
	//header name
	for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i]; ++i)
		line[i] = tolower(line[i]); //spdy requires lower case
	if(NULL == (name = strndup(line, i - pos)))
        DIE("No memory");
	if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name)
		|| 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name)
		|| 0 == strcmp(SPDY_HTTP_HEADER_TRANSFER_ENCODING, name)
    )
	{
		//forbidden in spdy, ignore
		free(name);
		return realsize;
	}
	if(i == realsize || '\r'==line[i])
	{
		//no value. is it possible?
		if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, ""))
			DIE("SPDY_name_value_add failed");
		return realsize;
	}
	
	//header value
	pos = i+1;
	while(pos<realsize && isspace(line[pos])) ++pos; //remove leading space
	for(i=pos; i<realsize && '\r'!=line[i]; ++i);
	if(NULL == (value = strndup(&(line[pos]), i - pos)))
        DIE("No memory");
  PRINT_VERBOSE2("Adding header: '%s': '%s'", name, value);
	if(SPDY_YES != (ret = SPDY_name_value_add(proxy->headers, name, value)))
	{
    abort_it=true;
    if(NULL != (values = SPDY_name_value_lookup(proxy->headers, name, &num_values)))
      for(i=0; i<num_values; ++i)
        if(0 == strcasecmp(value, values[i]))
        {
          abort_it=false;
          PRINT_INFO2("header appears more than once with same value '%s: %s'", name, value);
          break;
        }
    
    if(abort_it)
    {
      PRINT_INFO2("SPDY_name_value_add failed (%i) for '%s'", ret, name);
      abort();
    }
	}
	free(name);
	free(value);

	return realsize;
}
示例#18
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;
}
示例#19
0
static ssize_t
spdy_cb_data_source_read(spdylay_session *session, int32_t stream_id, uint8_t *buf, size_t length, int *eof, spdylay_data_source *source, void *user_data)
{
  (void)session;
  (void)stream_id;
  (void)user_data;

  ssize_t ret;
  assert(NULL != source);
  assert(NULL != source->ptr);
	struct Proxy *proxy = (struct Proxy *)(source->ptr);
	void *newbody;


  if(length < 1)
  {
    PRINT_INFO("spdy_cb_data_source_read: length is 0");
    return 0;
	}

	if(!proxy->received_body_size)//nothing to write now
  {
    if(proxy->receiving_done)
    {
      PRINT_INFO("POST spdy EOF");
      *eof = 1;
    }
      PRINT_INFO("POST SPDYLAY_ERR_DEFERRED");
		return SPDYLAY_ERR_DEFERRED;//TODO SPDYLAY_ERR_DEFERRED should be used
  }

	if(length >= proxy->received_body_size)
	{
		ret = proxy->received_body_size;
		newbody = NULL;
	}
	else
	{
		ret = length;
		if(NULL == (newbody = malloc(proxy->received_body_size - length)))
		{
			PRINT_INFO("no memory");
			return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE;
		}
		memcpy(newbody, proxy->received_body + length, proxy->received_body_size - length);
	}
	memcpy(buf, proxy->received_body, ret);
	free(proxy->received_body);
	proxy->received_body = newbody;
	proxy->received_body_size -= ret;

  if(0 == proxy->received_body_size && proxy->receiving_done)
    {
      PRINT_INFO("POST spdy EOF");
    *eof = 1;
  }

  PRINT_INFO2("given POST bytes to spdylay: %zd", ret);

  return ret;
}
示例#20
0
static ssize_t
http_cb_response (void *cls,
                        uint64_t pos,
                        char *buffer,
                        size_t max)
{
  (void)pos;
  
	int ret;
	struct Proxy *proxy = (struct Proxy *)cls;
	void *newbody;
  const union MHD_ConnectionInfo *info;
  int val = 1;
  
  PRINT_INFO2("http_cb_response for %s", proxy->url);
  
  if(proxy->spdy_error)
    return MHD_CONTENT_READER_END_WITH_ERROR;
  
	if(0 == proxy->http_body_size && (proxy->done || !proxy->spdy_active))
  {
    PRINT_INFO("sent end of stream");
    return MHD_CONTENT_READER_END_OF_STREAM;
  }
	
	if(!proxy->http_body_size)//nothing to write now
  {
    //flush data
    info = MHD_get_connection_info (proxy->http_connection,
         MHD_CONNECTION_INFO_CONNECTION_FD);
    ret = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
    if(ret == -1) {
      DIE("setsockopt");
    }
    
    PRINT_INFO("FLUSH data");
		return 0;
  }
	
	if(max >= proxy->http_body_size)
	{
		ret = proxy->http_body_size;
		newbody = NULL;
	}
	else
	{
		ret = max;
		if(NULL == (newbody = au_malloc(proxy->http_body_size - max)))
		{
			PRINT_INFO("no memory");
			return MHD_CONTENT_READER_END_WITH_ERROR;
		}
		memcpy(newbody, proxy->http_body + max, proxy->http_body_size - max);
	}
	memcpy(buffer, proxy->http_body, ret);
	free(proxy->http_body);
	proxy->http_body = newbody;
	proxy->http_body_size -= ret;
	
	if(proxy->length >= 0)
	{
		proxy->length -= ret;
	}
	
	PRINT_INFO2("response_callback, size: %i",ret);
	
	return ret;
}
示例#21
0
/*
 * The implementation of spdylay_send_callback type. Here we write
 * |data| with size |length| to the network and return the number of
 * bytes actually written. See the documentation of
 * spdylay_send_callback for the details.
 */
static ssize_t
spdy_cb_send(spdylay_session *session,
             const uint8_t *data,
             size_t length,
             int flags,
             void *user_data)
{
  (void)session;
  (void)flags;

  //PRINT_INFO("spdy_cb_send called");
  struct SPDY_Connection *connection;
  ssize_t rv;
  connection = (struct SPDY_Connection*)user_data;
  connection->want_io = IO_NONE;

  if(glob_opt.ignore_rst_stream
    && 16 == length
    && 0x80 == data[0]
    && 0x00 == data[2]
    && 0x03 == data[3]
    )
  {
    PRINT_INFO2("ignoring RST_STREAM for stream_id %i %i %i %i", data[8], data[9], data[10], data[11]);
    glob_opt.ignore_rst_stream = false;
    return 16;
  }
  glob_opt.ignore_rst_stream = false;

  if(connection->is_tls)
  {
    ERR_clear_error();
    rv = SSL_write(connection->ssl, data, length);
    if(rv < 0) {
      int err = SSL_get_error(connection->ssl, rv);
      if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
        connection->want_io |= (err == SSL_ERROR_WANT_READ ?
                               WANT_READ : WANT_WRITE);
        rv = SPDYLAY_ERR_WOULDBLOCK;
      } else {
        rv = SPDYLAY_ERR_CALLBACK_FAILURE;
      }
    }
  }
  else
  {
    rv = write(connection->fd,
            data,
            length);

    if (rv < 0)
    {
      switch(errno)
      {
        case EAGAIN:
  #if EAGAIN != EWOULDBLOCK
        case EWOULDBLOCK:
  #endif
          connection->want_io |= WANT_WRITE;
          rv = SPDYLAY_ERR_WOULDBLOCK;
          break;

        default:
          rv = SPDYLAY_ERR_CALLBACK_FAILURE;
      }
    }
  }

  PRINT_INFO2("%zd bytes written by spdy", rv);

  if(rv > 0)
    UPDATE_STAT(glob_stat.spdy_bytes_sent, rv);

  return rv;
}