#define _WIN32_WINNT 0x0501 #include #include #include #include #ifdef WIN32 #include #include #else #include #include #include #include #endif #include //#include "network.h" #include "network_worker.h" #include "socket.h" #include "worker.h" static struct worker s_network_worker; struct network_job { char *host; int port; network_callback callback; void *data; }; int resolve(const char *hostname, int port, struct sockaddr_in *addr) { struct addrinfo *ai; struct addrinfo hints; memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; #ifndef WIN32 hints.ai_flags = AI_ADDRCONFIG; #endif hints.ai_socktype = SOCK_STREAM; char port_name[6]; snprintf(port_name, sizeof port_name, "%u", port); int e = getaddrinfo(hostname, port_name, &hints, &ai); if (e != 0) { fprintf(stderr, "getaddrinfo: %s\n", strerror(errno)); return 0; } struct addrinfo *runp; for (runp = ai; runp != NULL; runp = runp->ai_next) { struct sockaddr_in *ai_addr = (struct sockaddr_in *)runp->ai_addr; /* Take the first address */ *addr = *ai_addr; break; } freeaddrinfo(ai); return 1; } static void network_worker(void *arg) { struct network_job *job = arg; if (job->callback != NULL) { struct sockaddr_in addr; if (!resolve(job->host, job->port, &addr)) { fprintf(stderr, "Unable to resolve %s:%d\n", job->host, job->port); if (job->callback != NULL) { job->callback(-1, job->data); } } else if (job->callback != NULL) { int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { #ifdef WIN32 fprintf(stderr, "socket: %d\n", WSAGetLastError()); #else fprintf(stderr, "socket: %s\n", strerror(errno)); #endif } else { socket_set_nonblock(fd); socket_set_nodelay(fd); if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) { #ifdef WIN32 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK) { fprintf(stderr, "connect: %d\n", WSAGetLastError()); fd = -1; } #else if (errno != EINPROGRESS && errno != EWOULDBLOCK) { fprintf(stderr, "connect: %s\n", strerror(errno)); fd = -1; } #endif } } job->callback(fd, job->data); } } free(job->host); free(job); } void network_worker_init(void) { worker_init(&s_network_worker, "network", 60000, 1, network_worker); } void network_worker_deinit(void) { worker_deinit(&s_network_worker); } void *network_connect(const char *host, int port, network_callback callback, void *data) { struct network_job *job = malloc(sizeof *job); job->host = strdup(host); job->port = port; job->callback = callback; job->data = data; worker_queue(&s_network_worker, job); return job; } int network_listen(int port, int tcp) { int fd; #ifdef USE_IPV6 fd = socket(AF_INET6, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); #else fd = socket(AF_INET, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); #endif if (fd < 0) { #ifdef WIN32 fprintf(stderr, "socket: %d\n", WSAGetLastError()); #else fprintf(stderr, "socket: %s\n", strerror(errno)); #endif return -1; } #ifdef USE_IPV6 struct sockaddr_in6 serv_addr; serv_addr.sin6_family = AF_INET6; serv_addr.sin6_addr = in6addr_any; serv_addr.sin6_port = htons(port); #else struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(port); #endif int on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof on) == -1) { fprintf(stderr, "setsockopt: Could not set SO_REUSEADDR: %s\n", strerror(errno)); } if (bind(fd, (struct sockaddr *)&serv_addr, sizeof serv_addr) < 0) { fprintf(stderr, "bind: %s\n", strerror(errno)); return -1; } socket_set_nonblock(fd); if (tcp) socket_set_nodelay(fd); return fd; }