/* Copyright Copyright (C) 2013 Andrey Uzunov This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * @file mhd2spdy_structures.h * @brief Common structures, functions, macros and global variables. * @author Andrey Uzunov */ #ifndef STRUCTURES_H #define STRUCTURES_H #define _GNU_SOURCE #include <unistd.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #include <stdio.h> #include <ctype.h> #include <errno.h> #include <assert.h> #include <microhttpd.h> #include <signal.h> #include <poll.h> #include <fcntl.h> #include <regex.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <spdylay/spdylay.h> #include <getopt.h> /* WANT_READ if SSL connection needs more input; or WANT_WRITE if it needs more output; or IO_NONE. This is necessary because SSL/TLS re-negotiation is possible at any time. Spdylay API offers similar functions like spdylay_session_want_read() and spdylay_session_want_write() but they do not take into account SSL connection. */ enum { IO_NONE, WANT_READ, WANT_WRITE }; struct Proxy; struct SPDY_Connection { SSL *ssl; spdylay_session *session; struct SPDY_Connection *prev; struct SPDY_Connection *next; struct Proxy *proxies_head; struct Proxy *proxies_tail; char *host; int fd; int want_io; uint counter; uint streams_opened; bool is_tls; }; struct URI { char * full_uri; char * scheme; char * host_and_port; char * host; char * path; char * path_and_more; char * query; char * fragment; uint16_t port; }; struct HTTP_URI; struct Proxy { struct MHD_Connection *http_connection; struct MHD_Response *http_response; struct URI *uri; struct HTTP_URI *http_uri; struct SPDY_Connection *spdy_connection; struct Proxy *next; struct Proxy *prev; char *url; char *version; void *http_body; void *received_body; size_t http_body_size; size_t received_body_size; ssize_t length; int status; int id; int32_t stream_id; bool done; bool http_error; bool spdy_error; bool http_active; bool spdy_active; bool receiving_done; }; struct HTTP_URI { char * uri; struct Proxy * proxy; }; struct SPDY_Headers { const char **nv; int num; int cnt; }; struct global_options { char *spdy2http_str; struct SPDY_Connection *spdy_connection; struct SPDY_Connection *spdy_connections_head; struct SPDY_Connection *spdy_connections_tail; int streams_opened; int responses_pending; regex_t uri_preg; size_t global_memory; SSL_CTX *ssl_ctx; uint32_t total_spdy_connections; uint16_t spdy_proto_version; uint16_t listen_port; bool verbose; bool only_proxy; bool spdy_data_received; bool statistics; bool ignore_rst_stream; } glob_opt; struct global_statistics { //unsigned long long http_bytes_sent; //unsigned long long http_bytes_received; unsigned long long spdy_bytes_sent; unsigned long long spdy_bytes_received; unsigned long long spdy_bytes_received_and_dropped; } glob_stat; //forbidden headers #define SPDY_HTTP_HEADER_TRANSFER_ENCODING "transfer-encoding" #define SPDY_HTTP_HEADER_PROXY_CONNECTION "proxy-connection" #define SPDY_HTTP_HEADER_KEEP_ALIVE "keep-alive" #define SPDY_HTTP_HEADER_CONNECTION "connection" #define MAX_SPDY_CONNECTIONS 100 #define SPDY_MAX_OUTLEN 4096 /** * Insert an element at the head of a DLL. Assumes that head, tail and * element are structs with prev and next fields. * * @param head pointer to the head of the DLL (struct ? *) * @param tail pointer to the tail of the DLL (struct ? *) * @param element element to insert (struct ? *) */ #define DLL_insert(head,tail,element) do { \ (element)->next = (head); \ (element)->prev = NULL; \ if ((tail) == NULL) \ (tail) = element; \ else \ (head)->prev = element; \ (head) = (element); } while (0) /** * Remove an element from a DLL. Assumes * that head, tail and element are structs * with prev and next fields. * * @param head pointer to the head of the DLL (struct ? *) * @param tail pointer to the tail of the DLL (struct ? *) * @param element element to remove (struct ? *) */ #define DLL_remove(head,tail,element) do { \ if ((element)->prev == NULL) \ (head) = (element)->next; \ else \ (element)->prev->next = (element)->next; \ if ((element)->next == NULL) \ (tail) = (element)->prev; \ else \ (element)->next->prev = (element)->prev; \ (element)->next = NULL; \ (element)->prev = NULL; } while (0) #define PRINT_INFO(msg) do{\ if(glob_opt.verbose){\ printf("%i:%s\n", __LINE__, msg);\ fflush(stdout);\ }\ }\ while(0) #define PRINT_INFO2(fmt, ...) do{\ if(glob_opt.verbose){\ printf("%i\n", __LINE__);\ printf(fmt,##__VA_ARGS__);\ printf("\n");\ fflush(stdout);\ }\ }\ while(0) #define DIE(msg) do{\ printf("FATAL ERROR (line %i): %s\n", __LINE__, msg);\ fflush(stdout);\ exit(EXIT_FAILURE);\ }\ while(0) #define UPDATE_STAT(stat, value) do{\ if(glob_opt.statistics)\ {\ stat += value;\ }\ }\ while(0) void free_uri(struct URI * uri); int init_parse_uri(regex_t * preg); void deinit_parse_uri(regex_t * preg); int parse_uri(regex_t * preg, char * full_uri, struct URI ** uri); void free_proxy(struct Proxy *proxy); void * au_malloc(size_t size); bool copy_buffer(const void *src, size_t src_size, void **dst, size_t *dst_size); #endif