]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/sh/netopen.c
Bash-4.4 distribution sources and documentation
[thirdparty/bash.git] / lib / sh / netopen.c
CommitLineData
bb70624e
JA
1/*
2 * netopen.c -- functions to make tcp/udp connections
3 *
4 * Chet Ramey
5 * chet@ins.CWRU.Edu
6 */
7
a0c0a00f 8/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
bb70624e
JA
9
10 This file is part of GNU Bash, the Bourne Again SHell.
11
3185942a
JA
12 Bash is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
bb70624e 16
3185942a
JA
17 Bash is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
bb70624e
JA
21
22 You should have received a copy of the GNU General Public License
3185942a
JA
23 along with Bash. If not, see <http://www.gnu.org/licenses/>.
24*/
bb70624e
JA
25
26#include <config.h>
27
28#if defined (HAVE_NETWORK)
29
f73dda09
JA
30#if defined (HAVE_UNISTD_H)
31# include <unistd.h>
32#endif
33
bb70624e
JA
34#include <stdio.h>
35#include <sys/types.h>
36
37#if defined (HAVE_SYS_SOCKET_H)
38# include <sys/socket.h>
39#endif
40
41#if defined (HAVE_NETINET_IN_H)
42# include <netinet/in.h>
43#endif
44
45#if defined (HAVE_NETDB_H)
46# include <netdb.h>
47#endif
48
49#if defined (HAVE_ARPA_INET_H)
50# include <arpa/inet.h>
51#endif
52
53#include <bashansi.h>
b80f6443
JA
54#include <bashintl.h>
55
bb70624e
JA
56#include <errno.h>
57
f73dda09
JA
58#include <shell.h>
59#include <xmalloc.h>
60
bb70624e
JA
61#ifndef errno
62extern int errno;
63#endif
64
65#if !defined (HAVE_INET_ATON)
f73dda09 66extern int inet_aton __P((const char *, struct in_addr *));
bb70624e
JA
67#endif
68
0628567a
JA
69#ifndef HAVE_GETADDRINFO
70static int _getaddr __P((char *, struct in_addr *));
71static int _getserv __P((char *, int, unsigned short *));
72static int _netopen4 __P((char *, char *, int));
73#else /* HAVE_GETADDRINFO */
74static int _netopen6 __P((char *, char *, int));
75#endif
76
77static int _netopen __P((char *, char *, int));
78
f73dda09 79#ifndef HAVE_GETADDRINFO
bb70624e
JA
80/* Stuff the internet address corresponding to HOST into AP, in network
81 byte order. Return 1 on success, 0 on failure. */
82
83static int
84_getaddr (host, ap)
85 char *host;
86 struct in_addr *ap;
87{
88 struct hostent *h;
89 int r;
90
91 r = 0;
f73dda09 92 if (host[0] >= '0' && host[0] <= '9')
bb70624e
JA
93 {
94 /* If the first character is a digit, guess that it's an
95 Internet address and return immediately if inet_aton succeeds. */
96 r = inet_aton (host, ap);
97 if (r)
98 return r;
99 }
100#if !defined (HAVE_GETHOSTBYNAME)
101 return 0;
102#else
103 h = gethostbyname (host);
104 if (h && h->h_addr)
105 {
106 bcopy(h->h_addr, (char *)ap, h->h_length);
107 return 1;
108 }
109#endif
110 return 0;
111
112}
113
114/* Return 1 if SERV is a valid port number and stuff the converted value into
115 PP in network byte order. */
116static int
28ef6c31 117_getserv (serv, proto, pp)
bb70624e 118 char *serv;
28ef6c31 119 int proto;
bb70624e
JA
120 unsigned short *pp;
121{
7117c2d2 122 intmax_t l;
bb70624e
JA
123 unsigned short s;
124
125 if (legal_number (serv, &l))
126 {
bb70624e 127 s = (unsigned short)(l & 0xFFFF);
f73dda09
JA
128 if (s != l)
129 return (0);
bb70624e
JA
130 s = htons (s);
131 if (pp)
132 *pp = s;
133 return 1;
134 }
135 else
28ef6c31
JA
136#if defined (HAVE_GETSERVBYNAME)
137 {
138 struct servent *se;
139
140 se = getservbyname (serv, (proto == 't') ? "tcp" : "udp");
141 if (se == 0)
142 return 0;
143 if (pp)
144 *pp = se->s_port; /* ports returned in network byte order */
145 return 1;
146 }
147#else /* !HAVE_GETSERVBYNAME */
bb70624e 148 return 0;
28ef6c31 149#endif /* !HAVE_GETSERVBYNAME */
bb70624e
JA
150}
151
f73dda09
JA
152/*
153 * Open a TCP or UDP connection to HOST on port SERV. Uses the
154 * traditional BSD mechanisms. Returns the connected socket or -1 on error.
155 */
bb70624e 156static int
f73dda09 157_netopen4(host, serv, typ)
bb70624e
JA
158 char *host, *serv;
159 int typ;
160{
161 struct in_addr ina;
162 struct sockaddr_in sin;
163 unsigned short p;
28ef6c31 164 int s, e;
bb70624e
JA
165
166 if (_getaddr(host, &ina) == 0)
167 {
b80f6443 168 internal_error (_("%s: host unknown"), host);
28ef6c31 169 errno = EINVAL;
bb70624e
JA
170 return -1;
171 }
172
28ef6c31 173 if (_getserv(serv, typ, &p) == 0)
bb70624e 174 {
b80f6443 175 internal_error(_("%s: invalid service"), serv);
28ef6c31 176 errno = EINVAL;
bb70624e
JA
177 return -1;
178 }
179
7117c2d2 180 memset ((char *)&sin, 0, sizeof(sin));
bb70624e
JA
181 sin.sin_family = AF_INET;
182 sin.sin_port = p;
183 sin.sin_addr = ina;
184
185 s = socket(AF_INET, (typ == 't') ? SOCK_STREAM : SOCK_DGRAM, 0);
186 if (s < 0)
187 {
188 sys_error ("socket");
189 return (-1);
190 }
191
192 if (connect (s, (struct sockaddr *)&sin, sizeof (sin)) < 0)
193 {
28ef6c31 194 e = errno;
bb70624e
JA
195 sys_error("connect");
196 close(s);
28ef6c31 197 errno = e;
bb70624e
JA
198 return (-1);
199 }
200
201 return(s);
202}
f73dda09
JA
203#endif /* ! HAVE_GETADDRINFO */
204
205#ifdef HAVE_GETADDRINFO
206/*
207 * Open a TCP or UDP connection to HOST on port SERV. Uses getaddrinfo(3)
208 * which provides support for IPv6. Returns the connected socket or -1
209 * on error.
210 */
211static int
212_netopen6 (host, serv, typ)
213 char *host, *serv;
214 int typ;
215{
216 int s, e;
217 struct addrinfo hints, *res, *res0;
218 int gerr;
219
7117c2d2 220 memset ((char *)&hints, 0, sizeof (hints));
f73dda09
JA
221 /* XXX -- if problems with IPv6, set to PF_INET for IPv4 only */
222#ifdef DEBUG /* PF_INET is the one that works for me */
223 hints.ai_family = PF_INET;
224#else
225 hints.ai_family = PF_UNSPEC;
226#endif
227 hints.ai_socktype = (typ == 't') ? SOCK_STREAM : SOCK_DGRAM;
228
229 gerr = getaddrinfo (host, serv, &hints, &res0);
230 if (gerr)
231 {
232 if (gerr == EAI_SERVICE)
233 internal_error ("%s: %s", serv, gai_strerror (gerr));
234 else
235 internal_error ("%s: %s", host, gai_strerror (gerr));
236 errno = EINVAL;
237 return -1;
238 }
239
240 for (res = res0; res; res = res->ai_next)
241 {
242 if ((s = socket (res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
243 {
244 if (res->ai_next)
245 continue;
246 sys_error ("socket");
247 freeaddrinfo (res0);
248 return -1;
249 }
250 if (connect (s, res->ai_addr, res->ai_addrlen) < 0)
251 {
252 if (res->ai_next)
253 {
254 close (s);
255 continue;
256 }
257 e = errno;
258 sys_error ("connect");
259 close (s);
260 freeaddrinfo (res0);
261 errno = e;
262 return -1;
263 }
264 freeaddrinfo (res0);
265 break;
266 }
267 return s;
268}
269#endif /* HAVE_GETADDRINFO */
270
271/*
272 * Open a TCP or UDP connection to HOST on port SERV. Uses getaddrinfo(3)
273 * if available, falling back to the traditional BSD mechanisms otherwise.
274 * Returns the connected socket or -1 on error.
275 */
276static int
277_netopen(host, serv, typ)
278 char *host, *serv;
279 int typ;
280{
281#ifdef HAVE_GETADDRINFO
282 return (_netopen6 (host, serv, typ));
283#else
284 return (_netopen4 (host, serv, typ));
285#endif
286}
bb70624e
JA
287
288/*
289 * Open a TCP or UDP connection given a path like `/dev/tcp/host/port' to
290 * host `host' on port `port' and return the connected socket.
291 */
292int
293netopen (path)
294 char *path;
295{
296 char *np, *s, *t;
297 int fd;
298
f73dda09 299 np = (char *)xmalloc (strlen (path) + 1);
bb70624e
JA
300 strcpy (np, path);
301
302 s = np + 9;
303 t = strchr (s, '/');
304 if (t == 0)
305 {
b80f6443 306 internal_error (_("%s: bad network path specification"), path);
a0c0a00f 307 free (np);
bb70624e
JA
308 return -1;
309 }
310 *t++ = '\0';
311 fd = _netopen (s, t, path[5]);
312 free (np);
313
314 return fd;
315}
316
317#if 0
318/*
319 * Open a TCP connection to host `host' on the port defined for service
320 * `serv' and return the connected socket.
321 */
322int
323tcpopen (host, serv)
324 char *host, *serv;
325{
326 return (_netopen (host, serv, 't'));
327}
328
329/*
330 * Open a UDP connection to host `host' on the port defined for service
331 * `serv' and return the connected socket.
332 */
333int
334udpopen (host, serv)
335 char *host, *serv;
336{
337 return _netopen (host, serv, 'u');
338}
339#endif
340
341#else /* !HAVE_NETWORK */
342
343int
344netopen (path)
345 char *path;
346{
b80f6443 347 internal_error (_("network operations not supported"));
bb70624e
JA
348 return -1;
349}
350
351#endif /* !HAVE_NETWORK */