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