socket.c
来自「mms client」· C语言 代码 · 共 606 行
C
606 行
#include <ctype.h>#include <errno.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <fcntl.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <arpa/inet.h>#include <sys/utsname.h>#include "gwlib.h"static Octstr *official_name = NULL;static Octstr *official_ip = NULL;/* * FreeBSD is not happy with our approach of allocating a sockaddr * and then filling in the fields. It has private fields that need * to be initialized to 0. This structure is used for that. */static const struct sockaddr_in empty_sockaddr_in;#ifndef UDP_PACKET_MAX_SIZE#define UDP_PACKET_MAX_SIZE (64*1024)#endifint make_server_socket(int port, const char *interface_name ){ struct sockaddr_in addr; int s; int reuse; struct hostent hostinfo; s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) { error(errno, "socket failed"); goto error; } addr = empty_sockaddr_in; addr.sin_family = AF_INET; addr.sin_port = htons(port); if (interface_name == NULL || strcmp(interface_name, "*") == 0) addr.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&hostinfo, interface_name) == -1) { error(errno, "gethostbyname failed"); goto error; } addr.sin_addr = *(struct in_addr *) hostinfo.h_addr; } reuse = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { error(errno, "setsockopt failed for server address"); goto error; } if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) { error(errno, "bind failed"); goto error; } if (listen(s, 10) == -1) { error(errno, "listen failed"); goto error; } return s;error: if (s >= 0) (void) close(s); return -1;}int tcpip_connect_to_server(char *hostname, int port, const char *interface_name){ return tcpip_connect_to_server_with_port(hostname, port, 0, interface_name);}int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *interface_name){ struct sockaddr_in addr; struct sockaddr_in o_addr; struct hostent hostinfo; struct hostent o_hostinfo; int s; s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) { error(errno, "Couldn't create new socket."); goto error; } if (gw_gethostbyname(&hostinfo, hostname) == -1) { error(errno, "gethostbyname failed"); goto error; } addr = empty_sockaddr_in; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr = *(struct in_addr *) hostinfo.h_addr; if (our_port > 0 || (interface_name != NULL && strcmp(interface_name, "*") != 0)) { int reuse; o_addr = empty_sockaddr_in; o_addr.sin_family = AF_INET; o_addr.sin_port = htons(our_port); if (interface_name == NULL || strcmp(interface_name, "*") == 0) o_addr.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&o_hostinfo, interface_name) == -1) { error(errno, "gethostbyname failed"); goto error; } o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; } reuse = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { error(errno, "setsockopt failed before bind"); goto error; } if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) { error(errno, "bind to local port %d failed", our_port); goto error; } } if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) { error(errno, "connect failed"); goto error; } return s;error: error(0, "error connecting to server `%s' at port `%d'", hostname, port); if (s >= 0) close(s); return -1;}int tcpip_connect_nb_to_server(char *hostname, int port, const char *interface_name, int *done){ return tcpip_connect_nb_to_server_with_port(hostname, port, 0, interface_name, done);}int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, const char *interface_name, int *done) { struct sockaddr_in addr; struct sockaddr_in o_addr; struct hostent hostinfo; struct hostent o_hostinfo; int s; int flags,rc; *done = 1; s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) { error(errno, "Couldn't create new socket."); goto error; } if (gw_gethostbyname(&hostinfo, hostname) == -1) { error(errno, "gethostbyname failed"); goto error; } addr = empty_sockaddr_in; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr = *(struct in_addr *) hostinfo.h_addr; if (our_port > 0 || (interface_name != NULL && strcmp(interface_name, "*") != 0)) { int reuse; o_addr = empty_sockaddr_in; o_addr.sin_family = AF_INET; o_addr.sin_port = htons(our_port); if (interface_name == NULL || strcmp(interface_name, "*") == 0) o_addr.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&o_hostinfo, interface_name) == -1) { error(errno, "gethostbyname failed"); goto error; } o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; } reuse = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { error(errno, "setsockopt failed before bind"); goto error; } if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) { error(errno, "bind to local port %d failed", our_port); goto error; } } flags = fcntl(s, F_GETFL, 0); fcntl(s, F_SETFL, flags | O_NONBLOCK); if ((rc = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) { if (errno != EINPROGRESS) { error(errno, "nonblocking connect failed"); goto error; } } /* May be connected immediatly * (if we connecting to localhost for example) */ if (rc == 0) { *done = 0; } return s; error: error(0, "error connecting to server `%s' at port `%d'", hostname, port); if (s >= 0) close(s); return -1;}int write_to_socket(int socket, char *str){ size_t len; int ret; len = strlen(str); while (len > 0) { ret = write(socket, str, len); if (ret == -1) { if (errno == EAGAIN) continue; if (errno == EINTR) continue; error(errno, "Writing to socket failed"); return -1; } /* ret may be less than len, if the writing was interrupted by a signal. */ len -= ret; str += ret; } return 0;}int socket_set_blocking(int fd, int blocking){ int flags, newflags; flags = fcntl(fd, F_GETFL); if (flags < 0) { error(errno, "cannot get flags for fd %d", fd); return -1; } if (blocking) newflags = flags & ~O_NONBLOCK; else newflags = flags | O_NONBLOCK; if (newflags != flags) { if (fcntl(fd, F_SETFL, newflags) < 0) { error(errno, "cannot set flags for fd %d", fd); return -1; } } return 0;}int read_available(int fd, long wait_usec){ fd_set rf; struct timeval to; int ret; div_t waits; gw_assert(fd >= 0); FD_ZERO(&rf); FD_SET(fd, &rf); waits = div(wait_usec, 1000000); to.tv_sec = waits.quot; to.tv_usec = waits.rem;retry: ret = select(fd + 1, &rf, NULL, NULL, &to); if (ret > 0 && FD_ISSET(fd, &rf)) return 1; if (ret < 0) { /* In most select() implementations, to will now contain the * remaining time rather than the original time. That is exactly * what we want when retrying after an interrupt. */ switch (errno) { /*The first two entries here are OK*/ case EINTR: goto retry; case EAGAIN: return 1; /* We are now sucking mud, figure things out here * as much as possible before it gets lost under * layers of abstraction. */ case EBADF: if (!FD_ISSET(fd, &rf)) { warning(0, "Tried to select on fd %d, not in the set!\n", fd); } else { warning(0, "Tried to select on invalid fd %d!\n", fd); } break; case EINVAL: /* Solaris catchall "It didn't work" error, lets apply * some tests and see if we can catch it. */ /* First up, try invalid timeout*/ if (to.tv_sec > 10000000) warning(0, "Wait more than three years for a select?\n"); if (to.tv_usec > 1000000) warning(0, "There are only 1000000 usec in a second...\n"); break; } return -1; /* some error */ } return 0;}int udp_client_socket(void){ int s; s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) { error(errno, "Couldn't create a UDP socket"); return -1; } return s;}int udp_bind(int port, const char *interface_name){ int s; struct sockaddr_in sa; struct hostent hostinfo; s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) { error(errno, "Couldn't create a UDP socket"); return -1; } sa = empty_sockaddr_in; sa.sin_family = AF_INET; sa.sin_port = htons(port); if (strcmp(interface_name, "*") == 0) sa.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&hostinfo, interface_name) == -1) { error(errno, "gethostbyname failed"); return -1; } sa.sin_addr = *(struct in_addr *) hostinfo.h_addr; } if (bind(s, (struct sockaddr *) &sa, (int) sizeof(sa)) == -1) { error(errno, "Couldn't bind a UDP socket to port %d", port); (void) close(s); return -1; } return s;}Octstr *udp_create_address(Octstr *host_or_ip, int port){ struct sockaddr_in sa; struct hostent h; sa = empty_sockaddr_in; sa.sin_family = AF_INET; sa.sin_port = htons(port); if (strcmp(octstr_get_cstr(host_or_ip), "*") == 0) { sa.sin_addr.s_addr = INADDR_ANY; } else { if (gw_gethostbyname(&h, octstr_get_cstr(host_or_ip)) == -1) { error(0, "Couldn't find the IP number of `%s'", octstr_get_cstr(host_or_ip)); return NULL; } sa.sin_addr = *(struct in_addr *) h.h_addr_list[0]; } return octstr_create_from_data((char *) &sa, sizeof(sa));}int udp_get_port(Octstr *addr){ struct sockaddr_in sa; gw_assert(octstr_len(addr) == sizeof(sa)); memcpy(&sa, octstr_get_cstr(addr), sizeof(sa)); return ntohs(sa.sin_port);}Octstr *udp_get_ip(Octstr *addr){ struct sockaddr_in sa; gw_assert(octstr_len(addr) == sizeof(sa)); memcpy(&sa, octstr_get_cstr(addr), sizeof(sa)); return gw_netaddr_to_octstr(AF_INET, &sa.sin_addr);}int udp_sendto(int s, Octstr *datagram, Octstr *addr){ struct sockaddr_in sa; gw_assert(octstr_len(addr) == sizeof(sa)); memcpy(&sa, octstr_get_cstr(addr), sizeof(sa)); if (sendto(s, octstr_get_cstr(datagram), octstr_len(datagram), 0, (struct sockaddr *) &sa, (int) sizeof(sa)) == -1) { error(errno, "Couldn't send UDP packet"); return -1; } return 0;}int udp_recvfrom(int s, Octstr **datagram, Octstr **addr){ struct sockaddr_in sa; int salen; char *buf; int bytes; buf = gw_malloc(UDP_PACKET_MAX_SIZE); salen = sizeof(sa); bytes = recvfrom(s, buf, UDP_PACKET_MAX_SIZE, 0, (struct sockaddr *) &sa, &salen); if (bytes == -1) { if (errno != EAGAIN) error(errno, "Couldn't receive UDP packet"); gw_free(buf); return -1; } *datagram = octstr_create_from_data(buf, bytes); *addr = octstr_create_from_data((char *) &sa, salen); gw_free(buf); return 0;}Octstr *host_ip(struct sockaddr_in addr){ return gw_netaddr_to_octstr(AF_INET, &addr.sin_addr);}Octstr *get_official_name(void){ gw_assert(official_name != NULL); return official_name;}Octstr *get_official_ip(void){ gw_assert(official_ip != NULL); return official_ip;}static void setup_official_name(void){ struct utsname u; struct hostent h; gw_assert(official_name == NULL); if (uname(&u) == -1) panic(0, "uname failed - can't happen, unless " GW_NAME " is buggy."); if (gw_gethostbyname(&h, u.nodename) == -1) { error(0, "Can't find out official hostname for this host, " "using `%s' instead.", u.nodename); official_name = octstr_create(u.nodename); official_ip = octstr_create("127.0.0.1"); } official_name = octstr_create(h.h_name); official_ip = gw_netaddr_to_octstr(AF_INET, h.h_addr);}void socket_init(void){ setup_official_name();}void socket_shutdown(void){ octstr_destroy(official_name); official_name = NULL; octstr_destroy(official_ip); official_ip = NULL;}static Octstr *gw_netaddr_to_octstr4(unsigned char *src){ return octstr_format("%d.%d.%d.%d", src[0], src[1], src[2], src[3]);}#ifdef AF_INET6static Octstr *gw_netaddr_to_octstr6(unsigned char *src){ return octstr_format( "%x:%x:%x:%x:" "%x:%x:%x:%x:" "%x:%x:%x:%x:" "%x:%x:%x:%x", src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7], src[8], src[9], src[10], src[11], src[12], src[13], src[14], src[15]);}#endifOctstr *gw_netaddr_to_octstr(int af, void *src){ switch (af) { case AF_INET: return gw_netaddr_to_octstr4(src);#ifdef AF_INET6 case AF_INET6: return gw_netaddr_to_octstr6(src);#endif default: return NULL; } }int gw_accept(int fd, Octstr **client_addr){ struct sockaddr_in addr; int addrlen; int new_fd; if (gwthread_pollfd(fd, POLLIN, -1.0) != POLLIN) { debug("gwlib.socket", 0, "gwthread_pollfd interrupted or failed"); return -1; } addrlen = sizeof(addr); new_fd = accept(fd, (struct sockaddr *) &addr, &addrlen); if (new_fd == -1) { error(errno, "accept system call failed."); return -1; } *client_addr = host_ip(addr); debug("test_smsc", 0, "accept() succeeded, client from %s", octstr_get_cstr(*client_addr)); return new_fd;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?