Skip to content

Instantly share code, notes, and snippets.

@x-yuri
Created January 5, 2018 15:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save x-yuri/95fd4776fb9bf8f1eaae7eb2e7ed6bd4 to your computer and use it in GitHub Desktop.
Save x-yuri/95fd4776fb9bf8f1eaae7eb2e7ed6bd4 to your computer and use it in GitHub Desktop.
#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