]>
Commit | Line | Data |
---|---|---|
bb70624e JA |
1 | /* |
2 | * netopen.c -- functions to make tcp/udp connections | |
3 | * | |
4 | * Chet Ramey | |
5 | * chet@ins.CWRU.Edu | |
6 | */ | |
7 | ||
8 | /* Copyright (C) 1987,1991 Free Software Foundation, Inc. | |
9 | ||
10 | This file is part of GNU Bash, the Bourne Again SHell. | |
11 | ||
12 | Bash is free software; you can redistribute it and/or modify it | |
13 | under the terms of the GNU General Public License as published by | |
14 | the Free Software Foundation; either version 2, or (at your option) | |
15 | any later version. | |
16 | ||
17 | Bash is distributed in the hope that it will be useful, but WITHOUT | |
18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
20 | License for more details. | |
21 | ||
22 | You should have received a copy of the GNU General Public License | |
23 | along with Bash; see the file COPYING. If not, write to the Free | |
24 | Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ | |
25 | ||
26 | #include <config.h> | |
27 | ||
28 | #if defined (HAVE_NETWORK) | |
29 | ||
30 | #include <stdio.h> | |
31 | #include <sys/types.h> | |
32 | ||
33 | #if defined (HAVE_SYS_SOCKET_H) | |
34 | # include <sys/socket.h> | |
35 | #endif | |
36 | ||
37 | #if defined (HAVE_NETINET_IN_H) | |
38 | # include <netinet/in.h> | |
39 | #endif | |
40 | ||
41 | #if defined (HAVE_NETDB_H) | |
42 | # include <netdb.h> | |
43 | #endif | |
44 | ||
45 | #if defined (HAVE_ARPA_INET_H) | |
46 | # include <arpa/inet.h> | |
47 | #endif | |
48 | ||
49 | #include <bashansi.h> | |
50 | #include <ctype.h> | |
51 | #include <errno.h> | |
52 | ||
53 | #ifndef errno | |
54 | extern int errno; | |
55 | #endif | |
56 | ||
57 | #if !defined (HAVE_INET_ATON) | |
58 | extern int inet_aton (); | |
59 | #endif | |
60 | ||
61 | extern char *xmalloc (); | |
62 | ||
63 | /* Stuff the internet address corresponding to HOST into AP, in network | |
64 | byte order. Return 1 on success, 0 on failure. */ | |
65 | ||
66 | static int | |
67 | _getaddr (host, ap) | |
68 | char *host; | |
69 | struct in_addr *ap; | |
70 | { | |
71 | struct hostent *h; | |
72 | int r; | |
73 | ||
74 | r = 0; | |
75 | if (isdigit (host[0])) | |
76 | { | |
77 | /* If the first character is a digit, guess that it's an | |
78 | Internet address and return immediately if inet_aton succeeds. */ | |
79 | r = inet_aton (host, ap); | |
80 | if (r) | |
81 | return r; | |
82 | } | |
83 | #if !defined (HAVE_GETHOSTBYNAME) | |
84 | return 0; | |
85 | #else | |
86 | h = gethostbyname (host); | |
87 | if (h && h->h_addr) | |
88 | { | |
89 | bcopy(h->h_addr, (char *)ap, h->h_length); | |
90 | return 1; | |
91 | } | |
92 | #endif | |
93 | return 0; | |
94 | ||
95 | } | |
96 | ||
97 | /* Return 1 if SERV is a valid port number and stuff the converted value into | |
98 | PP in network byte order. */ | |
99 | static int | |
28ef6c31 | 100 | _getserv (serv, proto, pp) |
bb70624e | 101 | char *serv; |
28ef6c31 | 102 | int proto; |
bb70624e JA |
103 | unsigned short *pp; |
104 | { | |
105 | long l; | |
106 | unsigned short s; | |
107 | ||
108 | if (legal_number (serv, &l)) | |
109 | { | |
110 | if (l > 65535) | |
111 | return 0; | |
112 | s = (unsigned short)(l & 0xFFFF); | |
113 | s = htons (s); | |
114 | if (pp) | |
115 | *pp = s; | |
116 | return 1; | |
117 | } | |
118 | else | |
28ef6c31 JA |
119 | #if defined (HAVE_GETSERVBYNAME) |
120 | { | |
121 | struct servent *se; | |
122 | ||
123 | se = getservbyname (serv, (proto == 't') ? "tcp" : "udp"); | |
124 | if (se == 0) | |
125 | return 0; | |
126 | if (pp) | |
127 | *pp = se->s_port; /* ports returned in network byte order */ | |
128 | return 1; | |
129 | } | |
130 | #else /* !HAVE_GETSERVBYNAME */ | |
bb70624e | 131 | return 0; |
28ef6c31 | 132 | #endif /* !HAVE_GETSERVBYNAME */ |
bb70624e JA |
133 | } |
134 | ||
135 | static int | |
136 | _netopen(host, serv, typ) | |
137 | char *host, *serv; | |
138 | int typ; | |
139 | { | |
140 | struct in_addr ina; | |
141 | struct sockaddr_in sin; | |
142 | unsigned short p; | |
28ef6c31 | 143 | int s, e; |
bb70624e JA |
144 | char **cp; |
145 | ||
146 | if (_getaddr(host, &ina) == 0) | |
147 | { | |
148 | internal_error ("%s: host unknown", host); | |
28ef6c31 | 149 | errno = EINVAL; |
bb70624e JA |
150 | return -1; |
151 | } | |
152 | ||
28ef6c31 | 153 | if (_getserv(serv, typ, &p) == 0) |
bb70624e JA |
154 | { |
155 | internal_error("%s: invalid service", serv); | |
28ef6c31 | 156 | errno = EINVAL; |
bb70624e JA |
157 | return -1; |
158 | } | |
159 | ||
160 | bzero ((char *)&sin, sizeof(sin)); | |
161 | sin.sin_family = AF_INET; | |
162 | sin.sin_port = p; | |
163 | sin.sin_addr = ina; | |
164 | ||
165 | s = socket(AF_INET, (typ == 't') ? SOCK_STREAM : SOCK_DGRAM, 0); | |
166 | if (s < 0) | |
167 | { | |
168 | sys_error ("socket"); | |
169 | return (-1); | |
170 | } | |
171 | ||
172 | if (connect (s, (struct sockaddr *)&sin, sizeof (sin)) < 0) | |
173 | { | |
28ef6c31 | 174 | e = errno; |
bb70624e JA |
175 | sys_error("connect"); |
176 | close(s); | |
28ef6c31 | 177 | errno = e; |
bb70624e JA |
178 | return (-1); |
179 | } | |
180 | ||
181 | return(s); | |
182 | } | |
183 | ||
184 | /* | |
185 | * Open a TCP or UDP connection given a path like `/dev/tcp/host/port' to | |
186 | * host `host' on port `port' and return the connected socket. | |
187 | */ | |
188 | int | |
189 | netopen (path) | |
190 | char *path; | |
191 | { | |
192 | char *np, *s, *t; | |
193 | int fd; | |
194 | ||
195 | np = xmalloc (strlen (path) + 1); | |
196 | strcpy (np, path); | |
197 | ||
198 | s = np + 9; | |
199 | t = strchr (s, '/'); | |
200 | if (t == 0) | |
201 | { | |
202 | internal_error ("%s: bad network path specification", path); | |
203 | return -1; | |
204 | } | |
205 | *t++ = '\0'; | |
206 | fd = _netopen (s, t, path[5]); | |
207 | free (np); | |
208 | ||
209 | return fd; | |
210 | } | |
211 | ||
212 | #if 0 | |
213 | /* | |
214 | * Open a TCP connection to host `host' on the port defined for service | |
215 | * `serv' and return the connected socket. | |
216 | */ | |
217 | int | |
218 | tcpopen (host, serv) | |
219 | char *host, *serv; | |
220 | { | |
221 | return (_netopen (host, serv, 't')); | |
222 | } | |
223 | ||
224 | /* | |
225 | * Open a UDP connection to host `host' on the port defined for service | |
226 | * `serv' and return the connected socket. | |
227 | */ | |
228 | int | |
229 | udpopen (host, serv) | |
230 | char *host, *serv; | |
231 | { | |
232 | return _netopen (host, serv, 'u'); | |
233 | } | |
234 | #endif | |
235 | ||
236 | #else /* !HAVE_NETWORK */ | |
237 | ||
238 | int | |
239 | netopen (path) | |
240 | char *path; | |
241 | { | |
242 | internal_error ("network operations not supported"); | |
243 | return -1; | |
244 | } | |
245 | ||
246 | #endif /* !HAVE_NETWORK */ |