-
-
Save kremso/0bb8edffd58720b5d492 to your computer and use it in GitHub Desktop.
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 <sys/stat.h> | |
#include <sys/un.h> | |
#include <sys/time.h> | |
#include <netinet/in.h> | |
#include <netinet/tcp.h> | |
#include <arpa/inet.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <netdb.h> | |
#include <errno.h> | |
#include <stdarg.h> | |
#include <stdio.h> | |
#define ANET_CONNECT_NONE 0 | |
#define ANET_CONNECT_NONBLOCK 1 | |
#define ANET_OK 0 | |
#define ANET_ERR -1 | |
#define ANET_ERR_LEN 256 | |
static void anetSetError(char *err, const char *fmt, ...) | |
{ | |
va_list ap; | |
if (!err) return; | |
va_start(ap, fmt); | |
vsnprintf(err, ANET_ERR_LEN, fmt, ap); | |
va_end(ap); | |
} | |
static int anetSetReuseAddr(char *err, int fd) { | |
int yes = 1; | |
/* Make sure connection-intensive things like the redis benckmark | |
* will be able to close/open sockets a zillion of times */ | |
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { | |
anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno)); | |
return ANET_ERR; | |
} | |
return ANET_OK; | |
} | |
int anetSetBlock(char *err, int fd, int non_block) { | |
int flags; | |
/* Set the socket blocking (if non_block is zero) or non-blocking. | |
* Note that fcntl(2) for F_GETFL and F_SETFL can't be | |
* interrupted by a signal. */ | |
if ((flags = fcntl(fd, F_GETFL)) == -1) { | |
anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno)); | |
return ANET_ERR; | |
} | |
if (non_block) | |
flags |= O_NONBLOCK; | |
else | |
flags &= ~O_NONBLOCK; | |
if (fcntl(fd, F_SETFL, flags) == -1) { | |
anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno)); | |
return ANET_ERR; | |
} | |
return ANET_OK; | |
} | |
int anetNonBlock(char *err, int fd) { | |
return anetSetBlock(err,fd,1); | |
} | |
static int anetTcpGenericConnect(char *err, char *addr, int port, | |
char *source_addr, int flags) | |
{ | |
int s = ANET_ERR, rv; | |
char portstr[6]; /* strlen("65535") + 1; */ | |
struct addrinfo hints, *servinfo, *bservinfo, *p, *b; | |
snprintf(portstr,sizeof(portstr),"%d",port); | |
memset(&hints,0,sizeof(hints)); | |
hints.ai_family = AF_UNSPEC; | |
hints.ai_socktype = SOCK_STREAM; | |
if ((rv = getaddrinfo(addr,portstr,&hints,&servinfo)) != 0) { | |
anetSetError(err, "%s", gai_strerror(rv)); | |
return ANET_ERR; | |
} | |
for (p = servinfo; p != NULL; p = p->ai_next) { | |
/* Try to create the socket and to connect it. | |
* If we fail in the socket() call, or on connect(), we retry with | |
* the next entry in servinfo. */ | |
printf("Creating socket\n"); | |
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1) | |
continue; | |
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error; | |
if (flags & ANET_CONNECT_NONBLOCK && anetNonBlock(err,s) != ANET_OK) | |
goto error; | |
if (source_addr) { | |
int bound = 0; | |
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */ | |
if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) | |
{ | |
anetSetError(err, "%s", gai_strerror(rv)); | |
goto end; | |
} | |
for (b = bservinfo; b != NULL; b = b->ai_next) { | |
int enabled = 1; | |
setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, &enabled, sizeof(enabled)); | |
if (bind(s,b->ai_addr,b->ai_addrlen) != -1) { | |
bound = 1; | |
break; | |
} | |
} | |
freeaddrinfo(bservinfo); | |
if (!bound) { | |
anetSetError(err, "bind: %s", strerror(errno)); | |
goto end; | |
} | |
} | |
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) { | |
printf(".. and failed\n"); | |
/* If the socket is non-blocking, it is ok for connect() to | |
* return an EINPROGRESS error here. */ | |
if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK) | |
goto end; | |
close(s); | |
s = ANET_ERR; | |
continue; | |
} | |
/* If we ended an iteration of the for loop without errors, we | |
* have a connected socket. Let's return to the caller. */ | |
goto end; | |
} | |
if (p == NULL) | |
anetSetError(err, "creating socket: %s", strerror(errno)); | |
error: | |
if (s != ANET_ERR) { | |
close(s); | |
s = ANET_ERR; | |
} | |
end: | |
freeaddrinfo(servinfo); | |
return s; | |
} | |
int main(char **argc, char **argv) | |
{ | |
char err[1000]; | |
char *addr = "10.134.82.199"; | |
int port = 18000; | |
char *source_addr = "127.0.0.1"; | |
int ret = anetTcpGenericConnect(err,addr,port,source_addr,ANET_CONNECT_NONBLOCK); | |
if(strlen(err) > 0) { | |
printf("There was an error: %s\n", err); | |
} | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment