Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/socket_tests/lib/inet_sockets.c')
-rw-r--r--winsup/cygwin/socket_tests/lib/inet_sockets.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/winsup/cygwin/socket_tests/lib/inet_sockets.c b/winsup/cygwin/socket_tests/lib/inet_sockets.c
new file mode 100644
index 000000000..396dbf906
--- /dev/null
+++ b/winsup/cygwin/socket_tests/lib/inet_sockets.c
@@ -0,0 +1,188 @@
+/*************************************************************************\
+* Copyright (C) Michael Kerrisk, 2018. *
+* *
+* This program is free software. You may use, modify, and redistribute it *
+* under the terms of the GNU Lesser General Public License as published *
+* by the Free Software Foundation, either version 3 or (at your option) *
+* any later version. This program is distributed without any warranty. *
+* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
+\*************************************************************************/
+
+/* Listing 59-9 */
+
+/* inet_sockets.c
+
+ A package of useful routines for Internet domain sockets.
+*/
+#define _BSD_SOURCE /* To get NI_MAXHOST and NI_MAXSERV
+ definitions from <netdb.h> */
+#include "af_unix_hdr.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "inet_sockets.h" /* Declares functions defined here */
+
+/* The following arguments are common to several of the routines
+ below:
+
+ 'host': NULL for loopback IP address, or
+ a host name or numeric IP address
+ 'service': either a name or a port number
+ 'type': either SOCK_STREAM or SOCK_DGRAM
+*/
+
+/* Create socket and connect it to the address specified by
+ 'host' + 'service'/'type'. Return socket descriptor on success,
+ or -1 on error */
+
+int
+inetConnect(const char *host, const char *service, int type)
+{
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ int sfd, s;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+ hints.ai_family = AF_UNSPEC; /* Allows IPv4 or IPv6 */
+ hints.ai_socktype = type;
+
+ s = getaddrinfo(host, service, &hints, &result);
+ if (s != 0) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ /* Walk through returned list until we find an address structure
+ that can be used to successfully connect a socket */
+
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (sfd == -1)
+ continue; /* On error, try next address */
+
+ if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+ break; /* Success */
+
+ /* Connect failed: close this socket and try next address */
+
+ close(sfd);
+ }
+
+ freeaddrinfo(result);
+
+ return (rp == NULL) ? -1 : sfd;
+}
+
+/* Create an Internet domain socket and bind it to the address
+ { wildcard-IP-address + 'service'/'type' }.
+ If 'doListen' is TRUE, then make this a listening socket (by
+ calling listen() with 'backlog'), with the SO_REUSEADDR option set.
+ If 'addrLen' is not NULL, then use it to return the size of the
+ address structure for the address family for this socket.
+ Return the socket descriptor on success, or -1 on error. */
+
+static int /* Public interfaces: inetBind() and inetListen() */
+inetPassiveSocket(const char *service, int type, socklen_t *addrlen,
+ Boolean doListen, int backlog)
+{
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ int sfd, optval, s;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+ hints.ai_socktype = type;
+ hints.ai_family = AF_UNSPEC; /* Allows IPv4 or IPv6 */
+ hints.ai_flags = AI_PASSIVE; /* Use wildcard IP address */
+
+ s = getaddrinfo(NULL, service, &hints, &result);
+ if (s != 0)
+ return -1;
+
+ /* Walk through returned list until we find an address structure
+ that can be used to successfully create and bind a socket */
+
+ optval = 1;
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (sfd == -1)
+ continue; /* On error, try next address */
+
+ if (doListen) {
+ if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval,
+ sizeof(optval)) == -1) {
+ close(sfd);
+ freeaddrinfo(result);
+ return -1;
+ }
+ }
+
+ if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
+ break; /* Success */
+
+ /* bind() failed: close this socket and try next address */
+
+ close(sfd);
+ }
+
+ if (rp != NULL && doListen) {
+ if (listen(sfd, backlog) == -1) {
+ freeaddrinfo(result);
+ return -1;
+ }
+ }
+
+ if (rp != NULL && addrlen != NULL)
+ *addrlen = rp->ai_addrlen; /* Return address structure size */
+
+ freeaddrinfo(result);
+
+ return (rp == NULL) ? -1 : sfd;
+}
+
+/* Create stream socket, bound to wildcard IP address + port given in
+ 'service'. Make the socket a listening socket, with the specified
+ 'backlog'. Return socket descriptor on success, or -1 on error. */
+
+int
+inetListen(const char *service, int backlog, socklen_t *addrlen)
+{
+ return inetPassiveSocket(service, SOCK_STREAM, addrlen, TRUE, backlog);
+}
+
+/* Create socket bound to wildcard IP address + port given in
+ 'service'. Return socket descriptor on success, or -1 on error. */
+
+int
+inetBind(const char *service, int type, socklen_t *addrlen)
+{
+ return inetPassiveSocket(service, type, addrlen, FALSE, 0);
+}
+
+/* Given a socket address in 'addr', whose length is specified in
+ 'addrlen', return a null-terminated string containing the host and
+ service names in the form "(hostname, port#)". The string is
+ returned in the buffer pointed to by 'addrStr', and this value is
+ also returned as the function result. The caller must specify the
+ size of the 'addrStr' buffer in 'addrStrLen'. */
+
+char *
+inetAddressStr(const struct sockaddr *addr, socklen_t addrlen,
+ char *addrStr, int addrStrLen)
+{
+ char host[NI_MAXHOST], service[NI_MAXSERV];
+
+ if (getnameinfo(addr, addrlen, host, NI_MAXHOST,
+ service, NI_MAXSERV, NI_NUMERICSERV) == 0)
+ snprintf(addrStr, addrStrLen, "(%s, %s)", host, service);
+ else
+ snprintf(addrStr, addrStrLen, "(?UNKNOWN?)");
+
+ return addrStr;
+}