Skip to content

Instantly share code, notes, and snippets.

@swoodtke
Created October 2, 2011 12:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save swoodtke/1257407 to your computer and use it in GitHub Desktop.
Save swoodtke/1257407 to your computer and use it in GitHub Desktop.
A wrapper for connecting and binding to TCP/UDP sockets
#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