httping-1.5.8/0000755000175000017500000000000012110676213013077 5ustar folkertfolkerthttping-1.5.8/error.h0000644000175000017500000000017012110676213014377 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ void error_exit(char *format, ...); httping-1.5.8/license.OpenSSL0000644000175000017500000000003012110676213015717 0ustar folkertfolkertPlease see license.txt. httping-1.5.8/mem.h0000644000175000017500000000035712110676213014033 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ void * mymalloc(int size, char *what); void * myrealloc(void *oldp, int newsize, char *what); void myfree(void *p); char * mystrdup(char *in, char *what); httping-1.5.8/io.h0000644000175000017500000000052512110676213013661 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ ssize_t read_to(int fd, char *whereto, size_t len, int timeout); ssize_t myread(int fd, char *whereto, size_t len, int timeout); ssize_t mywrite(int fd, char *wherefrom, size_t len, int timeout); int set_fd_nonblocking(int fd); int set_fd_blocking(int fd); httping-1.5.8/Makefile0000644000175000017500000000514612110676213014545 0ustar folkertfolkert# The GPL applies to this program. # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the # OpenSSL library under certain conditions as described in each # individual source file, and distribute linked combinations # including the two. # You must obey the GNU General Public License in all respects # for all of the code used other than OpenSSL. If you modify # file(s) with this exception, you may extend this exception to your # version of the file(s), but you are not obligated to do so. If you # do not wish to do so, delete this exception statement from your # version. If you delete this exception statement from all source # files in the program, then also delete it here. include version TARGET=httping DEBUG=yes WFLAGS=-Wall -W OFLAGS=-O3 CFLAGS+=$(WFLAGS) $(OFLAGS) -DVERSION=\"$(VERSION)\" PACKAGE=$(TARGET)-$(VERSION) PREFIX=/usr BINDIR=$(PREFIX)/bin MANDIR=$(PREFIX)/share/man DOCDIR=$(PREFIX)/share/doc/$(TARGET) INSTALL=install INSTALLDIR=$(INSTALL) -m 0755 -d INSTALLBIN=$(INSTALL) -m 0755 INSTALLMAN=$(INSTALL) -m 0644 INSTALLDOC=$(INSTALL) -m 0644 STRIP=/usr/bin/strip RMDIR=/bin/rm -rf MKDIR=/bin/mkdir ARCHIVE=/bin/tar cf - COMPRESS=/bin/gzip -9 OBJS=mem.o http.o io.o str.o error.o utils.o main.o tcp.o res.o MANS=httping.1 DOCS=license.txt license.OpenSSL readme.txt # support for tcp fast open? # TFO=yes ifeq ($(SSL),no) CFLAGS+=-DNO_SSL else OBJS+=mssl.o LDFLAGS+=-lssl -lcrypto endif ifeq ($(TFO),yes) CFLAGS+=-DTCP_TFO endif ifeq ($(DEBUG),yes) CFLAGS+=-D_DEBUG -ggdb LDFLAGS+=-g endif ifeq ($(ARM),yes) CC=arm-linux-gcc endif all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(WFLAGS) $(OBJS) $(LDFLAGS) -o $(TARGET) # # Oh, blatant plug: http://keetweej.vanheusden.com/wishlist.html install: $(TARGET) $(INSTALLDIR) $(DESTDIR)/$(BINDIR) $(INSTALLBIN) $(TARGET) $(DESTDIR)/$(BINDIR) $(INSTALLDIR) $(DESTDIR)/$(MANDIR)/man1 $(INSTALLMAN) $(MANS) $(DESTDIR)/$(MANDIR)/man1 $(INSTALLDIR) $(DESTDIR)/$(DOCDIR) $(INSTALLDOC) $(DOCS) $(DESTDIR)/$(DOCDIR) ifneq ($(DEBUG),yes) $(STRIP) $(DESTDIR)/$(BINDIR)/$(TARGET) endif clean: $(RMDIR) $(OBJS) $(TARGET) *~ core cov-int package: clean # source package $(RMDIR) $(PACKAGE)* $(MKDIR) $(PACKAGE) $(INSTALLDOC) *.c *.h Makefile version $(MANS) $(DOCS) $(PACKAGE) $(ARCHIVE) $(PACKAGE) | $(COMPRESS) > $(PACKAGE).tgz $(RMDIR) $(PACKAGE) check: cppcheck -v --enable=all --std=c++11 --inconclusive -I. . 2> err.txt coverity: clean rm -rf cov-int CC=gcc cov-build --dir cov-int make all tar vczf ~/site/coverity/httping.tgz README cov-int/ putsite -q /home/folkert/.coverity-hp.sh httping-1.5.8/utils.h0000644000175000017500000000027612110676213014415 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ double get_ts(void); #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) httping-1.5.8/main.c0000644000175000017500000007216612110676213014203 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NO_SSL #include #include "mssl.h" #endif #include #include "gen.h" #include "http.h" #include "io.h" #include "str.h" #include "mem.h" #include "tcp.h" #include "res.h" #include "utils.h" #include "error.h" static volatile int stop = 0; int quiet = 0; char machine_readable = 0; char nagios_mode = 0; char last_error[ERROR_BUFFER_SIZE]; void version(void) { fprintf(stderr, "HTTPing v" VERSION ", (C) 2003-2013 folkert@vanheusden.com\n"); #ifndef NO_SSL fprintf(stderr, "SSL support included\n"); #endif } void help_long(void) { fprintf(stderr, "--url -g\n"); fprintf(stderr, "--hostname -h\n"); fprintf(stderr, "--port -p\n"); fprintf(stderr, "--host-port -x\n"); fprintf(stderr, "--count -c\n"); fprintf(stderr, "--interval -i\n"); fprintf(stderr, "--timeout -t\n"); fprintf(stderr, "--ipv6 - 6\n"); fprintf(stderr, "--show-statusodes -s\n"); fprintf(stderr, "--split-time -S\n"); fprintf(stderr, "--get-request -G\n"); fprintf(stderr, "--show-transfer-speed -b\n"); fprintf(stderr, "--show-xfer-speed-compressed -B\n"); fprintf(stderr, "--data-limit -L\n"); fprintf(stderr, "--show-kb -X\n"); #ifndef NO_SSL fprintf(stderr, "--use-ssl -l\n"); fprintf(stderr, "--show-fingerprint -z\n"); #endif fprintf(stderr, "--flood -f\n"); fprintf(stderr, "--audible-ping -a\n"); fprintf(stderr, "--parseable-output -m\n"); fprintf(stderr, "--ok-result-codes -o\n"); fprintf(stderr, "--result-string -e\n"); fprintf(stderr, "--user-agent -I\n"); fprintf(stderr, "--referer -R\n"); fprintf(stderr, "--resolve-once -r\n"); fprintf(stderr, "--nagios-mode-1 -n\n"); fprintf(stderr, "--nagios-mode-2 -n\n"); fprintf(stderr, "--bind-to -y\n"); fprintf(stderr, "--quiet -q\n"); fprintf(stderr, "--basic-auth -A\n"); fprintf(stderr, "--username -U\n"); fprintf(stderr, "--password -P\n"); fprintf(stderr, "--cookie -C\n"); fprintf(stderr, "--persistent-connections -Q\n"); fprintf(stderr, "--no-cache -Z\n"); fprintf(stderr, "--tcp-fast-open -F\n"); fprintf(stderr, "--version -V\n"); fprintf(stderr, "--help -H\n"); } void usage(void) { fprintf(stderr, "\n-g url url (e.g. -g http://localhost/)\n"); fprintf(stderr, "-h hostname hostname (e.g. localhost)\n"); fprintf(stderr, "-p portnr portnumber (e.g. 80)\n"); fprintf(stderr, "-x host:port hostname+portnumber of proxyserver\n"); fprintf(stderr, "-c count how many times to connect\n"); fprintf(stderr, "-i interval delay between each connect, can be only smaller than 1 if user is root\n"); fprintf(stderr, "-t timeout timeout (default: 30s)\n"); fprintf(stderr, "-Z ask any proxies on the way not to cache the requests\n"); fprintf(stderr, "-Q use a persistent connection. adds a 'C' to the output if httping had to reconnect\n"); fprintf(stderr, "-6 use IPv6\n"); fprintf(stderr, "-s show statuscodes\n"); fprintf(stderr, "-S split time in connect-time and processing time\n"); fprintf(stderr, "-G do a GET request instead of HEAD (read the\n"); fprintf(stderr, " contents of the page as well)\n"); fprintf(stderr, "-b show transfer speed in KB/s (use with -G)\n"); fprintf(stderr, "-B like -b but use compression if available\n"); fprintf(stderr, "-L x limit the amount of data transferred (for -b)\n"); fprintf(stderr, " to 'x' (in bytes)\n"); fprintf(stderr, "-X show the number of KB transferred (for -b)\n"); #ifndef NO_SSL fprintf(stderr, "-l connect using SSL\n"); fprintf(stderr, "-z show fingerprint (SSL)\n"); #endif fprintf(stderr, "-f flood connect (no delays)\n"); fprintf(stderr, "-a audible ping\n"); fprintf(stderr, "-m give machine parseable output (see\n"); fprintf(stderr, " also -o and -e)\n"); fprintf(stderr, "-o rc,rc,... what http results codes indicate 'ok'\n"); fprintf(stderr, " coma seperated WITHOUT spaces inbetween\n"); fprintf(stderr, " default is 200, use with -e\n"); fprintf(stderr, "-e str string to display when http result code\n"); fprintf(stderr, " doesn't match\n"); fprintf(stderr, "-I str use 'str' for the UserAgent header\n"); fprintf(stderr, "-R str use 'str' for the Referer header\n"); fprintf(stderr, "-r resolve hostname only once (usefull when\n"); fprintf(stderr, " pinging roundrobin DNS: also takes the first\n"); fprintf(stderr, " DNS lookup out of the loop so that the first\n"); fprintf(stderr, " measurement is also correct)\n"); fprintf(stderr, "-W do not abort the program if resolving failed: keep retrying\n"); fprintf(stderr, "-n warn,crit Nagios-mode: return 1 when avg. response time\n"); fprintf(stderr, " >= warn, 2 if >= crit, otherwhise return 0\n"); fprintf(stderr, "-N x Nagios mode 2: return 0 when all fine, 'x'\n"); fprintf(stderr, " when anything failes\n"); fprintf(stderr, "-y ip[:port] bind to ip-address (and thus interface) [/port]\n"); fprintf(stderr, "-q quiet, only returncode\n"); fprintf(stderr, "-A Activate Basic authentication\n"); fprintf(stderr, "-U username needed for authentication\n"); fprintf(stderr, "-P password needed for authentication\n"); fprintf(stderr, "-T x read the password fom the file 'x' (replacement for -P)\n"); fprintf(stderr, "-C cookie=value Add a cookie to the request\n"); fprintf(stderr, "-V show the version\n\n"); fprintf(stderr, "\n"); fprintf(stderr, "-J list long options\n"); fprintf(stderr, "\n"); } void emit_error() { if (!quiet && !machine_readable && !nagios_mode) printf("%s", last_error); if (!nagios_mode) last_error[0] = 0x00; fflush(NULL); } void handler(int sig) { fprintf(stderr, "Got signal %d\n", sig); stop = 1; } /* Base64 encoding start */ const char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; void encode_tryptique(char source[3], char result[4]) /* Encode 3 char in B64, result give 4 Char */ { int tryptique, i; tryptique = source[0]; tryptique *= 256; tryptique += source[1]; tryptique *= 256; tryptique += source[2]; for (i=0; i<4; i++) { result[3-i] = alphabet[tryptique%64]; tryptique /= 64; } } int enc_b64(char *source, size_t source_lenght, char *target) { /* Divide string /3 and encode trio */ while (source_lenght >= 3) { encode_tryptique(source, target); source_lenght -= 3; source += 3; target += 4; } /* Add padding to the rest */ if (source_lenght > 0) { char pad[3]; memset(pad, 0, sizeof(pad)); memcpy(pad, source, source_lenght); encode_tryptique(pad, target); target[3] = '='; if (source_lenght == 1) target[2] = '='; target += 4; } target[0] = 0; return 1; } /* Base64 encoding END */ const char * read_file(const char *file) { char buffer[4096] = { 0 }, *lf = NULL; FILE *fh = fopen(file, "rb"); if (!fh) error_exit("Cannot open password-file %s", file); if (!fgets(buffer, sizeof buffer, fh)) error_exit("Problem reading password from file %s", file); fclose(fh); lf = strchr(buffer, '\n'); if (lf) *lf = 0x00; return strdup(buffer); } int main(int argc, char *argv[]) { char *hostname = NULL; char *proxy = NULL, *proxyhost = NULL; int proxyport = 8080; int portnr = 80; char *get = NULL, *request = NULL; int req_len = 0; int c = 0; int count = -1, curncount = 0; double wait = 1.0; int audible = 0; int ok = 0, err = 0; double min = 999999999999999.0, avg = 0.0, max = 0.0; int timeout=30; char show_statuscodes = 0; char use_ssl = 0; char *ok_str = "200"; char *err_str = "-1"; char *useragent = NULL; char *referer = NULL; char *host = NULL; const char *pwd = NULL; const char *usr = NULL; char *cookie = NULL; int port = 0; char resolve_once = 0; char auth_mode = 0; char have_resolved = 0; int req_sent = 0; double nagios_warn=0.0, nagios_crit=0.0; int nagios_exit_code = 2; double avg_httping_time = -1.0; int get_instead_of_head = 0; char *buffer = NULL; int page_size = sysconf(_SC_PAGESIZE); char show_Bps = 0, ask_compression = 0; int Bps_min = 1 << 30, Bps_max = 0; long long int Bps_avg = 0; int Bps_limit = -1; char show_bytes_xfer = 0, show_fp = 0; int fd = -1; SSL *ssl_h = NULL; struct sockaddr_in *bind_to = NULL; struct sockaddr_in bind_to_4; struct sockaddr_in6 bind_to_6; char bind_to_valid = 0; char split = 0, use_ipv6 = 0; char persistent_connections = 0, persistent_did_reconnect = 0; char no_cache = 0; char *getcopyorg = NULL; char tfo = 0; char abort_on_resolve_failure = 1; static struct option long_options[] = { {"url", 1, NULL, 'g' }, {"hostname", 1, NULL, 'h' }, {"port", 1, NULL, 'p' }, {"host-port", 1, NULL, 'x' }, {"count", 1, NULL, 'c' }, {"persistent-connections", 0, NULL, 'Q' }, {"interval", 1, NULL, 'i' }, {"timeout", 1, NULL, 't' }, {"ipv6", 0, NULL, '6' }, {"show-statusodes", 0, NULL, 's' }, {"split-time", 0, NULL, 'S' }, {"get-request", 0, NULL, 'G' }, {"show-transfer-speed", 0, NULL, 'b' }, {"show-xfer-speed-compressed", 0, NULL, 'B' }, {"data-limit", 1, NULL, 'L' }, {"show-kb", 0, NULL, 'X' }, {"no-cache", 0, NULL, 'Z' }, #ifndef NO_SSL {"use-ssl", 0, NULL, 'l' }, {"show-fingerprint", 0, NULL, 'z' }, #endif {"flood", 0, NULL, 'f' }, {"audible-ping", 0, NULL, 'a' }, {"parseable-output", 0, NULL, 'm' }, {"ok-result-codes", 1, NULL, 'o' }, {"result-string", 1, NULL, 'e' }, {"user-agent", 1, NULL, 'I' }, {"referer", 1, NULL, 'S' }, {"resolve-once",0, NULL, 'r' }, {"nagios-mode-1", 1, NULL, 'n' }, {"nagios-mode-2", 1, NULL, 'n' }, {"bind-to", 1, NULL, 'y' }, {"quiet", 0, NULL, 'q' }, {"basic-auth", 0, NULL, 'A' }, {"username", 1, NULL, 'U' }, {"password", 1, NULL, 'P' }, {"cookie", 1, NULL, 'C' }, {"version", 0, NULL, 'V' }, {"help", 0, NULL, 'H' }, {NULL, 0, NULL, 0 } }; signal(SIGPIPE, SIG_IGN); if (page_size == -1) page_size = 4096; buffer = (char *)mymalloc(page_size, "receive buffer"); while((c = getopt_long(argc, argv, "WT:JZQ6Sy:XL:bBg:h:p:c:i:Gx:t:o:e:falqsmV?I:R:rn:N:z:AP:U:C:F", long_options, NULL)) != -1) { switch(c) { case 'W': abort_on_resolve_failure = 0; break; case 'T': pwd = read_file(optarg); break; case 'J': help_long(); return 0; case 'Z': no_cache = 1; break; case '6': use_ipv6 = 1; break; case 'S': split = 1; break; case 'Q': persistent_connections = 1; break; case 'y': { char *dummy = strchr(optarg, ':'); bind_to_valid = 1; if (dummy) { bind_to = (struct sockaddr_in *)&bind_to_6; memset(&bind_to_6, 0x00, sizeof(bind_to_6)); bind_to_6.sin6_family = AF_INET6; if (inet_pton(AF_INET6, optarg, &(bind_to_6.sin6_addr)) != 1) { error_exit("cannot convert ip address '%s' (for -y)\n", optarg); } } else { bind_to = (struct sockaddr_in *)&bind_to_4; memset(&bind_to_4, 0x00, sizeof(bind_to_4)); bind_to_4.sin_family = AF_INET; if (inet_pton(AF_INET, optarg, &(bind_to_4.sin_addr)) != 1) { error_exit("cannot convert ip address '%s' (for -y)\n", optarg); } } } break; case 'z': show_fp = 1; break; case 'X': show_bytes_xfer = 1; break; case 'L': Bps_limit = atoi(optarg); break; case 'B': show_Bps = 1; ask_compression = 1; break; case 'b': show_Bps = 1; break; case 'e': err_str = optarg; break; case 'o': ok_str = optarg; break; case 'x': proxy = optarg; break; case 'g': get = optarg; break; case 'r': resolve_once = 1; break; case 'h': hostname = strdup(optarg); break; case 'p': portnr = atoi(optarg); break; case 'c': count = atoi(optarg); break; case 'i': wait = atof(optarg); if (wait < 1.0 && getuid() != 0) { fprintf(stderr, "Only root can use intervals smaller than 1\n"); wait = 1.0; } break; case 't': timeout = atoi(optarg); break; case 'I': useragent = optarg; break; case 'R': referer = optarg; break; case 'a': audible = 1; break; case 'f': wait = 0; break; case 'G': get_instead_of_head = 1; break; #ifndef NO_SSL case 'l': use_ssl = 1; break; #endif case 'm': machine_readable = 1; break; case 'q': quiet = 1; break; case 's': show_statuscodes = 1; break; case 'V': version(); return 0; case 'n': { char *dummy = strchr(optarg, ','); if (nagios_mode) error_exit("-n and -N are mutual exclusive\n"); nagios_mode = 1; if (!dummy) error_exit("-n: missing parameter\n"); nagios_warn = atof(optarg); nagios_crit = atof(dummy + 1); } break; case 'N': if (nagios_mode) error_exit("-n and -N are mutual exclusive\n"); nagios_mode = 2; nagios_exit_code = atoi(optarg); break; case 'A': auth_mode = 1; break; case 'P': pwd = optarg; break; case 'U': usr = optarg; break; case 'C': cookie = optarg; break; case 'F': #ifdef TCP_TFO tfo = 1; #else printf("Warning: TCP TFO is not supported. Disabling.\n"); #endif break; case 'H': version(); usage(); return 0; case '?': default: version(); usage(); return 1; } } if (optind < argc) get = argv[optind]; last_error[0] = 0x00; if (!get_instead_of_head && show_Bps) error_exit("-b/-B can only be used when also using -G\n"); if(tfo && use_ssl) error_exit("TCP Fast open and SSL not supported together\n"); if (get != NULL && hostname == NULL) { char *slash, *colon; char *getcopy = mystrdup(get, "get request"); getcopyorg = getcopy; if (strncasecmp(getcopy, "http://", 7) == 0) { getcopy += 7; } else if (strncasecmp(getcopy, "https://", 8) == 0) { getcopy += 8; use_ssl = 1; } /* if (strncasecmp(getcopy, http_string, http_string_len) != 0) { fprintf(stderr, "'%s' is a strange URL\n", getcopy); fprintf(stderr, "Expected: %s...\n", http_string); if (strncasecmp(getcopy, "https://", 8) == 0) fprintf(stderr, "Did you forget to add the '-l' switch to the httping commandline?\n"); return 2; } */ slash = strchr(getcopy, '/'); if (slash) *slash = 0x00; if (!use_ipv6) { colon = strchr(getcopy, ':'); if (colon) { *colon = 0x00; portnr = atoi(colon + 1); } } hostname = getcopy; } if (hostname == NULL) { usage(); error_exit("No hostname/getrequest given\n"); } #ifndef NO_SSL if (use_ssl && portnr == 80) portnr = 443; #endif if (get == NULL) { #ifndef NO_SSL if (use_ssl) { get = mymalloc(8 /* http:// */ + strlen(hostname) + 1 /* colon */ + 5 /* portnr */ + 1 /* / */ + 1 /* 0x00 */, "get"); sprintf(get, "https://%s:%d/", hostname, portnr); } else { #endif get = mymalloc(7 /* http:// */ + strlen(hostname) + 1 /* colon */ + 5 /* portnr */ + 1 /* / */ + 1 /* 0x00 */, "get"); sprintf(get, "http://%s:%d/", hostname, portnr); #ifndef NO_SSL } #endif } if (proxy) { char *dummy = strchr(proxy, ':'); proxyhost = proxy; if (dummy) { *dummy=0x00; proxyport = atoi(dummy + 1); } if (!quiet && !nagios_mode) fprintf(stderr, "Using proxyserver: %s:%d\n", proxyhost, proxyport); } #ifndef NO_SSL SSL_CTX *client_ctx = NULL; if (use_ssl) { client_ctx = initialize_ctx(); if (!client_ctx) { snprintf(last_error, sizeof last_error, "problem creating SSL context\n"); goto error_exit; } } #endif request = mymalloc(strlen(get) + 8192, "request"); if (proxyhost) sprintf(request, "%s %s HTTP/1.%c\r\n", get_instead_of_head?"GET":"HEAD", get, persistent_connections?'1':'0'); else { char *dummy = get, *slash; if (strncasecmp(dummy, "http://", 7) == 0) dummy += 7; else if (strncasecmp(dummy, "https://", 7) == 0) dummy += 8; slash = strchr(dummy, '/'); if (slash) sprintf(request, "%s %s HTTP/1.%c\r\n", get_instead_of_head?"GET":"HEAD", slash, persistent_connections?'1':'0'); else sprintf(request, "%s / HTTP/1.%c\r\n", get_instead_of_head?"GET":"HEAD", persistent_connections?'1':'0'); } if (useragent) sprintf(&request[strlen(request)], "User-Agent: %s\r\n", useragent); else sprintf(&request[strlen(request)], "User-Agent: HTTPing v" VERSION "\r\n"); sprintf(&request[strlen(request)], "Host: %s\r\n", hostname); if (referer) sprintf(&request[strlen(request)], "Referer: %s\r\n", referer); if (ask_compression) sprintf(&request[strlen(request)], "Accept-Encoding: gzip,deflate\r\n"); if (no_cache) { sprintf(&request[strlen(request)], "Pragma: no-cache\r\n"); sprintf(&request[strlen(request)], "Cache-Control: no-cache\r\n"); } /* Basic Authentification */ if (auth_mode) { char auth_string[255]; char b64_auth_string[255]; if (usr == NULL) error_exit("Basic Authnetication (-A) can only be used with a username and/or password (-U -P) "); sprintf(auth_string,"%s:%s",usr,pwd); enc_b64(auth_string, strlen(auth_string), b64_auth_string); sprintf(&request[strlen(request)], "Authorization: Basic %s\r\n", b64_auth_string); } /* Cookie Insertion */ if (cookie) { sprintf(&request[strlen(request)], "Cookie: %s;\r\n", cookie); } if (persistent_connections) sprintf(&request[strlen(request)], "Connection: keep-alive\r\n"); strcat(request, "\r\n"); req_len = strlen(request); if (!quiet && !machine_readable && !nagios_mode) printf("PING %s:%d (%s):\n", hostname, portnr, get); signal(SIGINT, handler); signal(SIGTERM, handler); timeout *= 1000; /* change to ms */ host = proxyhost?proxyhost:hostname; port = proxyhost?proxyport:portnr; struct sockaddr_in6 addr; struct addrinfo *ai = NULL, *ai_use; double started_at = get_ts(); if (resolve_once) { if (resolve_host(host, &ai, use_ipv6, port) == -1) { err++; emit_error(); have_resolved = 0; if (abort_on_resolve_failure) error_exit(last_error); } ai_use = select_resolved_host(ai, use_ipv6); if (!ai_use) { snprintf(last_error, sizeof last_error, "No valid IPv4 or IPv6 address found for %s\n", host); if (abort_on_resolve_failure) error_exit(last_error); // do not emit the resolve-error here: as 'have_resolved' is set to 0 // next, the program will try to resolve again anyway // this prevents a double error-message while err is increased only // once have_resolved = 0; } if (have_resolved) get_addr(ai_use, &addr); } if (persistent_connections) fd = -1; while((curncount < count || count == -1) && stop == 0) { double ms; double dstart, dend, dafter_connect = 0.0; char *reply; int Bps = 0; char is_compressed = 0; long long int bytes_transferred = 0; dstart = get_ts(); for(;;) { char *fp = NULL; int rc; char *sc = NULL, *scdummy = NULL; int persistent_tries = 0; int len = 0, overflow = 0, headers_len; curncount++; persistent_loop: if ((!resolve_once || (resolve_once == 1 && have_resolved == 0)) && fd == -1) { memset(&addr, 0x00, sizeof(addr)); if (ai) { freeaddrinfo(ai); ai = NULL; } if (resolve_host(host, &ai, use_ipv6, port) == -1) { err++; emit_error(); if (abort_on_resolve_failure) error_exit(last_error); break; } ai_use = select_resolved_host(ai, use_ipv6); if (!ai_use) { snprintf(last_error, sizeof last_error, "No valid IPv4 or IPv6 address found for %s\n", host); emit_error(); err++; if (abort_on_resolve_failure) error_exit(last_error); break; } get_addr(ai_use, &addr); have_resolved = 1; } req_sent = 0; if ((persistent_connections && fd < 0) || !persistent_connections) { fd = connect_to((struct sockaddr *)(bind_to_valid?bind_to:NULL), ai, timeout, &tfo, request, req_len, &req_sent); } if (fd == RC_CTRLC) /* ^C pressed */ break; if (fd < 0) { emit_error(); fd = -1; } if (fd >= 0) { /* set socket to low latency */ if (set_tcp_low_latency(fd) == -1) { close(fd); fd = -1; break; } /* set fd blocking */ if (set_fd_blocking(fd) == -1) { close(fd); fd = -1; break; } #ifndef NO_SSL if (use_ssl && ssl_h == NULL) { BIO *s_bio = NULL; int rc = connect_ssl(fd, client_ctx, &ssl_h, &s_bio, timeout); if (rc != 0) { close(fd); fd = rc; if (persistent_connections && ++persistent_tries < 2) { persistent_did_reconnect = 1; goto persistent_loop; } } } #endif } if (split) dafter_connect = get_ts(); if (fd < 0) { if (fd == RC_TIMEOUT) snprintf(last_error, sizeof last_error, "timeout connecting to host\n"); emit_error(); err++; fd = -1; break; } #ifndef NO_SSL if (use_ssl) rc = WRITE_SSL(ssl_h, request, req_len); else #endif { if(!req_sent) rc = mywrite(fd, request, req_len, timeout); else rc = req_len; } if (rc != req_len) { if (persistent_connections) { if (++persistent_tries < 2) { close(fd); fd = -1; persistent_did_reconnect = 1; goto persistent_loop; } } if (rc == -1) snprintf(last_error, sizeof last_error, "error sending request to host\n"); else if (rc == RC_TIMEOUT) snprintf(last_error, sizeof last_error, "timeout sending to host\n"); else if (rc == RC_CTRLC) {/* ^C */} else if (rc == 0) snprintf(last_error, sizeof last_error, "connection prematurely closed by peer\n"); emit_error(); close(fd); fd = -1; err++; break; } rc = get_HTTP_headers(fd, ssl_h, &reply, &overflow, timeout); if ((show_statuscodes || machine_readable) && reply != NULL) { /* statuscode is in first line behind * 'HTTP/1.x' */ char *dummy = strchr(reply, ' '); if (dummy) { sc = strdup(dummy + 1); /* lines are normally terminated with a * CR/LF */ dummy = strchr(sc, '\r'); if (dummy) *dummy = 0x00; dummy = strchr(sc, '\n'); if (dummy) *dummy = 0x00; } } if (ask_compression && reply != NULL) { char *encoding = strstr(reply, "\nContent-Encoding:"); if (encoding) { char *dummy = strchr(encoding + 1, '\n'); if (dummy) *dummy = 0x00; dummy = strchr(encoding + 1, '\r'); if (dummy) *dummy = 0x00; if (strstr(encoding, "gzip") == 0 || strstr(encoding, "deflate") == 0) is_compressed = 1; } } if (persistent_connections && show_bytes_xfer && reply != NULL) { char *length = strstr(reply, "\nContent-Length:"); if (!length) { snprintf(last_error, sizeof last_error, "'Content-Length'-header missing!\n"); emit_error(); close(fd); fd = -1; break; } len = atoi(&length[17]); } headers_len = 0; if (reply) { headers_len = strlen(reply) + 4; free(reply); } if (rc < 0) { if (persistent_connections) { if (++persistent_tries < 2) { close(fd); fd = -1; persistent_did_reconnect = 1; goto persistent_loop; } } if (rc == RC_SHORTREAD) snprintf(last_error, sizeof last_error, "short read during receiving reply-headers from host\n"); else if (rc == RC_TIMEOUT) snprintf(last_error, sizeof last_error, "timeout while receiving reply-headers from host\n"); emit_error(); close(fd); fd = -1; err++; break; } ok++; if (get_instead_of_head && show_Bps) { double dl_start = get_ts(), dl_end; int cur_limit = Bps_limit; if (persistent_connections) { if (cur_limit == -1 || len < cur_limit) cur_limit = len - overflow; } for(;;) { int n = cur_limit != -1 ? min(cur_limit - bytes_transferred, page_size) : page_size; int rc = read(fd, buffer, n); if (rc == -1) { if (errno != EINTR && errno != EAGAIN) error_exit("read failed"); } else if (rc == 0) break; bytes_transferred += rc; if (cur_limit != -1 && bytes_transferred >= cur_limit) break; } dl_end = get_ts(); Bps = bytes_transferred / max(dl_end - dl_start, 0.000001); Bps_min = min(Bps_min, Bps); Bps_max = max(Bps_max, Bps); Bps_avg += Bps; } dend = get_ts(); #ifndef NO_SSL if (use_ssl && !persistent_connections) { if (show_fp && ssl_h != NULL) { fp = get_fingerprint(ssl_h); } if (close_ssl_connection(ssl_h, fd) == -1) { snprintf(last_error, sizeof last_error, "error shutting down ssl\n"); emit_error(); } SSL_free(ssl_h); ssl_h = NULL; } #endif if (!persistent_connections) { close(fd); fd = -1; } ms = (dend - dstart) * 1000.0; avg += ms; min = min > ms ? ms : min; max = max < ms ? ms : max; if (machine_readable) { if (sc) { char *dummy = strchr(sc, ' '); if (dummy) *dummy = 0x00; if (strstr(ok_str, sc)) { printf("%f", ms); } else { printf("%s", err_str); } if (show_statuscodes) printf(" %s", sc); } else { printf("%s", err_str); } if(audible) putchar('\a'); printf("\n"); } else if (!quiet && !nagios_mode) { char current_host[1024]; char *operation = !persistent_connections ? "connected to" : "pinged host"; if (getnameinfo((const struct sockaddr *)&addr, sizeof(addr), current_host, sizeof(current_host), NULL, 0, NI_NUMERICHOST) == -1) snprintf(current_host, sizeof(current_host), "getnameinfo() failed: %d", errno); if (persistent_connections && show_bytes_xfer) printf("%s %s:%d (%d/%d bytes), seq=%d ", operation, current_host, portnr, headers_len, len, curncount-1); else printf("%s %s:%d (%d bytes), seq=%d ", operation, current_host, portnr, headers_len, curncount-1); if (split) printf("time=%.2f+%.2f=%.2f ms %s", (dafter_connect - dstart) * 1000.0, (dend - dafter_connect) * 1000.0, ms, sc?sc:""); else printf("time=%.2f ms %s", ms, sc?sc:""); if (persistent_did_reconnect) { printf(" C"); persistent_did_reconnect = 0; } if (show_Bps) { printf(" %dKB/s", Bps / 1024); if (show_bytes_xfer) printf(" %dKB", (int)(bytes_transferred / 1024)); if (ask_compression) { printf(" ("); if (!is_compressed) printf("not "); printf("compressed)"); } } if (use_ssl && show_fp && fp != NULL) { printf(" %s", fp); free(fp); } if(audible) putchar('\a'); printf("\n"); } if (show_statuscodes && ok_str != NULL && sc != NULL) { scdummy = strchr(sc, ' '); if (scdummy) *scdummy = 0x00; if (strstr(ok_str, sc) == NULL) { ok--; err++; } } free(sc); break; } fflush(NULL); if (curncount != count && !stop) usleep((useconds_t)(wait * 1000000.0)); } if (ok) avg_httping_time = avg / (double)ok; else avg_httping_time = -1.0; double total_took = get_ts() - started_at; if (!quiet && !machine_readable && !nagios_mode) { printf("--- %s ping statistics ---\n", get); if (curncount == 0 && err > 0) fprintf(stderr, "internal error! (curncount)\n"); if (count == -1) printf("%d connects, %d ok, %3.2f%% failed, time %.0fms\n", curncount, ok, (((double)err) / ((double)curncount)) * 100.0, total_took * 1000.0); else printf("%d connects, %d ok, %3.2f%% failed, time %.0fms\n", curncount, ok, (((double)err) / ((double)count)) * 100.0, total_took * 1000.0); if (ok > 0) { printf("round-trip min/avg/max = %.1f/%.1f/%.1f ms\n", min, avg_httping_time, max); if (show_Bps) printf("Transfer speed: min/avg/max = %d/%d/%d KB\n", Bps_min / 1024, (int)(Bps_avg / ok) / 1024, Bps_max / 1024); } } error_exit: if (nagios_mode == 1) { if (ok == 0) { printf("CRITICAL - connecting failed: %s", last_error); return 2; } else if (avg_httping_time >= nagios_crit) { printf("CRITICAL - average httping-time is %.1f\n", avg_httping_time); return 2; } else if (avg_httping_time >= nagios_warn) { printf("WARNING - average httping-time is %.1f\n", avg_httping_time); return 1; } printf("OK - average httping-time is %.1f (%s)|ping=%f\n", avg_httping_time, last_error, avg_httping_time); } else if (nagios_mode == 2) { if (ok && last_error[0] == 0x00) { printf("OK - all fine, avg httping time is %.1f|ping=%f\n", avg_httping_time, avg_httping_time); return 0; } printf("%s: - failed: %s", nagios_exit_code == 1?"WARNING":(nagios_exit_code == 2?"CRITICAL":"ERROR"), last_error); return nagios_exit_code; } freeaddrinfo(ai); free(request); free(buffer); free(getcopyorg); if (ok) return 0; else return 127; } httping-1.5.8/io.c0000644000175000017500000000621612110676213013657 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #include #include #include #include #include #include #include #include "gen.h" ssize_t read_to(int fd, char *whereto, size_t len, int timeout) { for(;;) { ssize_t rc; struct timeval to; fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds); to.tv_sec = timeout / 1000; to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000; rc = select(fd + 1, &rfds, NULL, NULL, &to); if (rc == 0) return RC_TIMEOUT; else if (rc == -1) { if (errno == EINTR || errno == EAGAIN) continue; snprintf(last_error, sizeof last_error, "myread::select failed: %s\n", strerror(errno)); return RC_SHORTREAD; } return read(fd, whereto, len); } } ssize_t myread(int fd, char *whereto, size_t len, int timeout) { ssize_t cnt=0; while(len>0) { ssize_t rc; struct timeval to; fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds); to.tv_sec = timeout / 1000; to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000; rc = select(fd + 1, &rfds, NULL, NULL, &to); if (rc == 0) return RC_TIMEOUT; else if (rc == -1) { if (errno == EINTR || errno == EAGAIN) continue; snprintf(last_error, sizeof last_error, "myread::select failed: %s\n", strerror(errno)); return RC_SHORTREAD; } if (FD_ISSET(fd, &rfds)) { rc = read(fd, whereto, len); if (rc == -1) { if (errno != EINTR && errno != EAGAIN) { snprintf(last_error, sizeof last_error, "myread::read failed: %s\n", strerror(errno)); return RC_SHORTREAD; } } else if (rc == 0) { break; } else { whereto += rc; len -= rc; cnt += rc; } } } return cnt; } ssize_t mywrite(int fd, char *wherefrom, size_t len, int timeout) { ssize_t cnt=0; while(len>0) { ssize_t rc; struct timeval to; fd_set wfds; FD_ZERO(&wfds); FD_SET(fd, &wfds); to.tv_sec = timeout / 1000; to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000; rc = select(fd + 1, NULL, &wfds, NULL, &to); if (rc == 0) return -2; else if (rc == -1) { if (errno == EINTR || errno == EAGAIN) continue; snprintf(last_error, sizeof last_error, "mywrite::select failed: %s\n", strerror(errno)); return -1; } rc = write(fd, wherefrom, len); if (rc == -1) { if (errno != EINTR && errno != EAGAIN) { snprintf(last_error, sizeof last_error, "mywrite::write failed: %s\n", strerror(errno)); return -1; } } else if (rc == 0) { break; } else { wherefrom += rc; len -= rc; cnt += rc; } } return cnt; } int set_fd_nonblocking(int fd) { /* set fd to non-blocking */ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { fprintf(stderr, "set_fd_nonblocking failed! (%s)\n", strerror(errno)); return -1; } return 0; } int set_fd_blocking(int fd) { /* set fd to blocking */ if (fcntl(fd, F_SETFL, 0) == -1) { fprintf(stderr, "set_fd_blocking failed! (%s)\n", strerror(errno)); return -1; } return 0; } httping-1.5.8/httping.10000644000175000017500000001214112110676213014635 0ustar folkertfolkert.\" Copyright Folkert van Heusden, 2003-2013 .\" .\" This file may be copied under the conditions described .\" in the GNU GENERAL PUBLIC LICENSE, version 2 .\" that can be found on the website of the free software .\" foundation. .\" .TH HTTPING 1 2013-11 "httping" .SH NAME httping - measure the lateceny and throughput of a webserver .SH SYNOPSIS .BI "httping [" options "] .sp options: .BI "[\-g url] [\-h hostname] [\-p portnumber] [\-x proxyhost:port] [\-c count] [\-i interval] [\-t timeout] [\-s] [\-G] [\-b] [\-L xferlimit] [\-X] [\-l] [\-z] [\-f] [\-m] [\-o rc,...] [\-e string]" .BI "[\-I useragent string] [\-R referer string] [\-r] [\-n warn,crit] [\-N mode] [\-q] [\-V]" .SH DESCRIPTION The program .B httping lets you measure the latency of a webserver. Since version 1.0.6 also the throughput can be measured. .PP .SH OPTIONS .TP .B "\-g url" This selects the url to probe. E.g.: http://localhost/ .TP .B "\-h hostname" Instead of '-g' one can also set a hostname to probe with -h: -h localhost .TP .B "\-p portnumber" -p can be used together with -h. -p selects the portnumber to probe. .TP .B "\-x proxyhost:port] Probe using a proxyserver. Note that you're also measuring the latency of the proxyserver! .TP .B "\-c count" How many probes to send before exiting. .TP .B "\-i interval" How many seconds to sleep between every probe sent. .TP .B "\-t timeout" How long to wait for answer from the other side. .TP .B "\-S" Split measured latency in time to connect and time to exchange a request with the HTTP server. .TP .B "\-s" When a successfull transaction was done, show the HTTP statuscode (200, 404, etc.). .TP .B "\-G" Do a GET request instead of a HEAD request: this means that also the complete page/file must be transferred. Note that in this case you're no longer measuring the latency! .TP .B "\-b" Use this switch together with '-G'. When this option is used, the transferspeed (in KB/s) is shown. .TP .B "\-B" Use this switch together with '-G'. Ask the HTTP server to compress the returned data: this will reduce the influence of the bandwidth of your connection while increasing the influence of the processorpower of the HTTP server. .TP .B "\-L x" Use this switch together with '-G'. Limit the amount of data transferred to 'x'. Note that this only affects the content of the page/file and not the headerdata. .TP .B "\-X" Use this switch together with '-G'. For each "ping" show the amount of data transferred (excluding the headers). .TP .B "\-l" Connect using SSL: for this to work you need to give a 'https'-url or a 443 portnumber. .TP .B "\-z" When connecting using SSL, display the fingerprint of the X509 certificate(s) of the peer. .TP .B "\-a" Audible ping .TP .B "\-f" Flood ping: do not sit idle between each ping but ping as fast as the computer and network allow you to. .TP .B "\-m" Show machine readable output (also check '-o' and '-e'). .TP .B "\-o x,x,..." This selects the HTTP status-codes which are regarded as an OK-state (only with '-m'). .TP .B "\-e str" When the status-code differs from the ones selected with '-o', the given string is displayed. .TP .B "\-I str" UserAgent-string to send to the webserver (instead of 'HTTPing '). .TP .B "\-R str" Referer-string to send to the webserver. .TP .B "\-r" Only resolve the hostname once: this takes the resolving out of the loop so that the latency of the DNS is not measured. Also usefull when you want to measure only 1 webserver while the DNS returns a different ip-address for each resolve ('roundrobin'). .TP .B "\-n warn,crit" Switches HTTPing to Nagios-plugin mode 1: return exitcode '1' when the average response time is bigger then 'warn', return exitcode '2' when the the average response time is bigger then 'crit'. In all other cases return exitcode '0'. .TP .B "\-N x" Switches HTTPing to Nagios-plugin mode 2: return 0 when everything is fine, 'x' when anything fails. E.g.: 1 => Nagios warning state, 2 => Nagios critical state. .TP .B "\-q" Be quiet, only return an exit-code. .TP .B "\-A,U,P" Activate the basic authentication, Username follow the -U, Password the -P. .TP .B "\-F" Attempt TCP Fast Open while trying to connect to a server (for Linux, version 3.7 onwards of the kernel) .TP .B "\-V" Show the version and exit. .SH KEYS Press + to exit the program. It will display a summary of what was measured. .SH EXAMPLES .TP .B "httping \-g http://localhost/" Ping the webserver on host 'localhost'. .TP .B "httping \-h localhost \-p 1000" Ping the webserver on host 'localhost' and portnumber 1000. .TP .B "httping \-l \-g https://localhost/" Ping the webserver on host 'localhost' using an SSL connection. .TP .B "httping \-g http://localhost/ -A -U username -P password" Ping the webserver on host 'localhost' using the Basic HTTP Authentication. .SH BUGS None. This program is totally bug-free. .SH "SEE ALSO" .BR http://www.vanheusden.com/httping/ .SH NOTES This page describes .B httping as found in the httping-1.5.8 package; other versions may differ slightly. Please mail corrections and additions to folkert@vanheusden.com. Report bugs in the program to folkert@vanheusden.com. Please consider sending bitcoins to 1N5Sn4jny4xVwTwSYLnf7WnFQEGoVRmTQF httping-1.5.8/res.h0000644000175000017500000000054212110676213014042 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #define incopy(a) *((struct in_addr *)a) int resolve_host(char *host, struct addrinfo **ai, char use_ipv6, int portnr); struct addrinfo * select_resolved_host(struct addrinfo *ai, char use_ipv6); void get_addr(struct addrinfo *ai_use, struct sockaddr_in6 *addr); httping-1.5.8/tcp.c0000644000175000017500000000660612110676213014041 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #include #include #include #include #include #include #include #include #include "gen.h" #include "io.h" #include "tcp.h" int connect_to(struct sockaddr *bind_to, struct addrinfo *ai, int timeout, char *tfo, char *msg, int msg_len, int *msg_accepted) { int fd; int rc; struct timeval to; fd_set wfds; /* create socket */ fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd == -1) { snprintf(last_error, sizeof last_error, "problem creating socket (%s)", strerror(errno)); return -1; } /* go through a specific interface? */ if (bind_to) { int set = 1; /* set reuse flags */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)) == -1) { close(fd); snprintf(last_error, sizeof last_error, "error setting sockopt to interface (%s)", strerror(errno)); return -1; } if (bind(fd, bind_to, sizeof(*bind_to)) == -1) { close(fd); snprintf(last_error, sizeof last_error, "error binding to interface (%s)", strerror(errno)); return -1; } } /* make fd nonblocking */ if (set_fd_nonblocking(fd) == -1) { close(fd); return -1; } /* wait for connection */ FD_ZERO(&wfds); FD_SET(fd, &wfds); to.tv_sec = timeout / 1000; to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000; /* connect to peer */ #ifdef TCP_TFO if (*tfo) { rc = sendto(fd, msg, msg_len, MSG_FASTOPEN, ai -> ai_addr, ai -> ai_addrlen); if(rc == msg_len) *msg_accepted = 1; if(errno == 0) return fd; if(errno == ENOTSUP) { printf("TCP TFO Not Supported. Please check if \"/proc/sys/net/ipv4/tcp_fastopen\" is 1. Disabling TFO for now.\n"); *tfo = 0; } } else #endif { int rc = connect(fd, ai -> ai_addr, ai -> ai_addrlen); if (rc == 0) { /* connection made, return */ return fd; } if (rc == -1) { // problem connecting if (errno != EINPROGRESS) { snprintf(last_error, sizeof last_error, "problem connecting to host: %s\n", strerror(errno)); close(fd); return -1; } } } /* wait for connection */ rc = select(fd + 1, NULL, &wfds, NULL, &to); if (rc == 0) { snprintf(last_error, sizeof last_error, "connect time out\n"); close(fd); return RC_TIMEOUT; /* timeout */ } else if (rc == -1) { close(fd); if (errno == EINTR) return RC_CTRLC;/* ^C pressed */ snprintf(last_error, sizeof last_error, "select() failed: %s\n", strerror(errno)); return -1; /* error */ } else { int optval=0; socklen_t optvallen=sizeof(optval); /* see if the connect succeeded or failed */ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, &optvallen) == -1) { snprintf(last_error, sizeof last_error, "getsockopt failed (%s)\n", strerror(errno)); close(fd); return -1; } /* no error? */ if (optval == 0) return fd; /* don't ask */ errno = optval; } close(fd); snprintf(last_error, sizeof last_error, "could not connect (%s)\n", strerror(errno)); return -1; } int set_tcp_low_latency(int sock) { int flag = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0) { snprintf(last_error, sizeof last_error, "could not set TCP_NODELAY on socket (%s)\n", strerror(errno)); return -1; } return 0; } httping-1.5.8/utils.c0000644000175000017500000000065512110676213014411 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #include #include #include #include "error.h" double get_ts(void) { struct timeval ts; struct timezone tz; if (gettimeofday(&ts, &tz) == -1) error_exit("gettimeofday failed"); return (double)ts.tv_sec + ((double)ts.tv_usec)/1000000.0; } httping-1.5.8/res.c0000644000175000017500000000214212110676213014033 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #include #include #include #include #include #include #include "gen.h" #include "res.h" #include "error.h" int resolve_host(char *host, struct addrinfo **ai, char use_ipv6, int portnr) { char servname[10]; struct addrinfo myaddr; memset(&myaddr, 0, sizeof(myaddr)); /* myaddr.ai_flags = AI_PASSIVE; */ myaddr.ai_socktype = SOCK_STREAM; myaddr.ai_protocol = IPPROTO_TCP; myaddr.ai_family = use_ipv6 ? AF_INET6 : AF_INET; snprintf(servname, sizeof(servname), "%d", portnr); return getaddrinfo(host, servname, &myaddr, ai); } struct addrinfo * select_resolved_host(struct addrinfo *ai, char use_ipv6) { struct addrinfo *p = ai; while(p) { if (p -> ai_family == AF_INET6 && use_ipv6) return p; if (p -> ai_family == AF_INET) return ai; } return NULL; } void get_addr(struct addrinfo *ai_use, struct sockaddr_in6 *addr) { memcpy(addr, ai_use->ai_addr, ai_use->ai_addrlen); } httping-1.5.8/gen.h0000644000175000017500000000102512110676213014017 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #define RC_OK 0 #define RC_SHORTREAD -1 #define RC_TIMEOUT -2 #define RC_CTRLC -3 #ifdef NO_SSL #define SSL void #define SSL_CTX void #define BIO void #endif #define ERROR_BUFFER_SIZE 4096 #ifdef TCP_TFO #ifndef MSG_FASTOPEN #define MSG_FASTOPEN 0x20000000 #endif #ifndef TCP_FASTOPEN #define TCP_FASTOPEN 23 #endif #ifndef TCPI_OPT_SYN_DATA #define TCPI_OPT_SYN_DATA 32 #endif #endif extern char last_error[ERROR_BUFFER_SIZE]; httping-1.5.8/error.c0000644000175000017500000000070712110676213014400 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #include #include #include #include void error_exit(char *format, ...) { va_list ap; va_start(ap, format); (void)vfprintf(stderr, format, ap); va_end(ap); fprintf(stderr, "\n\nerrno=%d which means %s (if applicable)\n", errno, strerror(errno)); exit(1); } httping-1.5.8/str.c0000644000175000017500000000056612110676213014062 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include "error.h" #include "mem.h" #include "utils.h" /* Most unixes have this function already. #ifndef _GNU_SOURCE char *strndup(char *in, int size) { char *out = mymalloc(size + 1, "strndup"); memcpy(out, in, size); out[size] = 0x00; return out; } #endif */ httping-1.5.8/http.c0000644000175000017500000000246712110676213014233 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #ifndef NO_SSL #include #include "mssl.h" #endif #include "gen.h" #include "mem.h" #include "http.h" #include "io.h" #include "str.h" #include "utils.h" int get_HTTP_headers(int socket_h, SSL *ssl_h, char **headers, int *overflow, int timeout) { int len_in=0, len=4096; char *buffer = mymalloc(len, "http header"); int rc = RC_OK; *headers = NULL; memset(buffer, 0x00, len); for(;;) { int rrc; int now_n = (len - len_in) - 1; #ifndef NO_SSL if (ssl_h) rrc = SSL_read(ssl_h, &buffer[len_in], now_n); else #endif rrc = read_to(socket_h, &buffer[len_in], now_n, timeout); if (rrc == 0 || rrc == RC_SHORTREAD) /* socket closed before request was read? */ { rc = RC_SHORTREAD; break; } else if (rrc == RC_TIMEOUT) /* timeout */ { free(buffer); return RC_TIMEOUT; } len_in += rrc; buffer[len_in] = 0x00; if (strstr(buffer, "\r\n\r\n") != NULL) break; if (len_in == (len - 1)) { len <<= 1; buffer = (char *)myrealloc(buffer, len, "http reply"); } } *headers = buffer; char *term = strstr(buffer, "\r\n\r\n"); if (term) *overflow = len_in - (term - buffer + 4); else *overflow = 0; return rc; } httping-1.5.8/tcp.h0000644000175000017500000000037112110676213014037 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ int connect_to(struct sockaddr *bind_to, struct addrinfo *ai, int timeout, char *tfo, char *msg, int msg_len, int *msg_accepted); int set_tcp_low_latency(int sock); httping-1.5.8/http.h0000644000175000017500000000026012110676213014225 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ int get_HTTP_headers(int socket_h, SSL *ssl_h, char **headers, int *overflow, int timeout); httping-1.5.8/mssl.c0000644000175000017500000000635212110676213014227 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include #include #include #include #include #include #include #include #include #include "gen.h" #include "mssl.h" BIO *bio_err=0; char close_ssl_connection(SSL *ssl_h, int socket_h) { int rc = SSL_shutdown(ssl_h); if (!rc) { shutdown(socket_h, 1); rc = SSL_shutdown(ssl_h); } /* rc == 0 means try again but it seems to be fine * to ignore that is what I read from the manpage */ if (rc == -1) return -1; else return 0; } int READ_SSL(SSL *ssl_h, char *whereto, int len) { int cnt=len; while(len>0) { int rc; rc = SSL_read(ssl_h, whereto, len); if (rc == -1) { if (errno != EINTR && errno != EAGAIN) { sprintf(last_error, "READ_SSL: io-error: %s\n", strerror(errno)); return -1; } } else if (rc == 0) { return 0; } else { whereto += rc; len -= rc; } } return cnt; } int WRITE_SSL(SSL *ssl_h, char *whereto, int len) { int cnt=len; while(len>0) { int rc; rc = SSL_write(ssl_h, whereto, len); if (rc == -1) { if (errno != EINTR && errno != EAGAIN) { sprintf(last_error, "WRITE_SSL: io-error: %s\n", strerror(errno)); return -1; } } else if (rc == 0) { return 0; } else { whereto += rc; len -= rc; } } return cnt; } int connect_ssl(int socket_h, SSL_CTX *client_ctx, SSL **ssl_h, BIO **s_bio, int timeout) { int dummy; // FIXME handle t/o #if 0 int rc; struct timeval to; fd_set rfds; FD_ZERO(&rfds); FD_SET(socket_h, &rfds); to.tv_sec = timeout / 1000; to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000; /* wait for connection */ rc = select(socket_h + 1, &rfds, NULL, NULL, &to); if (rc == 0) return -2; /* timeout */ else if (rc == -1) { if (errno == EINTR) return -3; /* ^C pressed */ else return -1; /* error */ } #endif *ssl_h = SSL_new(client_ctx); *s_bio = BIO_new_socket(socket_h, BIO_NOCLOSE); SSL_set_bio(*ssl_h, *s_bio, *s_bio); dummy = SSL_connect(*ssl_h); if (dummy <= 0) { sprintf(last_error, "problem starting SSL connection: %d\n", SSL_get_error(*ssl_h, dummy)); return -1; } return 0; } SSL_CTX * initialize_ctx(void) { if (!bio_err) { SSL_library_init(); SSL_load_error_strings(); /* error write context */ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); } /* create context */ const SSL_METHOD *meth = SSLv23_method(); return SSL_CTX_new(meth); } char * get_fingerprint(SSL *ssl_h) { char *string = NULL; unsigned char fp_digest[EVP_MAX_MD_SIZE]; X509 *x509_data = SSL_get_peer_certificate(ssl_h); if (x509_data) { unsigned int fp_digest_size = sizeof(fp_digest); memset(fp_digest, 0x00, sizeof(fp_digest)); if (X509_digest(x509_data, EVP_md5(), fp_digest, &fp_digest_size)) { string = (char *)malloc(MD5_DIGEST_LENGTH * 3 + 1); if (string) { int loop, pos =0; for(loop=0; loop #include #include #include #include #include #include #include #include #include static void error_exit(char *format, ...) { va_list ap; va_start(ap, format); (void)vfprintf(stderr, format, ap); va_end(ap); if (errno) fprintf(stderr, "errno: %d=%s (if applicable)\n", errno, strerror(errno)); exit(EXIT_FAILURE); } void myfree(void *p) { free(p); } void * myrealloc(void *oldp, int new_size, char *what) { void *newp = realloc(oldp, new_size); if (!newp) error_exit("Failed to reallocate a memory block (%s) to %d bytes.\n", what, new_size); return newp; } void * mymalloc(int size, char *what) { return myrealloc(NULL, size, what); } char * mystrdup(char *in, char *what) { int len = strlen(in) + 1; char *newp = (char *)mymalloc(len, what); memcpy(newp, in, len); return newp; } httping-1.5.8/version0000644000175000017500000000001612110676213014504 0ustar folkertfolkertVERSION=1.5.8 httping-1.5.8/mssl.h0000644000175000017500000000061512110676213014230 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ char close_ssl_connection(SSL *ssl_h, int socket_h); int READ_SSL(SSL *ssl_h, char *whereto, int len); int WRITE_SSL(SSL *ssl_h, char *whereto, int len); int connect_ssl(int socket_h, SSL_CTX *client_ctx, SSL **ssl_h, BIO **s_bio, int timeout); SSL_CTX * initialize_ctx(void); char * get_fingerprint(SSL *ssl_h); httping-1.5.8/str.h0000644000175000017500000000025512110676213014062 0ustar folkertfolkert/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */ #include /* #ifndef _GNU_SOURCE char *strndup(char *in, int size); #endif */