#include <libgen.h> | |
#include <limits.h> | |
#include <stdarg.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netdb.h> | |
#include <netinet/in.h> | |
#include <errno.h> | |
#include <error.h> | |
#define REMOTE_HOST "localhost" | |
#define REMOTE_PORT "8000" | |
#define BUFSIZE 4096 | |
#define CRLF "\r\n" | |
#define SAVE_GAI_ERROR(func, errno) \ | |
err_func = (func); \ | |
err_file = __FILE__; \ | |
err_line = __LINE__; \ | |
err_errno = 0; \ | |
err_gai_errno = errno; | |
#define SAVE_ERROR(func) \ | |
err_func = (func); \ | |
err_file = __FILE__; \ | |
err_line = __LINE__; \ | |
err_errno = errno; \ | |
err_gai_errno = 0; | |
#define CUR_ERRNO (err_errno || err_gai_errno) | |
const char *prog; | |
const char *err_func; | |
const char *err_file; | |
int err_line; | |
int err_errno; | |
int err_gai_errno; | |
const char* family_to_string(int family) | |
{ | |
return family == AF_INET ? "AF_INET" | |
: family == AF_INET6 ? "AF_INET6" | |
: "<unknown>"; | |
} | |
const char* socktype_to_string(int socktype) | |
{ | |
return socktype == SOCK_STREAM ? "SOCK_STREAM" | |
: socktype == SOCK_DGRAM ? "SOCK_DGRAM" | |
: "<unknown>"; | |
} | |
const char* protocol_to_string(int protocol) | |
{ | |
return protocol == IPPROTO_TCP ? "IPPROTO_TCP" | |
: protocol == IPPROTO_UDP ? "IPPROTO_UDP" | |
: "<unknown>"; | |
} | |
int get_host_serv(struct addrinfo *ai, char **phost, char **pserv) | |
{ | |
int r; | |
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; | |
char *host, *serv; | |
r = getnameinfo(ai->ai_addr, ai->ai_addrlen, | |
hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), | |
NI_NUMERICHOST | NI_NUMERICSERV); | |
if (r) { | |
SAVE_GAI_ERROR("getnameinfo", r); | |
return 1; | |
} | |
host = strdup(hbuf); | |
if ( ! host) { | |
SAVE_ERROR("strdup"); | |
return 1; | |
} | |
serv = strdup(sbuf); | |
if ( ! serv) { | |
SAVE_ERROR("strdup"); | |
free(host); | |
return 1; | |
} | |
*phost = host; | |
*pserv = serv; | |
return 0; | |
} | |
int print_addrinfo(struct addrinfo *ai) | |
{ | |
const char *family = family_to_string(ai->ai_family); | |
const char *socktype = socktype_to_string(ai->ai_socktype); | |
const char *protocol = protocol_to_string(ai->ai_protocol); | |
const char *family2 = family_to_string(ai->ai_addr->sa_family); | |
char *host, *serv; | |
int r; | |
r = get_host_serv(ai, &host, &serv); | |
if (r) { | |
return 1; | |
} | |
printf("flags=%i, family=%s, socktype=%s, protocol=%s, family=%s, host=%s, serv=%s\n", | |
ai->ai_flags, family, socktype, protocol, family2, host, serv); | |
free(host); | |
free(serv); | |
return 0; | |
} | |
int get_socket(int *psfd) | |
{ | |
int r, sfd; | |
struct addrinfo hints; | |
struct addrinfo *result, *ai; | |
memset(&hints, 0, sizeof(struct addrinfo)); | |
// hints.ai_family = AF_INET; | |
hints.ai_socktype = SOCK_STREAM; | |
r = getaddrinfo(REMOTE_HOST, REMOTE_PORT, &hints, &result); | |
if (r) { | |
SAVE_GAI_ERROR("getaddrinfo", r); | |
return 1; | |
} | |
for (ai = result; ai; ai = ai->ai_next) { | |
char *host, *serv; | |
r = get_host_serv(ai, &host, &serv); | |
if (r) { | |
freeaddrinfo(result); | |
return 1; | |
} | |
printf("creating socket for %s:%s...", host, serv); | |
sfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | |
if (sfd == -1) { | |
SAVE_ERROR("socket"); | |
} | |
printf(" %s\n", sfd == -1 ? "fail" : "done"); | |
if (sfd == -1) { | |
free(host); | |
free(serv); | |
freeaddrinfo(result); | |
return 1; | |
} | |
printf("connecting to %s:%s...", host, serv); | |
r = connect(sfd, ai->ai_addr, ai->ai_addrlen); | |
printf(" %s\n", r ? "fail" : "done"); | |
free(host); | |
free(serv); | |
if (r) { | |
close(sfd); | |
} else { | |
*psfd = sfd; | |
freeaddrinfo(result); | |
return 0; | |
} | |
} | |
freeaddrinfo(result); | |
return 1; | |
} | |
int set_prog(char *argv0) | |
{ | |
char *prog1 = strdup(argv0); | |
if ( ! prog1) { | |
prog = argv0; | |
return 1; | |
} | |
char *prog2 = basename(prog1); | |
free(prog1); | |
char *prog3 = strdup(prog2); | |
if ( ! prog3) { | |
prog = argv0; | |
return 1; | |
} | |
prog = prog3; | |
return 0; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
(void)argc; | |
int r, sfd; | |
ssize_t ss; | |
set_prog(argv[0]); | |
r = get_socket(&sfd); | |
if (r) { | |
goto error; | |
} | |
// TODO. add port | |
char request[] = "GET / HTTP/1.0" CRLF | |
"Host: " REMOTE_HOST CRLF | |
CRLF; | |
ss = write(sfd, request, sizeof(request)); | |
if (ss == -1) { | |
SAVE_ERROR("write"); | |
close(sfd); | |
goto error; | |
} else if (ss != sizeof(request)) { | |
error_at_line(1, 0, __FILE__, __LINE__, "write: %li / %lu\n", ss, sizeof(request)); | |
close(sfd); | |
exit(EXIT_FAILURE); | |
} | |
char b[BUFSIZE]; | |
while (1) { | |
ss = read(sfd, b, sizeof(b)); | |
if (ss == -1) { | |
SAVE_ERROR("read"); | |
close(sfd); | |
goto error; | |
} else if (ss == 0) { | |
close(sfd); | |
break; | |
} | |
// printf("%li\n", ss); | |
ssize_t ss2; | |
ss2 = fwrite(b, 1, ss, stdout); | |
if (ss2 != ss) { | |
error_at_line(1, 0, __FILE__, __LINE__, "fwrite: %li / %lu\n", ss2, ss); | |
close(sfd); | |
exit(EXIT_FAILURE); | |
} | |
} | |
exit(EXIT_SUCCESS); | |
error: | |
if (err_errno) | |
error_at_line(1, err_errno, err_file, err_line, "%s", err_func); | |
else if (err_gai_errno) | |
error_at_line(1, 0, err_file, err_line, "%s: %s", err_func, gai_strerror(err_gai_errno)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment