1 /* $Id: inet.c,v 1.40 2020-10-08 03:24:56 phil Exp $ */
2 
3 /* WinSock v1 inet support */
4 
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif /* HAVE_CONFIG_H defined */
8 
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <stdlib.h>			/* malloc */
12 #include <winsock.h>
13 
14 #include "h.h"				/* TRUE/FALSE */
15 #include "snotypes.h"			/* needed on VAX/VMS for macros.h */
16 #include "lib.h"
17 #include "inet.h"			/* {tcp,udp}_socket */
18 #include "str.h"
19 #include "bindresvport.h"
20 
21 /*
22  * fcntl.h and io.h included for borland BCC32 v5.5
23  * Greg White <glwhite@netconnect.com.au> 8/30/2000
24  * needed for MINGW too! -phil 2/14/2002
25  */
26 #include <fcntl.h>
27 #include <io.h>
28 
29 #ifndef INADDR_NONE
30 #define INADDR_NONE ((unsigned long)0xffffffff)	/* want u_int32_t! */
31 #endif /* INADDR_NONE not defined */
32 
33 static sock_t
inet_socket(char * host,char * service,int type,int flags,int port)34 inet_socket(char *host, char *service,
35 	    int type, int flags, int port) {
36     struct hostent *hp;
37     struct sockaddr_in sin;
38     struct servent *sp;
39     sock_t s;
40     int true = 1;
41 
42     if (!host || !service)
43 	return INVALID_SOCKET;
44 
45     bzero(&sin, sizeof(sin));
46     sin.sin_family = AF_INET;
47 
48     if (service) {
49 	sp = getservbyname(service, (type == SOCK_STREAM ? "tcp" : "udp"));
50 	if (sp != NULL) {
51 	    sin.sin_port = sp->s_port;
52 	}
53 	else if (isdigit((unsigned char)*service)) {
54 	    port = atoi(service);
55 	    if (port < 0 || port > 0xffff)
56 		return INVALID_SOCKET;
57 	    sin.sin_port = htons((short)port);
58 	} /* no service; saw digit */
59 	else if (port >= 0 && port <= 0xffff) {
60 	    sin.sin_port = htons((short)port);
61 	}
62 	else
63 	    return INVALID_SOCKET;
64     } /* have service */
65     else if (port >= 0 && port <= 0xffff) {
66 	sin.sin_port = htons((short)port);
67     }
68     else
69 	return INVALID_SOCKET;
70 
71     /*
72      * need winsock2.h WSASocketA call with
73      * WSA_FLAG_NO_HANDLE_INHERIT to implement INET_CLOEXEC?
74      */
75     s = socket( AF_INET, type, 0 );
76     if (s == INVALID_SOCKET)
77 	return s;
78 
79 /* set a boolean option: TRUE iff flag set and attempt fails */
80 #define TRYOPT(FLAG,LAYER,OPT) \
81 	((flags & FLAG) && setsockopt(s,LAYER,OPT,(const void *)&true,sizeof(true)) < 0)
82 
83     if (((flags & INET_PRIV) && bindresvport(s, &sin) < 0) ||
84 	TRYOPT(INET_BROADCAST,SOL_SOCKET,SO_BROADCAST) ||
85 	TRYOPT(INET_REUSEADDR,SOL_SOCKET,SO_REUSEADDR) ||
86 	TRYOPT(INET_DONTROUTE,SOL_SOCKET,SO_DONTROUTE) ||
87 	TRYOPT(INET_OOBINLINE,SOL_SOCKET,SO_OOBINLINE) ||
88 	TRYOPT(INET_KEEPALIVE,SOL_SOCKET,SO_KEEPALIVE) ||
89 	TRYOPT(INET_NODELAY,IPPROTO_TCP,TCP_NODELAY)) {
90 	closesocket(s);
91 	return -1;
92     }
93 
94     hp = gethostbyname( host );
95     if (hp != NULL) {
96 	char **ap;
97 
98 	/* try each addr in turn */
99 	for (ap = hp->h_addr_list; *ap; ap++) {
100 	    memcpy(&sin.sin_addr.s_addr, *ap, sizeof(sin.sin_addr.s_addr));
101 	    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == 0)
102 		return s;
103 	}
104     } /* have hostname */
105     else if (isdigit((unsigned char)*host)) { /* possible host addr? */
106 	u_long addr;
107 
108 	/* XXX use inet_aton() if available?? */
109 	addr = inet_addr(host);
110 	if (addr != 0 && addr != INADDR_NONE) {
111 	    sin.sin_addr.s_addr = addr;
112 	    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == 0)
113 		return s;
114 	} /* good inet_addr */
115     } /* saw digit */
116     closesocket(s);
117     return INVALID_SOCKET;
118 } /* inet_socket */
119 
120 sock_t
tcp_socket(char * host,char * service,int port,int flags)121 tcp_socket(char *host, char *service, int port, int flags) {
122     return inet_socket( host, service, port, flags, SOCK_STREAM );
123 }
124 
125 sock_t
udp_socket(char * host,char * service,int port,int flags)126 udp_socket(char *host, char *service, int port, int flags) {
127     return inet_socket( host, service, port, flags, SOCK_DGRAM );
128 }
129