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