Create a gist now

Instantly share code, notes, and snippets.

@n-miyo /c.c
Created May 19, 2011

select/recvfrom issue
#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