1 /* $Id: inet6.c,v 1.31 2020-11-19 02:48:14 phil Exp $ */
2 
3 /*
4  * Berkeley sockets inet interface using RFC2553 & POSIX 1003.1g
5  * extensions for IPv6 compatibility
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H defined */
11 
12 #ifdef HAVE_UNISTD_H
13 #include <unistd.h>			/* close() */
14 #endif /* HAVE_UNISTD_H defined */
15 
16 #include <stdio.h>
17 #include <fcntl.h>
18 
19 #ifdef FOLD_HOSTNAMES
20 #include <ctype.h>
21 #endif /* FOLD_HOSTNAMES defined */
22 
23 #ifdef HAVE_WINSOCK2_H
24 #include <ws2tcpip.h>			/* getaddrinfo */
25 #else
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>		/* TCP_NODELAY */
31 #endif
32 
33 #include "inet.h"			/* own prototypes */
34 #include "str.h"			/* bzero */
35 #include "bindresvport.h"
36 
37 /* NOTE!! Ignores "port" arg!! */
38 static sock_t
inet_socket(char * host,char * service,int type,int port,int flags)39 inet_socket(char *host, char *service, int type, int port, int flags) {
40     struct addrinfo hint, *res0, *res;
41     int yes = 1;
42     int error;
43     sock_t s;
44 
45     (void) port;
46     if (!host || !service)
47 	return -1;
48 
49     bzero((char *)&hint, sizeof(hint));
50     hint.ai_family = PF_UNSPEC;
51     hint.ai_socktype = type;
52 
53 #ifdef FOLD_HOSTNAMES
54     /* WATTCP on DOS requires hostname in upper case?! */
55     char *cp = host;
56     while ((*cp++ = toupper(*cp)))
57 	;
58 #endif /* FOLD_HOSTNAMES defined */
59 
60     res0 = NULL;
61     error = getaddrinfo(host, service, &hint, &res0);
62     if (error)
63 	return -1;
64     s = -1;
65     for (res = res0; res; res = res->ai_next) {
66 	s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
67 	if (s < 0)
68 	    continue;
69 
70 #ifdef F_SETFD
71 	if (flags & INET_CLOEXEC) {
72 	    int ff = fcntl(s, F_GETFD, 0);
73 	    if (ff != -1 || fcntl(s, F_SETFD, ff|FD_CLOEXEC) < 0) {
74 		close_socket(s);
75 		return -1;
76 	    }
77 	}
78 #endif
79 
80 /* set a boolean option: TRUE iff flag set and attempt fails */
81 #define TRYOPT(FLAG,LAYER,OPT) \
82 	((flags & FLAG) && \
83 	 setsockopt(s,LAYER,OPT,SETSOCKOPT_ARG_CAST &yes,sizeof(yes)) < 0)
84 
85 	if (((flags & INET_PRIV) && bindresvport_sa(s, NULL) < 0) ||
86 	    TRYOPT(INET_BROADCAST,SOL_SOCKET,SO_BROADCAST) ||
87 	    TRYOPT(INET_REUSEADDR,SOL_SOCKET,SO_REUSEADDR) ||
88 	    TRYOPT(INET_DONTROUTE,SOL_SOCKET,SO_DONTROUTE) ||
89 	    TRYOPT(INET_OOBINLINE,SOL_SOCKET,SO_OOBINLINE) ||
90 	    TRYOPT(INET_KEEPALIVE,SOL_SOCKET,SO_KEEPALIVE) ||
91 	    TRYOPT(INET_NODELAY,IPPROTO_TCP,TCP_NODELAY) ||
92 	    connect(s, res->ai_addr, res->ai_addrlen) < 0) {
93 	    close_socket(s);
94 	    s = -1;
95 	    continue;
96 	}
97 	break;				/* got one! */
98     }
99     freeaddrinfo(res0);
100 
101     return s;
102 }
103 
104 /* NOTE!! Ignores "port" arg!! */
105 sock_t
tcp_socket(char * host,char * service,int port,int flags)106 tcp_socket(char *host, char *service, int port, int flags) {
107     return inet_socket( host, service, SOCK_STREAM, port, flags);
108 }
109 
110 /* NOTE!! Ignores "port" arg!! */
111 sock_t
udp_socket(char * host,char * service,int port,int flags)112 udp_socket(char *host, char *service, int port, int flags) {
113     return inet_socket( host, service, SOCK_DGRAM, port, flags);
114 }
115 
116 #ifndef INET_IO
117 void
inet_cleanup(void)118 inet_cleanup(void) {
119 }
120 #endif
121