-
-
Save n-miyo/981019 to your computer and use it in GitHub Desktop.
select/recvfrom issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <limits.h> | |
#include <err.h> | |
#include <netdb.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <sys/select.h> | |
#define MYBUFSIZ 16384 | |
#define CONTENT_LENGTH "Content-Length: " | |
#define DELIMITER "\r\n\r\n" | |
static char *prog; | |
static size_t min, should, actual; | |
struct response { | |
ssize_t content_length; | |
ssize_t hlen; | |
ssize_t blen; | |
int found_delimiter; | |
}; | |
int | |
read_data(int s, struct response *resp) | |
{ | |
char buf[MYBUFSIZ]; | |
ssize_t n; | |
memset(buf, 0, sizeof(buf)); | |
if ((n = recv(s, buf, sizeof(buf), 0)) == -1) { | |
errx(1, "recv"); | |
} | |
fprintf(stderr, "-read: %zd\n", n); | |
printf("%s", buf); | |
if (resp->found_delimiter) { | |
resp->blen += n; | |
} else { | |
char *s = buf, *p; | |
resp->hlen += n; | |
if ((p = strcasestr(buf, CONTENT_LENGTH))) { | |
char *pp; | |
for (pp = p+sizeof(CONTENT_LENGTH)-1; *pp != '\r'; pp++) { | |
resp->content_length = resp->content_length*10 + (*pp - '0'); | |
} | |
s = pp; | |
} | |
if ((p = strcasestr(s, DELIMITER))) { | |
ssize_t num = (p-buf+4); /* 4 for DELIMITER */ | |
resp->hlen = resp->hlen - n + num; | |
resp->blen = n - num; | |
resp->found_delimiter++; | |
} | |
} | |
return n; | |
} | |
int | |
send_data(int s, const char* host, const char *command) | |
{ | |
ssize_t pos = 0; | |
ssize_t rem; | |
ssize_t n; | |
char p[8192]; /* XXX */ | |
snprintf(p, 8192, | |
"%s HTTP/1.1\r\n" | |
"User-Agent: c\r\n" | |
"Host: %s\r\n" | |
"Accept: */*\r\n" | |
"\r\n", command, host); | |
rem = strlen(p); | |
do { | |
if ((n = send(s, p+pos, rem, 0)) == -1) { | |
errx(1, "send"); | |
} | |
pos += n; | |
rem =- n; | |
} while (rem > 0); | |
return 0; | |
} | |
int | |
do_select(int s, int w) | |
{ | |
fd_set fds; | |
FD_ZERO(&fds); | |
FD_SET(s, &fds); | |
if ((select(s+1, &fds, NULL, NULL, NULL) <= 0) | |
|| (!FD_ISSET(s, &fds))) { | |
errx(1, "select"); | |
} | |
if (w > 0) { | |
struct timespec ts; | |
ts.tv_sec = w / 1000; | |
ts.tv_nsec = (w % 1000) * 1000000; | |
nanosleep(&ts, 0); | |
} | |
return s; | |
} | |
/* From: man 3 getaddrinfo */ | |
int | |
do_connect(const char *host, const char *port) | |
{ | |
struct addrinfo hints, *res, *res0; | |
int error; | |
int s; | |
const char *cause = NULL; | |
memset(&hints, 0, sizeof(hints)); | |
hints.ai_family = PF_UNSPEC; | |
hints.ai_socktype = SOCK_STREAM; | |
error = getaddrinfo(host, port, &hints, &res0); | |
if (error) { | |
errx(1, "%s", gai_strerror(error)); | |
/*NOTREACHED*/ | |
} | |
s = -1; | |
for (res = res0; res; res = res->ai_next) { | |
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | |
if (s < 0) { | |
cause = "socket"; | |
continue; | |
} | |
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { | |
cause = "connect"; | |
close(s); | |
s = -1; | |
continue; | |
} | |
break; /* okay we got one */ | |
} | |
if (s < 0) { | |
err(1, "%s", cause); | |
/*NOTREACHED*/ | |
} | |
freeaddrinfo(res0); | |
return s; | |
} | |
int | |
run(const char *host, const char *port, int w, const char *command) | |
{ | |
int s; | |
ssize_t n = 1, t; | |
struct response resp; | |
memset(&resp, 0, sizeof(resp)); | |
s = do_connect(host, port); | |
send_data(s, host, command); | |
while (n) { | |
n = read_data(do_select(s, w), &resp); | |
if (resp.content_length && resp.blen >= resp.content_length) { | |
break; | |
} | |
} | |
close(s); | |
t = (resp.blen + resp.hlen); | |
fprintf(stderr, "hlen: %zd\n", resp.hlen); | |
fprintf(stderr, "clen: %zd\n", resp.content_length); | |
fprintf(stderr, "blen: %zd\n", resp.blen); | |
fprintf(stderr, "diff: %zd\n", resp.content_length-resp.blen); | |
fprintf(stderr, "totl: %zd\n", t); | |
min = resp.blen > min ? min : resp.blen; | |
should += resp.content_length; | |
actual += resp.blen; | |
return 0; | |
} | |
void | |
usage() | |
{ | |
fprintf(stderr, "usage: %s: host port wsec command num\n", prog); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
int i; | |
prog = argv[0]; | |
if (argc != 6) { | |
usage(); | |
exit(1); | |
} | |
min = SSIZE_MAX; /* XXX */ | |
for (i = 0; i < atoi(argv[5]); i++) { | |
run(argv[1], argv[2], atoi(argv[3]), argv[4]); | |
} | |
fprintf(stderr, "MIN : %zd\n", min); | |
fprintf(stderr, "SHLD: %zd\n", should); | |
fprintf(stderr, "ACTL: %zd\n", actual); | |
fprintf(stderr, "DIFF: %zd\n", should-actual); | |
return 0; | |
} | |
/* EOF */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment