1 /* $Id: inet.c,v 1.43 2020-11-17 19:24:36 phil Exp $ */
2
3 /* Berkeley sockets inet interface (IPv4 only) */
4
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif /* HAVE_CONFIG_H defined */
8
9 #include <stdlib.h> /* atoi() */
10
11 #ifdef HAVE_UNISTD_H
12 #include <unistd.h> /* close() */
13 #endif /* HAVE_UNISTD_H defined */
14
15 #include <stdio.h>
16 #include <ctype.h>
17
18 #ifdef OLD_UCX_INCLUDES
19 #include <types.h>
20 #include <socket.h>
21 #include <in.h>
22 #define HAVE_INCLUDES
23 #endif /* OLD_UCX_INCLUDES defined */
24
25 #ifndef HAVE_INCLUDES
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <netinet/tcp.h> /* TCP_NODELAY */
30 #include <arpa/inet.h> /* inet_addr() */
31 #endif /* HAVE_INCLUDES not defined */
32
33 #include <netdb.h>
34 #include <fcntl.h>
35
36 #include "inet.h" /* own prototypes */
37 #include "str.h" /* memcpy() */
38 #include "bindresvport.h"
39
40 #ifndef INADDR_NONE
41 #define INADDR_NONE ((unsigned long)0xffffffff) /* want u_int32_t! */
42 #endif /* INADDR_NONE not defined */
43
44 static int
inet_socket2(char * host,char * service,int type,int port,int flags)45 inet_socket2(char *host, char *service, int type, int port, int flags) {
46 struct hostent *hp;
47 struct sockaddr_in sin;
48 struct servent *sp;
49 int s;
50 int true = 1;
51
52 if (!host || !service)
53 return -1;
54
55 bzero((char *)&sin, sizeof(sin));
56 sin.sin_family = AF_INET;
57
58 if (service) {
59 sp = getservbyname(service, (type == SOCK_STREAM ? "tcp" : "udp"));
60 if (sp != NULL) {
61 sin.sin_port = sp->s_port;
62 }
63 else if (isdigit((unsigned char)*service)) {
64 port = atoi(service);
65 if (port < 0 || port > 0xffff)
66 return -1;
67 sin.sin_port = htons(port);
68 } /* no service; saw digit */
69 else if (port >= 0 && port <= 0xffff) {
70 sin.sin_port = htons(port);
71 }
72 else
73 return -1;
74 } /* have service */
75 else if (port >= 0 && port <= 0xffff) {
76 sin.sin_port = htons(port);
77 }
78 else
79 return -1;
80
81 s = socket( AF_INET, type, 0 );
82 if (s < 0)
83 return -1;
84
85 /* set a boolean option: TRUE iff flag set and attempt fails */
86 #define TRYOPT(FLAG,LAYER,OPT) \
87 ((flags & FLAG) && \
88 setsockopt(s,LAYER,OPT,(const void *)&true,sizeof(true)) < 0)
89
90 if (((flags & INET_PRIV) && bindresvport(s, NULL) < 0) ||
91 TRYOPT(INET_BROADCAST,SOL_SOCKET,SO_BROADCAST) ||
92 TRYOPT(INET_REUSEADDR,SOL_SOCKET,SO_REUSEADDR) ||
93 TRYOPT(INET_DONTROUTE,SOL_SOCKET,SO_DONTROUTE) ||
94 TRYOPT(INET_OOBINLINE,SOL_SOCKET,SO_OOBINLINE) ||
95 TRYOPT(INET_KEEPALIVE,SOL_SOCKET,SO_KEEPALIVE) ||
96 TRYOPT(INET_NODELAY,IPPROTO_TCP,TCP_NODELAY)) {
97 close(s);
98 return -1;
99 }
100
101 if (flags & INET_CLOEXEC) {
102 int ff = fcntl(s, F_GETFD, 0);
103 if (ff != -1 || fcntl(s, F_SETFD, ff|FD_CLOEXEC) < 0) {
104 close(s);
105 return -1;
106 }
107 }
108
109 hp = gethostbyname( host );
110 if (hp != NULL) {
111 char **ap;
112
113 /* try each addr in turn */
114 for (ap = hp->h_addr_list; *ap; ap++) {
115 memcpy(&sin.sin_addr.s_addr, *ap, sizeof(sin.sin_addr.s_addr));
116 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == 0)
117 return s;
118 }
119 } /* have hostname */
120 else if (isdigit((unsigned char)*host)) { /* possible host addr? */
121 u_long addr;
122
123 /* XXX use inet_aton() if available?? */
124 addr = inet_addr(host);
125 if (addr != 0 && addr != INADDR_NONE) {
126 sin.sin_addr.s_addr = addr;
127 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == 0)
128 return s;
129 } /* good inet_addr */
130 } /* saw digit */
131 close(s);
132 return -1;
133 }
134
135 static int
inet_socket(char * host,char * service,int type,int port,int flags)136 inet_socket(char *host, char *service, int type, int port, int flags) {
137 int s;
138
139 #ifdef FOLD_HOSTNAMES
140 /* WATTCP on DOS requires hostname in upper case?! */
141 char *cp = host;
142 if (!cp)
143 return -1;
144 while ((*cp++ = toupper(*cp)))
145 ;
146 #endif /* FOLD_HOSTNAMES defined */
147
148 s = inet_socket2(host, service, type, port, flags );
149
150 return s;
151 }
152
153 /* called from stdio_obj.c */
154 int
tcp_socket(char * host,char * service,int port,int flags)155 tcp_socket(char *host, char *service, int port, int flags) {
156 return inet_socket( host, service, SOCK_STREAM, port, flags );
157 }
158
159 /* called from stdio_obj.c */
160 int
udp_socket(char * host,char * service,int port,int flags)161 udp_socket(char *host, char *service, int port, int flags) {
162 return inet_socket( host, service, SOCK_DGRAM, port, flags);
163 }
164
165 void
inet_cleanup(void)166 inet_cleanup(void) {
167 }
168