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