From ea435789dc2fab30ec16fa765a0b6577fe08166a Mon Sep 17 00:00:00 2001 From: GuoWenxue <“guowenxue@gmail.com”> Date: Tue, 19 Apr 2022 10:06:03 +0800 Subject: [PATCH] update client and socket.c, add DNS support --- apue/project_socket/src/socket.c | 188 +++++++++++++++++++++++++++++----------------- 1 files changed, 118 insertions(+), 70 deletions(-) diff --git a/apue/project_socket/src/socket.c b/apue/project_socket/src/socket.c index 9de6d1a..677a3cc 100644 --- a/apue/project_socket/src/socket.c +++ b/apue/project_socket/src/socket.c @@ -8,7 +8,7 @@ * Version: 1.0.0(18/04/22) * Author: Guo Wenxue <guowenxue@gmail.com> * ChangeLog: 1, Release initial version on "18/04/22 17:09:59" - * + * ********************************************************************************/ #include <stdio.h> #include <unistd.h> @@ -18,7 +18,7 @@ #include <unistd.h> #include <sys/un.h> #include <poll.h> -#include <errno.h> +#include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <linux/sockios.h> @@ -32,8 +32,8 @@ #include "socket.h" #include "logger.h" -/* description: initial socket context - * input args: +/* description: initial socket context + * input args: * $sock: socket context pointer * $host: connect server hostname for client mode, unused for server mode * $port: connect server port for client mode or listen port for server mode @@ -51,7 +51,7 @@ } /* description: close socket - * input args: + * input args: * $sock: socket context pointer * return value: <0: failure 0:ok */ @@ -70,66 +70,114 @@ } /* description: socket server start listen - * input args: + * input args: * $sock: socket context pointer * return value: <0: failure 0:ok */ int socket_listen(socket_ctx_t *sock) { - int rv = 0; + int rv = 0; struct sockaddr_in addr; - int backlog = 13; + int backlog = 13; if( !sock ) return -1; } -/* description: socket check connected or not - * input args: +/* description: socket connect to server in block mode + * input args: * $sock: socket context pointer * return value: <0: failure 0:ok */ int socket_connect(socket_ctx_t *sock) { - int rv = 0; - int sockfd = 0; + int rv = 0; + int sockfd = 0; struct sockaddr_in servaddr; + char service[20]; + struct addrinfo hints, *rp; + struct addrinfo *res = NULL; + struct in_addr inaddr; + struct sockaddr_in addr; + int len = sizeof(addr); if( !sock ) return -1; socket_term(sock); - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if(sockfd < 0) - { - log_error("create socket failure: %s\n", strerror(errno)); - return -1; - } + /*+--------------------------------------------------+ + *| use getaddrinfo() to do domain name translation | + *+--------------------------------------------------+*/ - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family=AF_INET; - servaddr.sin_port = htons(sock->port); - inet_aton(sock->host, &servaddr.sin_addr); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; /* Only support IPv4 */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; /* TCP protocol */ - rv=connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); - if(rv < 0) - { - //log_error("connect to server[%s:%d] failure: %s\n", sock->host, sock->port, strerror(errno)); - close(sockfd); - return -2; - } + /* If $host is a valid IP address, then don't use name resolution */ + if( inet_aton(sock->host, &inaddr) ) + { + //log_info("%s is a valid IP address, don't use domain name resolution.\n", sock->host); + hints.ai_flags |= AI_NUMERICHOST; + } - log_info("Connect to server[%s:%d] on fd[%d] successfully!\n", sock->host, sock->port, sockfd); + /* Obtain address(es) matching host/port */ + snprintf(service, sizeof(service), "%d", sock->port); + if( (rv=getaddrinfo(sock->host, service, &hints, &res)) ) + { + log_error("getaddrinfo() parser [%s:%s] failed: %s\n", sock->host, service, gai_strerror(rv)); + return -3; + } - sock->fd = sockfd; + /* getaddrinfo() returns a list of address structures. Try each + address until we successfully connect or bind */ + for (rp=res; rp!=NULL; rp=rp->ai_next) + { +#if 0 + char ipaddr[INET_ADDRSTRLEN]; + struct sockaddr_in *sp = (struct sockaddr_in *) rp->ai_addr; - return 0; + /* print domain name translation result */ + memset( ipaddr, 0, sizeof(ipaddr) ); + if( inet_ntop(AF_INET, &sp->sin_addr, ipaddr, sizeof(ipaddr)) ) + { + log_info("domain name resolution [%s->%s]\n", sock->host, ipaddr); + } +#endif + + /* Create the socket */ + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if( sockfd < 0) + { + log_error("socket() create failed: %s\n", strerror(errno)); + rv = -3; + continue; + } + + /* connect to server */ + rv = connect(sockfd, rp->ai_addr, len); + if( 0 == rv ) + { + sock->fd = sockfd; + log_info("Connect to server[%s:%d] on fd[%d] successfully!\n", sock->host, sock->port, sockfd); + break; + } + else + { + /* socket connect get error, try another IP address */ + close(sockfd); + continue; + } + } + + freeaddrinfo(res); + return rv; } /* description: send data from the socket - * input args: + * input args: * $sock : socket context pointer * $data : socket send data * $bytes: socket send data bytes @@ -144,32 +192,32 @@ if( !sock || !data || bytes<= 0 ) return -1; - while( left_bytes > 0 ) - { + while( left_bytes > 0 ) + { rv=write(sock->fd, &data[i], left_bytes); - if( rv < 0 ) + if( rv < 0 ) { log_info("socket[%d] write() failure: %s, close socket now\n", sock->fd, strerror(errno)); socket_term(sock); - return -2; + return -2; } else if( rv == left_bytes ) { log_info("socket send %d bytes data over\n", bytes); return 0; } - else + else { /* not send over this time, continue to send left data */ - i += rv; - left_bytes -= rv; + i += rv; + left_bytes -= rv; continue; } - } + } } /* description: receive data from the socket - * input args: + * input args: * $sock : socket context pointer * $buf : socket receive data buffer * $size : socket receive data buffer size @@ -278,30 +326,30 @@ { int opts; /* - * fcntl may set: + * fcntl may set: * - * EACCES, EAGAIN: Operation is prohibited by locks held by other - * processes. Or, operation is prohibited because the file has - * been memory-mapped by another process. - * EBADF: fd is not an open file descriptor, or the command was F_SETLK - * or F_SETLKW and the file descriptor open mode doesn't match + * EACCES, EAGAIN: Operation is prohibited by locks held by other + * processes. Or, operation is prohibited because the file has + * been memory-mapped by another process. + * EBADF: fd is not an open file descriptor, or the command was F_SETLK + * or F_SETLKW and the file descriptor open mode doesn't match * with the type of lock requested. - * EDEADLK: It was detected that the specified F_SETLKW command would + * EDEADLK: It was detected that the specified F_SETLKW command would * cause a deadlock. * EFAULT: lock is outside your accessible address space. - * EINTR: For F_SETLKW, the command was interrupted by a signal. For - * F_GETLK and F_SETLK, the command was interrupted by a signal - * before the lock was checked or acquired. Most likely when - * locking a remote file (e.g. locking over NFS), but can + * EINTR: For F_SETLKW, the command was interrupted by a signal. For + * F_GETLK and F_SETLK, the command was interrupted by a signal + * before the lock was checked or acquired. Most likely when + * locking a remote file (e.g. locking over NFS), but can * sometimes happen locally. - * EINVAL: For F_DUPFD, arg is negative or is greater than the maximum - * allowable value. For F_SETSIG, arg is not an allowable signal + * EINVAL: For F_DUPFD, arg is negative or is greater than the maximum + * allowable value. For F_SETSIG, arg is not an allowable signal * number. - * EMFILE: For F_DUPFD, the process already has the maximum number of - * file descriptors open. - * ENOLCK: Too many segment locks open, lock table is full, or a remote + * EMFILE: For F_DUPFD, the process already has the maximum number of + * file descriptors open. + * ENOLCK: Too many segment locks open, lock table is full, or a remote * locking protocol failed (e.g. locking over NFS). - * EPERM: Attempted to clear the O_APPEND flag on a file that has the + * EPERM: Attempted to clear the O_APPEND flag on a file that has the * append-only attribute set. */ opts = fcntl(sockfd, F_GETFL); @@ -377,7 +425,7 @@ * Enable socket SO_KEEPALIVE, if the connection disconnected, any system call on socket * will return immediately and errno will be set to "WSAENOTCONN" * - * keepalive is not program related, but socket related, * so if you have multiple sockets, + * keepalive is not program related, but socket related, * so if you have multiple sockets, * you can handle keepalive for each of them separately. * * Reference: http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/ @@ -400,10 +448,10 @@ if(keepintvl || keepcnt) { /* - * The tcp_keepidle parameter specifies the interval between the last data packet sent - * (simple ACKs are not considered data) and the first keepalive probe; after the - * connection is marked to need keepalive, this counter is not used any further. - * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_time + * The tcp_keepidle parameter specifies the interval between the last data packet sent + * (simple ACKs are not considered data) and the first keepalive probe; after the + * connection is marked to need keepalive, this counter is not used any further. + * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_time * 7200 */ opt = 3; /* 3 seconds */ @@ -416,9 +464,9 @@ if((opt=keepintvl) > 0) { /* - * The tcp_keepintvl parameter specifies the interval between subsequential keepalive + * The tcp_keepintvl parameter specifies the interval between subsequential keepalive * probes, regardless of what the connection has exchanged in the meantime. - * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_intvl + * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_intvl * 75 */ if (setsockopt (sockfd, SOL_TCP, TCP_KEEPINTVL, (char *) &opt, sizeof (opt))) @@ -431,11 +479,11 @@ if((opt=keepcnt) > 0) { /* - * The TCP_KEEPCNT option specifies the maximum number of unacknowledged probes to + * The TCP_KEEPCNT option specifies the maximum number of unacknowledged probes to * send before considering the connection dead and notifying the application layer - * probes to be sent. The value of TCP_KEEPCNT is an integer value between 1 and n, - * where n is the value of the systemwide tcp_keepcnt parameter. - * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_probes + * probes to be sent. The value of TCP_KEEPCNT is an integer value between 1 and n, + * where n is the value of the systemwide tcp_keepcnt parameter. + * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_probes * 9 */ if (setsockopt (sockfd, SOL_TCP, TCP_KEEPCNT, (char *) &opt, sizeof (opt))) -- Gitblit v1.9.1