Created
October 2, 2011 12:34
-
-
Save swoodtke/1257407 to your computer and use it in GitHub Desktop.
A wrapper for connecting and binding to TCP/UDP sockets
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 <sys/types.h> | |
#include <sys/socket.h> | |
#include <netdb.h> | |
#include <string.h> | |
#include <assert.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <ctype.h> | |
#include <stdio.h> | |
static int connection_addr(const char *addr, struct addrinfo **info, int server); | |
int connection_bind(const char *addr) | |
{ | |
struct addrinfo *info = NULL; | |
int st = connection_addr(addr, &info, 1); | |
if (st < 0) return st; | |
int sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol); | |
if (sock < 0) { | |
freeaddrinfo(info); | |
return sock; | |
} | |
st = bind(sock, info->ai_addr, info->ai_addrlen); | |
freeaddrinfo(info); | |
if (st < 0) { | |
close(sock); | |
return st; | |
} | |
return sock; | |
} | |
int connection_connect(const char *addr) | |
{ | |
struct addrinfo *info = NULL; | |
int st = connection_addr(addr, &info, 0); | |
if (st < 0) return st; | |
int sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol); | |
if (sock < 0) { | |
freeaddrinfo(info); | |
return sock; | |
} | |
st = connect(sock, info->ai_addr, info->ai_addrlen); | |
freeaddrinfo(info); | |
if (st < 0) { | |
close(sock); | |
return st; | |
} | |
return sock; | |
} | |
static int connection_addr(const char *addr, struct addrinfo **info, int server) | |
{ | |
// an addr is <type>://<host>:<port> | |
const char *ptr = addr; | |
int i, st; | |
struct addrinfo hints; | |
memset(&hints, 0, sizeof hints); | |
if (strncasecmp(addr, "tcp://", strlen("tcp://")) == 0) { | |
ptr += strlen("tcp://"); | |
hints.ai_family = AF_INET; | |
hints.ai_socktype = SOCK_STREAM; | |
hints.ai_protocol = IPPROTO_TCP; | |
} else if (strncasecmp(addr, "udp://", strlen("udp://")) == 0) { | |
ptr += strlen("udp://"); | |
hints.ai_family = AF_INET; | |
hints.ai_socktype = SOCK_DGRAM; | |
hints.ai_protocol = IPPROTO_UDP; | |
} else { | |
errno = ENOSYS; | |
return -1; | |
} | |
char host[256]; | |
char port[16]; | |
for (i = 0; *ptr != ':' && *ptr != '\0' && i < sizeof(host); ++ptr, ++i) { | |
host[i] = *ptr; | |
} | |
if (*ptr == '\0' || i == sizeof(host)) { | |
errno = EINVAL; | |
return -1; | |
} | |
ptr += 1; // skip the ':' | |
host[i] = '\0'; | |
for (i = 0; *ptr != '\0' && isdigit(*ptr) && i < sizeof(port); ++ptr, ++i) { | |
port[i] = *ptr; | |
} | |
if (i == sizeof(port)) { | |
errno = EINVAL; | |
return -1; | |
} | |
port[i] = '\0'; | |
st = getaddrinfo(host, port, &hints, info); | |
if (st != 0) { | |
errno = EINVAL; | |
return -1; | |
} | |
if (server && host[0] == '\0') { | |
// an empty host is returned as "localhost" when it should refer to all hosts when | |
// binding to a server | |
struct sockaddr_in *a = (struct sockaddr_in *)(*info)->ai_addr; | |
a->sin_addr.s_addr = htonl(INADDR_ANY); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment