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 + -
显示快捷键?