static void write_socks_request(struct conninfo *info) { if (info->socks == SOCKS_4) { struct sockaddr_in *sin = (struct sockaddr_in*)&info->addr; if (info->addr.ss_family != AF_INET) { finish_connection(info, 0, "SOCKS 4 can't handle ipv6!"); } /* connection request */ bufferevent_write(info->bev, "\x04\x01", 2); bufferevent_write(info->bev, &sin->sin_port, sizeof(sin->sin_port)); bufferevent_write(info->bev, &sin->sin_addr.s_addr, sizeof(sin->sin_addr.s_addr)); bufferevent_write(info->bev, "xx", 3); } else { ev_uint16_t port = htons(info->port); assert(info->host != NULL); bufferevent_write(info->bev, "\x04\x01", 2); bufferevent_write(info->bev, &port, sizeof(port)); bufferevent_write(info->bev, "\x00\x00\x00\xff", 4); bufferevent_write(info->bev, "xx", 3); bufferevent_write(info->bev, info->host, strlen(info->host)+1); } bufferevent_enable(info->bev, EV_READ); }
static void idle( ClientData client_data, struct timeval* nowP ) { int cnum; connecttab* c; for ( cnum = 0; cnum < max_connects; ++cnum ) { c = &connects[cnum]; switch ( c->conn_state ) { case CNST_READING: if ( nowP->tv_sec - c->active_at >= IDLE_READ_TIMELIMIT ) { httpd_send_err( c->hc, 408, httpd_err408title, "", httpd_err408form, "" ); finish_connection( c, nowP ); } break; case CNST_SENDING: case CNST_PAUSING: if ( nowP->tv_sec - c->active_at >= IDLE_SEND_TIMELIMIT ) { clear_connection( c, nowP ); } break; case CNST_SLEEPING:; } } }
static void idle(ClientData client_data, struct timeval *nowP) { int cnum; struct connect_s *conn; for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) { conn = &connects[cnum]; switch (conn->conn_state) { case CNST_READING: if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_READ_LIMIT_SEC) { ndbg("%s connection timed out reading\n", httpd_ntoa(&conn->hc->client_addr)); httpd_send_err(conn->hc, 408, httpd_err408title, "", httpd_err408form, ""); finish_connection(conn, nowP); } break; case CNST_SENDING: if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC) { ndbg("%s connection timed out sending\n", httpd_ntoa(&conn->hc->client_addr)); clear_connection(conn, nowP); } break; } } }
static void must_succeed(grpc_exec_ctx *exec_ctx, void *arg, int success) { GPR_ASSERT(g_connecting != NULL); GPR_ASSERT(success); grpc_endpoint_shutdown(exec_ctx, g_connecting); grpc_endpoint_destroy(exec_ctx, g_connecting); g_connecting = NULL; finish_connection(); }
int conn_connect_bufferevent(struct bufferevent *bev, struct evdns_base *dns, int family, const char *name, int port, conn_connectcb conncb, void *arg) { struct conninfo *info; int rv = -1; info = mem_calloc(1, sizeof(*info)); info->bev = bev; info->on_connect = conncb; info->cbarg = arg; info->connecting = 1; info->socks = use_socks; bufferevent_setcb(bev, conn_readcb, NULL, conn_errorcb, info); if (use_socks != SOCKS_NONE) { info->host = mem_strdup(name); info->port = port; if (use_socks == SOCKS_4a) { rv = bufferevent_socket_connect(bev, (struct sockaddr*)&socks_addr, socks_addr_len); return rv; } #ifndef DISABLE_DIRECT_CONNECTIONS else { struct evutil_addrinfo hint; char portstr[NI_MAXSERV]; evutil_snprintf(portstr, sizeof(portstr), "%d", port); memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_INET; hint.ai_protocol = IPPROTO_TCP; hint.ai_socktype = SOCK_STREAM; evdns_getaddrinfo(dns, name, portstr, &hint, socks_resolvecb, info); return 0; } #endif } #ifdef DISABLE_DIRECT_CONNECTIONS { const char *msg; msg = "Direct connections disabled, but I have no SOCKS 4a " "proxy to connect to!"; log_error("conn: %s", msg); finish_connection(info, 0, msg); } #else rv = bufferevent_socket_connect_hostname(bev, dns, family, name, port); #endif return rv; }
static void must_succeed(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_ASSERT(g_connecting != NULL); GPR_ASSERT(error == GRPC_ERROR_NONE); grpc_endpoint_shutdown( exec_ctx, g_connecting, GRPC_ERROR_CREATE_FROM_STATIC_STRING("must_succeed called")); grpc_endpoint_destroy(exec_ctx, g_connecting); g_connecting = NULL; finish_connection(exec_ctx); }
static void handle_read_2( connecttab *c, struct timeval *tvP ) { httpd_conn* hc = c->hc; ClientData client_data; /* Fill in end_byte_index. */ if ( hc->got_range ) { c->next_byte_index = hc->first_byte_index; c->end_byte_index = hc->last_byte_index + 1; } else if ( hc->bytes_to_send < 0 ) c->end_byte_index = 0; else c->end_byte_index = hc->bytes_to_send; /* Check if it's already handled. */ if ( hc->body_data == (char*) 0 ) { /* No body data means someone else is handling it. */ c->next_byte_index = hc->bytes_sent; finish_connection( c, tvP ); return; } if ( c->next_byte_index >= c->end_byte_index ) { /* There's nothing to send. */ finish_connection( c, tvP ); return; } /* Cool, we have a valid connection and a file to send to it. */ c->conn_state = CNST_SENDING; c->started_at = tvP->tv_sec; c->wouldblock_delay = 0; client_data.p = c; fdwatch_del_fd( hc->conn_fd ); fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE ); }
static void conn_errorcb(struct bufferevent *bev, short what, void *arg) { struct conninfo *info = arg; if (info->connecting) { info->connecting = 0; if (what & BEV_EVENT_CONNECTED) { if (info->socks != SOCKS_NONE) write_socks_request(info); else finish_connection(info, 1, NULL); } else { // XXX need better err msg const char *msg = "Connection failed"; if (info->socks != SOCKS_NONE) msg = "Connection to proxy server failed"; finish_connection(info, 0, msg); } } else { finish_connection(info, 0, "SOCKS I/O error"); } }
static void conn_readcb(struct bufferevent *bev, void *arg) { struct conninfo *info = arg; struct evbuffer *inbuf = bufferevent_get_input(bev); unsigned char *data; unsigned char code; /* socks4 and socks4a both have an 8 byte response */ if (evbuffer_get_length(inbuf) < 8) { log_debug("conn: waiting for full socks response"); return; } data = evbuffer_pullup(inbuf, 8); code = data[1]; evbuffer_drain(inbuf, 8); if (code != 0x5a) { finish_connection(info, 0, socks4_error_to_string(code)); } else { finish_connection(info, 1, NULL); } }
static void httpd_conn_wakeup( ClientData client_data, struct timeval* nowP ) { connecttab* c = client_data.p; c->conn_state = CNST_READING; c->wakeup_timer = (Timer*) 0; if( httpd_continue_request( c->hc, nowP ) < 0 ) { finish_connection( c, nowP ); return; } if( c->conn_state == CNST_READING ) handle_read_2( c, nowP ); }
void socks_resolvecb(int result, struct evutil_addrinfo *ai, void *arg) { struct conninfo *info = arg; if (result) { char buf[256]; evutil_snprintf(buf, sizeof(buf), "DNS Failure: %s", evutil_gai_strerror(result)); finish_connection(info, 0, buf); } else { log_debug("conn: socks resolve %s", format_addr(ai->ai_addr)); assert(ai->ai_addrlen <= sizeof(info->addr)); memcpy(&info->addr, ai->ai_addr, ai->ai_addrlen); info->addr_len = ai->ai_addrlen; bufferevent_socket_connect(info->bev, (struct sockaddr*)&socks_addr, socks_addr_len); } if (ai) evutil_freeaddrinfo(ai); }
static void deinit_socket_server (assuan_context_t ctx) { finish_connection (ctx); }
static void handle_read(struct connect_s *conn, struct timeval *tv) { ClientData client_data; httpd_conn *hc = conn->hc; off_t actual; int sz; /* Is there room in our buffer to read more bytes? */ if (hc->read_idx >= hc->read_size) { if (hc->read_size > CONFIG_THTTPD_MAXREALLOC) { BADREQUEST("MAXREALLOC"); goto errout_with_400; } httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->read_size + CONFIG_THTTPD_REALLOCINCR); } /* Read some more bytes */ sz = read(hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx); if (sz == 0) { BADREQUEST("EOF"); goto errout_with_400; } if (sz < 0) { /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glance * you would think that connections returned by fdwatch as readable * should never give an EWOULDBLOCK; however, this apparently can * happen if a packet gets garbled. */ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { return; } ndbg("read(fd=%d) failed: %d\n", hc->conn_fd, errno); BADREQUEST("read"); goto errout_with_400; } hc->read_idx += sz; conn->active_at = tv->tv_sec; /* Do we have a complete request yet? */ switch (httpd_got_request(hc)) { case GR_NO_REQUEST: return; case GR_BAD_REQUEST: BADREQUEST("httpd_got_request"); goto errout_with_400; } /* Yes. Try parsing and resolving it */ if (httpd_parse_request(hc) < 0) { goto errout_with_connection; } /* Start the connection going */ if (httpd_start_request(hc, tv) < 0) { /* Something went wrong. Close down the connection */ goto errout_with_connection; } /* Set up the file offsets to read */ conn->eof = false; if (hc->got_range) { conn->offset = hc->range_start; conn->end_offset = hc->range_end + 1; } else { conn->offset = 0; if (hc->bytes_to_send < 0) { conn->end_offset = 0; } else { conn->end_offset = hc->bytes_to_send; } } /* Check if it's already handled */ if (hc->file_fd < 0) { /* No file descriptor means someone else is handling it */ conn->offset = hc->bytes_sent; goto errout_with_connection; } if (conn->offset >= conn->end_offset) { /* There's nothing to send */ goto errout_with_connection; } /* Seek to the offset of the next byte to send */ actual = lseek(hc->file_fd, conn->offset, SEEK_SET); if (actual != conn->offset) { ndbg("fseek to %d failed: offset=%d errno=%d\n", conn->offset, actual, errno); BADREQUEST("lseek"); goto errout_with_400; } /* We have a valid connection and a file to send to it */ conn->conn_state = CNST_SENDING; client_data.p = conn; fdwatch_del_fd(fw, hc->conn_fd); return; errout_with_400: BADREQUEST("errout"); httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); errout_with_connection: finish_connection(conn, tv); return; }
static void must_fail(grpc_exec_ctx *exec_ctx, void *arg, int success) { GPR_ASSERT(g_connecting == NULL); GPR_ASSERT(!success); finish_connection(); }
static void handle_send( connecttab* c, struct timeval* tvP ) { size_t max_bytes; int sz, coast; ClientData client_data; time_t elapsed; httpd_conn* hc = c->hc; int tind; max_bytes = 1000000000L; /* Do we need to write the headers first? */ if ( hc->responselen == 0 ) { /* No, just write the file. */ sz = write( hc->conn_fd, &(hc->body_data[c->next_byte_index]), MIN( c->end_byte_index - c->next_byte_index, max_bytes ) ); } else { /* Yes. We'll combine headers and file into a single writev(), ** hoping that this generates a single packet. */ struct iovec iv[2]; iv[0].iov_base = hc->response; iv[0].iov_len = hc->responselen; iv[1].iov_base = &(hc->body_data[c->next_byte_index]); iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes ); sz = writev( hc->conn_fd, iv, 2 ); } if ( sz < 0 && errno == EINTR ) return; if ( sz == 0 || ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) ) { /* This shouldn't happen, but some kernels, e.g. ** SunOS 4.1.x, are broken and select() says that ** O_NDELAY sockets are always writable even when ** they're actually not. ** ** Current workaround is to block sending on this ** socket for a brief adaptively-tuned period. ** Fortunately we already have all the necessary ** blocking code, for use with throttling. */ c->wouldblock_delay += MIN_WOULDBLOCK_DELAY; c->conn_state = CNST_PAUSING; fdwatch_del_fd( hc->conn_fd ); client_data.p = c; c->wakeup_timer = tmr_create( tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 ); if ( c->wakeup_timer == (Timer*) 0 ) { return; } return; } if ( sz < 0 ) { /* Something went wrong, close this connection. */ clear_connection( c, tvP ); return; } /* Ok, we wrote something. */ c->active_at = tvP->tv_sec; /* Was this a headers + file writev()? */ if ( hc->responselen > 0 ) { /* Yes; did we write only part of the headers? */ if ( sz < hc->responselen ) { /* Yes; move the unwritten part to the front of the buffer. */ int newlen = hc->responselen - sz; (void) memmove( hc->response, &(hc->response[sz]), newlen ); hc->responselen = newlen; sz = 0; } else { /* Nope, we wrote the full headers, so adjust accordingly. */ sz -= hc->responselen; hc->responselen = 0; } } /* And update how much of the file we wrote. */ c->next_byte_index += sz; c->hc->bytes_sent += sz; /* Are we done? */ if ( c->next_byte_index >= c->end_byte_index ) { /* This connection is finished! */ finish_connection( c, tvP ); return; } /* Tune the (blockheaded) wouldblock delay. */ if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY ) c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY; /* (No check on min_limit here, that only controls connection startups.) */ }
static void handle_send(struct connect_s *conn, struct timeval *tv) { httpd_conn *hc = conn->hc; int nwritten; int nread; /* Read until the entire file is sent -- this could take awhile!! */ while (conn->offset < conn->end_offset) { nvdbg("offset: %d end_offset: %d bytes_sent: %d\n", conn->offset, conn->end_offset, conn->hc->bytes_sent); /* Fill the rest of the response buffer with file data */ nread = read_buffer(conn); if (nread < 0) { ndbg("File read error: %d\n", errno); goto errout_clear_connection; } nvdbg("Read %d bytes, buflen %d\n", nread, hc->buflen); /* Send the buffer */ if (hc->buflen > 0) { /* httpd_write does not return until all bytes have been sent * (or an error occurs). */ nwritten = httpd_write(hc->conn_fd, hc->buffer, hc->buflen); if (nwritten < 0) { ndbg("Error sending %s: %d\n", hc->encodedurl, errno); goto errout_clear_connection; } /* We wrote one full buffer of data (httpd_write does not * return until the full buffer is written (or an error occurs). */ conn->active_at = tv->tv_sec; hc->buflen = 0; /* And update how much of the file we wrote */ conn->offset += nwritten; conn->hc->bytes_sent += nwritten; nvdbg("Wrote %d bytes\n", nwritten); } } /* The file transfer is complete -- finish the connection */ nvdbg("Finish connection\n"); finish_connection(conn, tv); return; errout_clear_connection: ndbg("Clear connection\n"); clear_connection(conn, tv); return; }
static void must_fail(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_ASSERT(g_connecting == NULL); GPR_ASSERT(error != GRPC_ERROR_NONE); finish_connection(exec_ctx); }
static void handle_read( connecttab* c, struct timeval* tvP ) { int sz; httpd_conn* hc = c->hc; /* Is there room in our buffer to read more bytes? */ if ( hc->read_idx >= hc->read_size ) { if ( hc->read_size > 5000 ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } httpd_realloc_str( &hc->read_buf, &hc->read_size, hc->read_size + 1000 ); } /* Read some more bytes. */ sz = read( hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx ); if ( sz == 0 ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } if ( sz < 0 ) { /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glance ** you would think that connections returned by fdwatch as readable ** should never give an EWOULDBLOCK; however, this apparently can ** happen if a packet gets garbled. */ if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) return; httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } hc->read_idx += sz; c->active_at = tvP->tv_sec; /* Do we have a complete request yet? */ switch ( httpd_got_request( hc ) ) { case GR_NO_REQUEST: return; case GR_BAD_REQUEST: httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } /* Yes. Try parsing and resolving it. */ if ( httpd_parse_request( hc ) < 0 ) { finish_connection( c, tvP ); return; } /* Start the connection going. */ if ( httpd_start_request( hc, tvP ) < 0 ) { /* Something went wrong. Close down the connection. */ finish_connection( c, tvP ); return; } if ( c->conn_state == CNST_SLEEPING ) { return; } handle_read_2( c, tvP ); }