void msg_event_handler( int fd, int msgid, int event ) { char buf[PACK_DATA_SIZE]; ssize_t n; // printf( "event 0x%03x for msg %d\n", event, msgid ); switch ( event ) { case MSG_EVT_ACCEPT_READY: if ( msg_accept( fd, msgid ) != 0 ) msg_set_read( fd, msgid ); // These are commands break; case MSG_EVT_READ_READY: msg_clr_read( fd, msgid ); n = msg_read( fd, msgid, buf, sizeof( buf ) ); if ( n <= 0 ) { cleanup_connection( msg_get_type( fd, msgid ) ); break; } if ( msg_get_type( fd, msgid ) < 0 ) { /* If the msgid is less than zero, it refers to a command and the message should not be routed to a file descriptor. */ // the entire command must fit inside one transport command_handler( fd, msgid, buf, n ); } else { zs_set_write( msg_get_type( fd, msgid ) ); /* if msgid is zero or greater it refers to a socket file descriptor that the message should be routed to. */ if ( zs_write( msg_get_type( fd, msgid ), buf, n ) == -1 ) cleanup_connection( msg_get_type( fd, msgid ) ); } break; case MSG_EVT_WRITE_READY: if ( msgid < 0 ) break; zs_set_read( msg_get_type( fd, msgid ) ); msg_clr_write( fd, msgid ); break; case MSG_SWITCH_EVT_IO_ERROR: //zclose( msg_switch->sockfd ); if ( website_get_by_sockfd( fd ) ) remove_website( fd ); else { for ( n = 0; n < FD_SETSIZE; n++ ) { if ( msg_exists( fd, n ) ) { if ( msg_get_type( fd, n ) > 0 ) cleanup_connection( msg_get_type( fd, n ) ); // else // msg_close( fd, n ); } } msg_switch_destroy( fd ); zs_close( fd ); } break; } }
int forward_client_to_service(struct ConnectionState *st) { char buf[4096]; int r = 1; int ret = SSL_read(st->ssl, buf, sizeof(buf)); int err = SSL_get_error(st->ssl, ret); switch (err) { case SSL_ERROR_NONE: { // fcntl(st->service_conn, F_SETFL, 0); assert(ret > 0); stats.up_bytes += ret; int status = sendall(st->service_conn, buf, ret); log_data(st, buf, ret); if (status < 0) { fprintf(stderr, "couldn't forward data to service\n"); cleanup_connection(st); return 0; } // fcntl(st->service_conn, F_SETFL, O_NONBLOCK); break; } case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: if (err == SSL_ERROR_SSL) { extern BIO *bio_err; if (!bio_err) { bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); } ERR_print_errors(bio_err); } else if (err == SSL_ERROR_SYSCALL) { // Socket closed cleanup_connection_after_ssl(st, 1); return 0; } cleanup_connection(st); r = 0; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: //fprintf(stderr, "Ignoring recoverable SSL error %d while forwarding to service\n", err); break; } return r; }
int remove_website( int fd ) { website_t* website; if ( !( website = website_get_by_sockfd( fd ) ) ) { syslog( LOG_WARNING, "stop_website: tried to stop a nonexisting website" ); return 0; } syslog( LOG_INFO, "website: stopping \"%s\" on \"%s\"", website->full_url, website->ip ); website_data_t* website_data = (website_data_t*) website->udata; int i; for ( i = 0; i < FD_SETSIZE; i++ ) { if ( connections[ i ] && connections[ i ]->website_sockfd == website->sockfd ) cleanup_connection( i ); } msg_switch_destroy( fd ); zs_close( fd ); if ( website_data->exlisnfd != -1 ) zs_close( website_data->exlisnfd ); free( website_data ); website_remove( website ); return 1; }
int main(int argc, char **argv) { (void)argc; (void)argv; const uint32_t net = 0x0a0a0a00; char *password; setup_test("tcpr-test", "test-spurious-fins"); password = get_password(htonl(net | 2), 8888, htonl(net | 3), 9999); setup_connection(net | 2, net | 4, net | 3, 8888, 9999, 0xdeadbeef, 0xcafebabe, test_options_size, test_options, peer_mss, peer_ws, password); fprintf(stderr, "Application: FIN (failure)\n"); send_segment(internal_log, net | 4, net | 2, 9999, 8888, TH_ACK | TH_FIN, 0xcafebabe + 1, 0xdeadbeef + 1, 0, NULL, 0, NULL, password); fprintf(stderr, " Filter: RST\n"); recv_segment(internal_log, net | 2, net | 4, 8888, 9999, TH_RST, 0xdeadbeef + 1, 0, 0, NULL, 0, NULL, password); cleanup_connection(net | 2, net | 4, 8888, 9999, 0xcafebabe + 1, 0xdeadbeef + 1, 0); cleanup_test(); return EXIT_SUCCESS; }
static void on_read_ready(int fd, short event_type, struct ConnectionState *st) { assert(event_type == EV_READ); if (st->client_conn == fd) { st->client_ready[READ] = 1; event_del(st->ev_client_read); if (st->cleanup_waiting == SSL_ERROR_WANT_READ) { cleanup_connection_ssl_try_shutdown(st); return; } // g_slice_free(st->ev_client_read); // st->ev_client_read = 0; } else if (st->service_conn == fd) { st->service_ready[READ] = 1; event_del(st->ev_service_read); // g_slice_free(st->ev_service_read); // st->ev_service_read = 0; } else { //fprintf(stderr,"Error: on_read_ready(%d, %d, %p)\n", fd, event_type, st); cleanup_connection(st); return; } try_to_forward(st); pet_watchdog(st); }
int forward_service_to_client(struct ConnectionState *st) { assert(st->client_conn >= 0); int conn = st->service_conn; int r = 1; char buf[4096]; int num_received = recv(conn, buf, sizeof(buf), 0); if (num_received < 0) { perror("Error reading from service"); if (errno == EAGAIN || errno == EWOULDBLOCK) { fprintf(stderr, "on_service_read called, but we'd block\n"); return r; } cleanup_connection(st); r = 0; return r; } else if (num_received == 0) { cleanup_connection(st); r = 0; return r; } stats.down_bytes += num_received; // TODO(swolchok): some error codes are non-fatal... int ret = SSL_write(st->ssl, buf, num_received); int err = SSL_get_error(st->ssl, ret); switch (err) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: //fprintf(stderr, "Recoverable SSL error %d writing to client", err); break; default: fprintf(stderr, "SSL error %d writing to client\n", err); cleanup_connection(st); r = 0; break; } return r; }
void cleanup_iet_isns(void) { struct portal *p; cleanup_connection(sock_fd); if (iet_entity) free(iet_entity); while (iet_portal) { p = iet_portal->next; free(iet_portal); iet_portal = p; }; }
MemcachedStore::~MemcachedStore() { // Destroy the updater (if it was created). delete _updater; // Clean up this thread's connection now, rather than waiting for // pthread_exit. This is to support use by single-threaded code // (e.g., UTs), where pthread_exit is never called. connection* conn = (connection*)pthread_getspecific(_thread_local); if (conn != NULL) { pthread_setspecific(_thread_local, NULL); cleanup_connection(conn); } pthread_rwlock_destroy(&_view_lock); }
int main(int argc, char **argv) { (void)argc; (void)argv; const uint32_t net = 0x0a0a0a00; char *password; setup_test("tcpr-test", "test-recover-peer-send"); password = get_password(htonl(net | 2), 8888, htonl(net | 3), 9999); setup_connection(net | 2, net | 4, net | 3, 8888, 9999, 0xdeadbeef, 0xcafebabe, test_options_size, test_options, peer_mss, peer_ws, password); recover_connection(net | 5, net | 2, net | 3, 9999, 8888, 0xfeedbead, 0xcafebabe, 0xdeadbeef, test_options_size, test_options, peer_mss, peer_ws, TCPR_HAVE_ACK | TCPR_HAVE_PEER_MSS | TCPR_HAVE_PEER_WS, password); fprintf(stderr, " Peer: \"baz\" (retransmit)\n"); send_segment(external_log, net | 2, net | 3, 8888, 9999, TH_ACK, 0xdeadbeef + 1, 0xcafebabe + 1, 0, NULL, 4, "baz", password); recv_segment(internal_log, net | 2, net | 5, 8888, 9999, TH_ACK, 0xdeadbeef + 1, 0xfeedbead + 1, 0, NULL, 4, "baz", password); fprintf(stderr, "Application: ACK\n"); send_segment(internal_log, net | 5, net | 2, 9999, 8888, TH_ACK, 0xfeedbead + 1, 0xdeadbeef + 5, 0, NULL, 0, NULL, password); fprintf(stderr, "Application: update\n"); send_update(net | 2, net | 5, 8888, 9999, 0xcafebabe + 1, 0xdeadbeef + 5, 0, 0, (0xfeedbead + 1) - (0xcafebabe + 1), TCPR_HAVE_ACK); fprintf(stderr, " Filter: ACK\n"); recv_segment(external_log, net | 3, net | 2, 9999, 8888, TH_ACK, 0xcafebabe + 1, 0xdeadbeef + 5, 0, NULL, 0, NULL, password); cleanup_connection(net | 2, net | 4, 8888, 9999, 0xcafebabe + 1, 0xdeadbeef + 1, (0xfeedbead + 1) - (0xcafebabe + 1)); cleanup_test(); return EXIT_SUCCESS; }
int main(int argc, char **argv) { (void)argc; (void)argv; const uint32_t net = 0x0a0a0a00; char *password; setup_test("tcpr-test", "test-filter-recovery"); password = get_password(htonl(net | 2), 8888, htonl(net | 3), 9999); fprintf(stderr, "Application: \"a\"\n"); send_segment(internal_log, net | 4, net | 2, 9999, 8888, TH_ACK, 0xbeefbead, 0xbabedeed, 0, NULL, 2, "a", password); fprintf(stderr, " Filter: update (failure)\n"); recv_update(net | 2, net | 4, 8888, 9999, 0, 0, 0, 0, 0, 0); fprintf(stderr, "Application: update\n"); send_update(net | 2, net | 4, 8888, 9999, 0xbeefbead, 0xbabedeed - 4, peer_mss, peer_ws, 0, TCPR_HAVE_ACK); fprintf(stderr, " Filter: ACK\n"); recv_segment(external_log, net | 3, net | 2, 9999, 8888, TH_ACK, 0xbeefbead + 2, 0xbabedeed - 4, 0, NULL, 0, NULL, password); fprintf(stderr, "Application: \"a\" (retransmit)\n"); send_segment(internal_log, net | 4, net | 2, 9999, 8888, TH_ACK, 0xbeefbead, 0xbabedeed, 0, NULL, 2, "a", password); recv_segment(external_log, net | 3, net | 2, 9999, 8888, TH_ACK, 0xbeefbead, 0xbabedeed - 4, 0, NULL, 2, "a", password); cleanup_connection(net | 2, net | 4, 8888, 9999, 0xbeefbead, 0xbabedeed - 4, 0); cleanup_test(); return EXIT_SUCCESS; }
int main(int argc, char **argv) { (void)argc; (void)argv; const uint32_t net = 0x0a0a0a00; char *password; setup_test("tcpr-test", "test-simultaneous-recovery"); password = get_password(htonl(net | 2), 8888, htonl(net | 3), 9999); fprintf(stderr, "Application: SYN (simultaneous recovery)\n"); send_segment(internal_log, net | 4, net | 2, 9999, 8888, TH_SYN, 0xcafebabe, 0, 0, NULL, 0, NULL, password); recv_segment(external_log, net | 3, net | 2, 9999, 8888, TH_SYN, 0xcafebabe, 0, 0, NULL, 0, NULL, password); fprintf(stderr, " Peer: ACK (answer unacceptable SYN)\n"); send_segment(external_log, net | 2, net | 3, 8888, 9999, TH_ACK, 0xdeadbeef + 5, 0xcafebabe + 1, 0, NULL, 0, NULL, password); fprintf(stderr, " Filter: update (failure)\n"); recv_update(net | 2, net | 4, 8888, 9999, 0xcafebabe + 1, 0, 0, 0, 0, 0); fprintf(stderr, "Application: update\n"); send_update(net | 2, net | 4, 8888, 9999, 0xcafebabe + 1, 0xdeadbeef + 5, 0, 0, 0, TCPR_HAVE_ACK); fprintf(stderr, " Filter: ACK\n"); recv_segment(external_log, net | 3, net | 2, 9999, 8888, TH_ACK, 0xcafebabe + 1, 0xdeadbeef + 5, 0, NULL, 0, NULL, password); fprintf(stderr, "Application: SYN (retransmit)\n"); send_segment(internal_log, net | 4, net | 2, 9999, 8888, TH_SYN, 0xcafebabe, 0, 0, NULL, 0, NULL, password); fprintf(stderr, " Filter: SYN ACK\n"); recv_segment(internal_log, net | 2, net | 4, 8888, 9999, TH_SYN | TH_ACK, 0xdeadbeef + 4, 0xcafebabe + 1, 0, NULL, 0, NULL, password); fprintf(stderr, " Filter: update\n"); recv_update(net | 2, net | 4, 8888, 9999, 0xcafebabe + 1, 0xdeadbeef + 5, 0, 0, 0, TCPR_HAVE_ACK); fprintf(stderr, "Application: ACK\n"); send_segment(internal_log, net | 4, net | 2, 9999, 8888, TH_ACK, 0xcafebabe + 1, 0xdeadbeef + 5, 0, NULL, 0, NULL, password); recv_segment(external_log, net | 3, net | 2, 9999, 8888, TH_ACK, 0xcafebabe + 1, 0xdeadbeef + 5, 0, NULL, 0, NULL, password); fprintf(stderr, "Application: update (reset)\n"); send_update(net | 2, net | 4, 8888, 9999, 0xcafebabe + 1, 0xdeadbeef + 5, 0, 0, 0, TCPR_HAVE_ACK | TCPR_TIME_WAIT); cleanup_connection(net | 2, net | 4, 8888, 9999, 0xcafebabe + 1, 0xdeadbeef + 1, 0); cleanup_test(); return EXIT_SUCCESS; }
void exread( int sockfd ) { void* ptr; conn_data_t* conn_data = connections[ sockfd ]; if ( !conn_data->buffer ) { conn_data->buffer = malloc(PACK_DATA_SIZE); conn_data->bufferlen = 0; memset( conn_data->buffer, 0, PACK_DATA_SIZE ); } website_t* website; ssize_t len = zs_read( sockfd, conn_data->buffer + conn_data->bufferlen, PACK_DATA_SIZE - conn_data->bufferlen ); // TODO: wait for entire header before looking up website if ( len <= 0 ) { cleanup: // cleanup cleanup_connection( sockfd ); return; } if ( conn_data->postlen == -1 ) /* if we have received all the data already, ignore */ return; conn_data->bufferlen += len; //printf( "%d: read %zu\n", sockfd, len ); ptr = conn_data->buffer; if ( conn_data->website_sockfd == -1 ) { /* If req_info is NULL this is the start of a request and the HTTP request headers need to be parsed. */ struct hostent* hp; hp = NULL;//gethostbyaddr( (char*) &conn_data->addr, sizeof( conn_data->addr ), AF_INET ); char* endofhdrs; if ( !( endofhdrs = strnstr( conn_data->buffer, HTTP_HDR_ENDL HTTP_HDR_ENDL, PACK_DATA_SIZE ) ) ) { if ( conn_data->bufferlen == PACK_DATA_SIZE ) { /* If the end of the headers was not found the request was either malformatted or too long, DO NOT send to website. */ zs_write( sockfd, html_error_414, sizeof( html_error_414 ) ); syslog( LOG_WARNING, "exread: headers to long" ); goto cleanup; } // Have not received the full header yet, wait zs_set_read( sockfd ); return; } endofhdrs += sizeof( HTTP_HDR_ENDL HTTP_HDR_ENDL ) - 1; /* Get HTTP request type */ if ( startswith( conn_data->buffer, HTTP_GET ) ) conn_data->request_type = HTTP_GET_TYPE; else if ( startswith( conn_data->buffer, HTTP_POST ) ) conn_data->request_type = HTTP_POST_TYPE; else { zs_write( sockfd, html_error_400, sizeof( html_error_400 ) ); goto cleanup; } /* Find website for request from HTTP header */ char urlbuf[ PACK_DATA_SIZE ]; if ( !get_url_from_http_header( conn_data->buffer, urlbuf, sizeof( urlbuf ) ) ) { //syslog( LOG_WARNING, "exread: no url found in http request headers: %s %s", // inet_ntoa( conn_data->addr.sin_addr ), hp ? hp->h_name : "" ); zs_write( sockfd, html_error_400, sizeof( html_error_400 ) ); goto cleanup; } if ( !( website = website_find( urlbuf, conn_data->is_https ? "https://" : "http://", inet_ntoa( zs_get_addr( conn_data->exlisnfd )->sin_addr ) ) ) ) { //syslog( LOG_WARNING, "exread: no website to service request: %s %s %s", // inet_ntoa( conn_data->addr.sin_addr ), hp ? hp->h_name : "", urlbuf ); zs_write( sockfd, html_error_404, sizeof( html_error_404 ) ); goto cleanup; } /* Set the website id so that furthur sections of this request can check if the website is still alive. */ conn_data->website_sockfd = website->sockfd; /* Check the websites socket to make sure the request came in on the right socket. */ website_data_t* website_data = website->udata; if ( website_data->exlisnfd != conn_data->exlisnfd ) { //syslog( LOG_WARNING, "exread: no website to service request: %s %s %s", // inet_ntoa( conn_data->addr.sin_addr ), hp ? hp->h_name : "", urlbuf ); zs_write( sockfd, html_error_404, sizeof( html_error_404 ) ); goto cleanup; } //printf( "%s\n", buffer ); /* Create a new message to send the request to the corresponding website. The msgid should be set to the external file descriptor to send the response back to. */ conn_data->msgid = msg_open( website->sockfd, sockfd ); zs_set_write( sockfd ); // If request_type is POST check if there is content after the HTTP header char postlenbuf[ 32 ]; memset( postlenbuf, 0, sizeof( postlenbuf ) ); if ( conn_data->request_type == HTTP_POST_TYPE && ( ptr = strnstr( conn_data->buffer, "Content-Length: ", PACK_DATA_SIZE ) ) ) { char* tmp = strnstr( ptr + 16, HTTP_HDR_ENDL, PACK_DATA_SIZE - ( (long)ptr + 16 - (long)conn_data->buffer ) ); if ( !tmp ) { zs_write( sockfd, html_error_400, sizeof( html_error_400 ) ); goto cleanup; } memcpy( postlenbuf, ptr + 16, (long) tmp - (long) ( ptr + 16 ) ); conn_data->postlen = strtoumax( postlenbuf, NULL, 0 ); if ( conn_data->postlen < 0 ) { zs_write( sockfd, html_error_400, sizeof( html_error_400 ) ); goto cleanup; } } // Write the message length size_t msglen = ( endofhdrs - conn_data->buffer ) + conn_data->postlen + sizeof( conn_data->addr.sin_addr ) + 1; if ( hp ) msglen += strlen( hp->h_name ); if ( msg_write( website->sockfd, conn_data->msgid, (void*) &msglen, sizeof( size_t ) ) == -1 ) { zs_write( sockfd, html_error_502, sizeof( html_error_502 ) ); goto cleanup; } // Write the ip address and hostname of the request if ( msg_write( website->sockfd, conn_data->msgid, (void*) &conn_data->addr.sin_addr, sizeof( conn_data->addr.sin_addr ) ) == -1 || ( hp && msg_write( website->sockfd, conn_data->msgid, (void*) hp->h_name, strlen( hp->h_name ) ) == -1 ) || msg_write( website->sockfd, conn_data->msgid, (void*) "\0", 1 ) == -1 ) { zs_write( sockfd, html_error_502, sizeof( html_error_502 ) ); goto cleanup; } // Send the whole header to the website if ( msg_write( website->sockfd, conn_data->msgid, (void*) conn_data->buffer, ( endofhdrs - conn_data->buffer ) ) == -1 ) { zs_write( sockfd, html_error_502, sizeof( html_error_502 ) ); goto cleanup; } ptr = endofhdrs; } else { if ( !( website = website_get_by_sockfd( conn_data->website_sockfd ) ) ) { // syslog( LOG_WARNING, "exread: no website to service request" ); zs_write( sockfd, html_error_502, sizeof( html_error_502 ) ); goto cleanup; } } if ( conn_data->request_type == HTTP_POST_TYPE && conn_data->postlen ) { int left = conn_data->bufferlen - ( ptr - (void*)conn_data->buffer ); if ( left > conn_data->postlen ) conn_data->postlen = left; if ( msg_write( website->sockfd, conn_data->msgid, (void*) ptr, left ) == -1 ) { zs_write( sockfd, html_error_502, sizeof( html_error_502 ) ); goto cleanup; } conn_data->postlen -= left; } if ( !conn_data->postlen ) { /* If there isn't more data coming, */ msg_flush( website->sockfd, conn_data->msgid ); /* must make sure to keep sockfd in read mode to detect a connection close from the other end */ conn_data->postlen = -1; zs_set_read( sockfd ); } else msg_set_write( website->sockfd, conn_data->msgid ); free( conn_data->buffer ); conn_data->buffer = NULL; //printf( "%d: still needs %d post data\n", sockfd, conn_data->postlen ); }