]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* net.cc: network-related routines. |
2 | ||
55ae1dff | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001 Cygnus Solutions. |
1fd5e000 CF |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | /* #define DEBUG_NEST_ON 1 */ | |
12 | ||
13 | #define __INSIDE_CYGWIN_NET__ | |
14 | ||
4c8d72de | 15 | #include "winsup.h" |
1fd5e000 CF |
16 | #include <errno.h> |
17 | #include <sys/socket.h> | |
18 | #include <sys/un.h> | |
9182099c | 19 | #include <iphlpapi.h> |
1fd5e000 | 20 | |
619f7fa0 | 21 | #include <stdlib.h> |
84c7d409 | 22 | #include <unistd.h> |
1fd5e000 CF |
23 | #include <netdb.h> |
24 | #include <fcntl.h> | |
a1299ba5 | 25 | #define USE_SYS_TYPES_FD_SET |
dd4f0b23 | 26 | #include <winsock2.h> |
bccd5e0d | 27 | #include "cygerrno.h" |
95a8465b | 28 | #include "perprocess.h" |
6b91b8d5 | 29 | #include "security.h" |
bccd5e0d CF |
30 | #include "fhandler.h" |
31 | #include "path.h" | |
e2ebe117 | 32 | #include "dtable.h" |
0381fec6 | 33 | #include "cygheap.h" |
bccd5e0d CF |
34 | #include "sync.h" |
35 | #include "sigproc.h" | |
e2ebe117 | 36 | #include "pinfo.h" |
f0338f54 | 37 | #include "registry.h" |
1fd5e000 | 38 | |
4e6a4ea8 | 39 | extern "C" { |
1fd5e000 CF |
40 | int h_errno; |
41 | ||
42 | int __stdcall rcmd (char **ahost, unsigned short inport, char *locuser, | |
43 | char *remuser, char *cmd, SOCKET *fd2p); | |
44 | int __stdcall rexec (char **ahost, unsigned short inport, char *locuser, | |
45 | char *password, char *cmd, SOCKET *fd2p); | |
46 | int __stdcall rresvport (int *); | |
47 | int sscanf (const char *, const char *, ...); | |
48 | } /* End of "C" section */ | |
49 | ||
a2cdb048 CV |
50 | class wsock_event |
51 | { | |
52 | WSAEVENT event; | |
53 | WSAOVERLAPPED ovr; | |
54 | public: | |
55 | wsock_event () : event (NULL) {}; | |
9f13167f CV |
56 | ~wsock_event () |
57 | { | |
58 | if (event) | |
462f4eff | 59 | WSACloseEvent (event); |
9f13167f CV |
60 | event = NULL; |
61 | }; | |
a2cdb048 CV |
62 | |
63 | LPWSAOVERLAPPED prepare (); | |
64 | int wait (int socket, LPDWORD flags); | |
65 | }; | |
66 | ||
67 | LPWSAOVERLAPPED | |
68 | wsock_event::prepare () | |
69 | { | |
70 | LPWSAOVERLAPPED ret = NULL; | |
71 | ||
72 | SetLastError (0); | |
6a574f1a | 73 | if ((event = WSACreateEvent ()) != WSA_INVALID_EVENT) |
a2cdb048 CV |
74 | { |
75 | memset (&ovr, 0, sizeof ovr); | |
76 | ovr.hEvent = event; | |
77 | ret = &ovr; | |
78 | } | |
79 | else if (GetLastError () == ERROR_PROC_NOT_FOUND) /* winsock2 not available */ | |
80 | WSASetLastError (0); | |
462f4eff | 81 | |
a2cdb048 CV |
82 | debug_printf ("%d = wsock_event::prepare ()", ret); |
83 | return ret; | |
84 | } | |
85 | ||
86 | int | |
87 | wsock_event::wait (int socket, LPDWORD flags) | |
88 | { | |
89 | int ret = -1; | |
90 | WSAEVENT ev[2] = { event, signal_arrived }; | |
91 | ||
92 | switch (WSAWaitForMultipleEvents(2, ev, FALSE, WSA_INFINITE, FALSE)) | |
93 | { | |
94 | case WSA_WAIT_EVENT_0: | |
95 | DWORD len; | |
96 | if (WSAGetOverlappedResult(socket, &ovr, &len, FALSE, flags)) | |
97 | ret = (int) len; | |
98 | break; | |
99 | case WSA_WAIT_EVENT_0 + 1: | |
0260054a CV |
100 | if (!CancelIo ((HANDLE)socket)) |
101 | { | |
102 | debug_printf ("CancelIo() %E, fallback to blocking io"); | |
103 | WSAGetOverlappedResult(socket, &ovr, &len, TRUE, flags); | |
462f4eff | 104 | } |
0260054a | 105 | else |
462f4eff | 106 | WSASetLastError (WSAEINTR); |
a2cdb048 CV |
107 | break; |
108 | case WSA_WAIT_FAILED: | |
109 | break; | |
110 | default: /* Should be impossible. *LOL* */ | |
111 | WSASetLastError (WSAEFAULT); | |
112 | break; | |
113 | } | |
114 | WSACloseEvent (event); | |
115 | event = NULL; | |
116 | return ret; | |
117 | } | |
118 | ||
d61b1993 | 119 | WSADATA wsadata; |
dd4f0b23 | 120 | |
1fd5e000 | 121 | /* Cygwin internal */ |
829425c9 CF |
122 | static SOCKET __stdcall |
123 | set_socket_inheritance (SOCKET sock) | |
1fd5e000 | 124 | { |
e5ba4c06 | 125 | if (iswinnt) |
829425c9 CF |
126 | (void) SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); |
127 | else | |
1fd5e000 | 128 | { |
829425c9 CF |
129 | SOCKET newsock; |
130 | if (!DuplicateHandle (hMainProc, (HANDLE) sock, hMainProc, (HANDLE *) &newsock, | |
131 | 0, TRUE, DUPLICATE_SAME_ACCESS)) | |
132 | small_printf ("DuplicateHandle failed %E"); | |
133 | else | |
134 | { | |
135 | closesocket (sock); | |
136 | sock = newsock; | |
137 | } | |
1fd5e000 | 138 | } |
1fd5e000 CF |
139 | return sock; |
140 | } | |
141 | ||
142 | /* htonl: standards? */ | |
4e6a4ea8 | 143 | extern "C" unsigned long int |
1fd5e000 CF |
144 | htonl (unsigned long int x) |
145 | { | |
1fd5e000 CF |
146 | return ((((x & 0x000000ffU) << 24) | |
147 | ((x & 0x0000ff00U) << 8) | | |
148 | ((x & 0x00ff0000U) >> 8) | | |
149 | ((x & 0xff000000U) >> 24))); | |
150 | } | |
151 | ||
152 | /* ntohl: standards? */ | |
4e6a4ea8 | 153 | extern "C" unsigned long int |
1fd5e000 CF |
154 | ntohl (unsigned long int x) |
155 | { | |
156 | return htonl (x); | |
157 | } | |
158 | ||
159 | /* htons: standards? */ | |
4e6a4ea8 | 160 | extern "C" unsigned short |
1fd5e000 CF |
161 | htons (unsigned short x) |
162 | { | |
1fd5e000 CF |
163 | return ((((x & 0x000000ffU) << 8) | |
164 | ((x & 0x0000ff00U) >> 8))); | |
165 | } | |
166 | ||
167 | /* ntohs: standards? */ | |
4e6a4ea8 | 168 | extern "C" unsigned short |
1fd5e000 CF |
169 | ntohs (unsigned short x) |
170 | { | |
171 | return htons (x); | |
172 | } | |
173 | ||
174 | /* Cygwin internal */ | |
175 | static void | |
176 | dump_protoent (struct protoent *p) | |
177 | { | |
178 | if (p) | |
179 | debug_printf ("protoent %s %x %x", p->p_name, p->p_aliases, p->p_proto); | |
180 | } | |
181 | ||
0bec0119 | 182 | /* exported as inet_ntoa: BSD 4.3 */ |
4e6a4ea8 | 183 | extern "C" char * |
1fd5e000 CF |
184 | cygwin_inet_ntoa (struct in_addr in) |
185 | { | |
186 | char *res = inet_ntoa (in); | |
187 | return res; | |
188 | } | |
189 | ||
0bec0119 | 190 | /* exported as inet_addr: BSD 4.3 */ |
4e6a4ea8 | 191 | extern "C" unsigned long |
1fd5e000 CF |
192 | cygwin_inet_addr (const char *cp) |
193 | { | |
194 | unsigned long res = inet_addr (cp); | |
195 | return res; | |
196 | } | |
197 | ||
0bec0119 CV |
198 | /* exported as inet_aton: BSD 4.3 |
199 | inet_aton is not exported by wsock32 and ws2_32, | |
200 | so it has to be implemented here. */ | |
201 | extern "C" int | |
202 | cygwin_inet_aton (const char *cp, struct in_addr *inp) | |
203 | { | |
204 | unsigned long res = inet_addr (cp); | |
205 | if (res == INADDR_NONE && strcmp (cp, "255.255.255.255")) | |
38c5dd44 | 206 | return 0; |
0bec0119 CV |
207 | if (inp) |
208 | inp->s_addr = res; | |
38c5dd44 | 209 | return 1; |
0bec0119 CV |
210 | } |
211 | ||
046069e4 | 212 | /* undocumented in wsock32.dll */ |
e77d29a9 | 213 | extern "C" unsigned int WINAPI inet_network (const char *); |
046069e4 | 214 | |
75a57bf0 | 215 | extern "C" unsigned int |
046069e4 DD |
216 | cygwin_inet_network (const char *cp) |
217 | { | |
218 | unsigned int res = inet_network (cp); | |
219 | return res; | |
220 | } | |
221 | ||
1fd5e000 CF |
222 | /* inet_netof is in the standard BSD sockets library. It is useless |
223 | for modern networks, since it assumes network values which are no | |
224 | longer meaningful, but some existing code calls it. */ | |
225 | ||
4e6a4ea8 | 226 | extern "C" unsigned long |
1fd5e000 CF |
227 | inet_netof (struct in_addr in) |
228 | { | |
229 | unsigned long i, res; | |
230 | ||
231 | ||
232 | i = ntohl (in.s_addr); | |
233 | if (IN_CLASSA (i)) | |
234 | res = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT; | |
235 | else if (IN_CLASSB (i)) | |
236 | res = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT; | |
237 | else | |
238 | res = (i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT; | |
239 | ||
240 | ||
241 | return res; | |
242 | } | |
243 | ||
244 | /* inet_makeaddr is in the standard BSD sockets library. It is | |
245 | useless for modern networks, since it assumes network values which | |
246 | are no longer meaningful, but some existing code calls it. */ | |
247 | ||
4e6a4ea8 | 248 | extern "C" struct in_addr |
1fd5e000 CF |
249 | inet_makeaddr (int net, int lna) |
250 | { | |
251 | unsigned long i; | |
252 | struct in_addr in; | |
253 | ||
254 | ||
255 | if (net < IN_CLASSA_MAX) | |
256 | i = (net << IN_CLASSA_NSHIFT) | (lna & IN_CLASSA_HOST); | |
257 | else if (net < IN_CLASSB_MAX) | |
258 | i = (net << IN_CLASSB_NSHIFT) | (lna & IN_CLASSB_HOST); | |
259 | else if (net < 0x1000000) | |
260 | i = (net << IN_CLASSC_NSHIFT) | (lna & IN_CLASSC_HOST); | |
261 | else | |
262 | i = net | lna; | |
263 | ||
264 | in.s_addr = htonl (i); | |
265 | ||
266 | ||
267 | return in; | |
268 | } | |
269 | ||
270 | struct tl | |
271 | { | |
272 | int w; | |
273 | const char *s; | |
274 | int e; | |
275 | }; | |
276 | ||
277 | static struct tl errmap[] = | |
278 | { | |
3065afdb | 279 | {WSAEINTR, "WSAEINTR", EINTR}, |
1fd5e000 CF |
280 | {WSAEWOULDBLOCK, "WSAEWOULDBLOCK", EWOULDBLOCK}, |
281 | {WSAEINPROGRESS, "WSAEINPROGRESS", EINPROGRESS}, | |
282 | {WSAEALREADY, "WSAEALREADY", EALREADY}, | |
283 | {WSAENOTSOCK, "WSAENOTSOCK", ENOTSOCK}, | |
284 | {WSAEDESTADDRREQ, "WSAEDESTADDRREQ", EDESTADDRREQ}, | |
285 | {WSAEMSGSIZE, "WSAEMSGSIZE", EMSGSIZE}, | |
286 | {WSAEPROTOTYPE, "WSAEPROTOTYPE", EPROTOTYPE}, | |
287 | {WSAENOPROTOOPT, "WSAENOPROTOOPT", ENOPROTOOPT}, | |
288 | {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT", EPROTONOSUPPORT}, | |
289 | {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT", ESOCKTNOSUPPORT}, | |
290 | {WSAEOPNOTSUPP, "WSAEOPNOTSUPP", EOPNOTSUPP}, | |
291 | {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT", EPFNOSUPPORT}, | |
292 | {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT", EAFNOSUPPORT}, | |
293 | {WSAEADDRINUSE, "WSAEADDRINUSE", EADDRINUSE}, | |
294 | {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL", EADDRNOTAVAIL}, | |
295 | {WSAENETDOWN, "WSAENETDOWN", ENETDOWN}, | |
296 | {WSAENETUNREACH, "WSAENETUNREACH", ENETUNREACH}, | |
297 | {WSAENETRESET, "WSAENETRESET", ENETRESET}, | |
298 | {WSAECONNABORTED, "WSAECONNABORTED", ECONNABORTED}, | |
299 | {WSAECONNRESET, "WSAECONNRESET", ECONNRESET}, | |
300 | {WSAENOBUFS, "WSAENOBUFS", ENOBUFS}, | |
301 | {WSAEISCONN, "WSAEISCONN", EISCONN}, | |
302 | {WSAENOTCONN, "WSAENOTCONN", ENOTCONN}, | |
303 | {WSAESHUTDOWN, "WSAESHUTDOWN", ESHUTDOWN}, | |
304 | {WSAETOOMANYREFS, "WSAETOOMANYREFS", ETOOMANYREFS}, | |
305 | {WSAETIMEDOUT, "WSAETIMEDOUT", ETIMEDOUT}, | |
306 | {WSAECONNREFUSED, "WSAECONNREFUSED", ECONNREFUSED}, | |
307 | {WSAELOOP, "WSAELOOP", ELOOP}, | |
308 | {WSAENAMETOOLONG, "WSAENAMETOOLONG", ENAMETOOLONG}, | |
309 | {WSAEHOSTDOWN, "WSAEHOSTDOWN", EHOSTDOWN}, | |
310 | {WSAEHOSTUNREACH, "WSAEHOSTUNREACH", EHOSTUNREACH}, | |
311 | {WSAENOTEMPTY, "WSAENOTEMPTY", ENOTEMPTY}, | |
312 | {WSAEPROCLIM, "WSAEPROCLIM", EPROCLIM}, | |
313 | {WSAEUSERS, "WSAEUSERS", EUSERS}, | |
314 | {WSAEDQUOT, "WSAEDQUOT", EDQUOT}, | |
315 | {WSAESTALE, "WSAESTALE", ESTALE}, | |
316 | {WSAEREMOTE, "WSAEREMOTE", EREMOTE}, | |
317 | {WSAEINVAL, "WSAEINVAL", EINVAL}, | |
318 | {WSAEFAULT, "WSAEFAULT", EFAULT}, | |
f940c5b1 | 319 | {0, "NOERROR", 0}, |
01cf5d0f | 320 | {0, NULL, 0} |
1fd5e000 CF |
321 | }; |
322 | ||
c90e420d CF |
323 | static int |
324 | find_winsock_errno (int why) | |
325 | { | |
f940c5b1 | 326 | for (int i = 0; errmap[i].s != NULL; ++i) |
c90e420d CF |
327 | if (why == errmap[i].w) |
328 | return errmap[i].e; | |
329 | ||
330 | return EPERM; | |
331 | } | |
332 | ||
1fd5e000 CF |
333 | /* Cygwin internal */ |
334 | void | |
829425c9 | 335 | __set_winsock_errno (const char *fn, int ln) |
1fd5e000 | 336 | { |
c90e420d CF |
337 | DWORD werr = WSAGetLastError (); |
338 | int err = find_winsock_errno (werr); | |
339 | set_errno (err); | |
340 | syscall_printf ("%s:%d - winsock error %d -> errno %d", fn, ln, werr, err); | |
1fd5e000 CF |
341 | } |
342 | ||
7d9688b7 CV |
343 | /* |
344 | * Since the member `s' isn't used for debug output we can use it | |
345 | * for the error text returned by herror and hstrerror. | |
346 | */ | |
1fd5e000 CF |
347 | static struct tl host_errmap[] = |
348 | { | |
7d9688b7 CV |
349 | {WSAHOST_NOT_FOUND, "Unknown host", HOST_NOT_FOUND}, |
350 | {WSATRY_AGAIN, "Host name lookup failure", TRY_AGAIN}, | |
351 | {WSANO_RECOVERY, "Unknown server error", NO_RECOVERY}, | |
352 | {WSANO_DATA, "No address associated with name", NO_DATA}, | |
01cf5d0f | 353 | {0, NULL, 0} |
1fd5e000 CF |
354 | }; |
355 | ||
356 | /* Cygwin internal */ | |
357 | static void | |
358 | set_host_errno () | |
359 | { | |
360 | int i; | |
361 | ||
362 | int why = WSAGetLastError (); | |
7d9688b7 | 363 | for (i = 0; host_errmap[i].w != 0; ++i) |
1fd5e000 CF |
364 | if (why == host_errmap[i].w) |
365 | break; | |
366 | ||
367 | if (host_errmap[i].w != 0) | |
368 | h_errno = host_errmap[i].e; | |
369 | else | |
370 | h_errno = NETDB_INTERNAL; | |
371 | } | |
372 | ||
373 | /* exported as getprotobyname: standards? */ | |
4e6a4ea8 | 374 | extern "C" struct protoent * |
1fd5e000 CF |
375 | cygwin_getprotobyname (const char *p) |
376 | { | |
1fd5e000 CF |
377 | struct protoent *res = getprotobyname (p); |
378 | if (!res) | |
379 | set_winsock_errno (); | |
380 | ||
381 | dump_protoent (res); | |
382 | return res; | |
383 | } | |
384 | ||
385 | /* exported as getprotobynumber: standards? */ | |
4e6a4ea8 | 386 | extern "C" struct protoent * |
1fd5e000 CF |
387 | cygwin_getprotobynumber (int number) |
388 | { | |
1fd5e000 CF |
389 | struct protoent *res = getprotobynumber (number); |
390 | if (!res) | |
391 | set_winsock_errno (); | |
392 | ||
393 | dump_protoent (res); | |
394 | return res; | |
395 | } | |
396 | ||
4e6a4ea8 | 397 | fhandler_socket * |
1fd5e000 CF |
398 | fdsock (int fd, const char *name, SOCKET soc) |
399 | { | |
dd4f0b23 CV |
400 | if (wsadata.wVersion < 512) /* < Winsock 2.0 */ |
401 | soc = set_socket_inheritance (soc); | |
0381fec6 | 402 | fhandler_socket *fh = (fhandler_socket *) cygheap->fdtab.build_fhandler (fd, FH_SOCKET, name); |
1fd5e000 CF |
403 | fh->set_io_handle ((HANDLE) soc); |
404 | fh->set_flags (O_RDWR); | |
0381fec6 | 405 | cygheap->fdtab.inc_need_fixup_before (); |
4e6a4ea8 | 406 | return fh; |
1fd5e000 CF |
407 | } |
408 | ||
409 | /* exported as socket: standards? */ | |
4e6a4ea8 | 410 | extern "C" int |
1fd5e000 CF |
411 | cygwin_socket (int af, int type, int protocol) |
412 | { | |
413 | int res = -1; | |
4e6a4ea8 | 414 | SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socket"); |
1fd5e000 CF |
415 | |
416 | SOCKET soc; | |
417 | ||
0381fec6 | 418 | int fd = cygheap->fdtab.find_unused_handle (); |
1fd5e000 CF |
419 | |
420 | if (fd < 0) | |
4e6a4ea8 | 421 | set_errno (EMFILE); |
1fd5e000 CF |
422 | else |
423 | { | |
424 | debug_printf ("socket (%d, %d, %d)", af, type, protocol); | |
425 | ||
298fad46 | 426 | soc = socket (AF_INET, type, af == AF_UNIX ? 0 : protocol); |
1fd5e000 CF |
427 | |
428 | if (soc == INVALID_SOCKET) | |
b0e82b74 CF |
429 | { |
430 | set_winsock_errno (); | |
431 | goto done; | |
432 | } | |
1fd5e000 | 433 | |
1fd5e000 CF |
434 | const char *name; |
435 | if (af == AF_INET) | |
b0e82b74 | 436 | name = (type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp"); |
1fd5e000 | 437 | else |
0381fec6 | 438 | name = (type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket"); |
1fd5e000 | 439 | |
4e6a4ea8 | 440 | fdsock (fd, name, soc)->set_addr_family (af); |
1fd5e000 | 441 | res = fd; |
1fd5e000 CF |
442 | } |
443 | ||
444 | done: | |
445 | syscall_printf ("%d = socket (%d, %d, %d)", res, af, type, protocol); | |
4e6a4ea8 | 446 | ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socket"); |
1fd5e000 CF |
447 | return res; |
448 | } | |
449 | ||
450 | /* cygwin internal: map sockaddr into internet domain address */ | |
451 | ||
452 | static int get_inet_addr (const struct sockaddr *in, int inlen, | |
619f7fa0 | 453 | struct sockaddr_in *out, int *outlen, int* secret = 0) |
1fd5e000 | 454 | { |
619f7fa0 ED |
455 | int secret_buf [4]; |
456 | int* secret_ptr = (secret ? : secret_buf); | |
457 | ||
1fd5e000 CF |
458 | if (in->sa_family == AF_INET) |
459 | { | |
460 | *out = * (sockaddr_in *)in; | |
461 | *outlen = inlen; | |
462 | return 1; | |
463 | } | |
464 | else if (in->sa_family == AF_UNIX) | |
465 | { | |
6b6a8cef | 466 | int fd = _open (in->sa_data, O_RDONLY); |
1fd5e000 CF |
467 | if (fd == -1) |
468 | return 0; | |
6b6a8cef CV |
469 | |
470 | int ret = 0; | |
619f7fa0 | 471 | char buf[128]; |
6b6a8cef CV |
472 | memset (buf, 0, sizeof buf); |
473 | if (read (fd, buf, sizeof buf) != -1) | |
462f4eff | 474 | { |
6b6a8cef CV |
475 | sockaddr_in sin; |
476 | sin.sin_family = AF_INET; | |
619f7fa0 ED |
477 | sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x", |
478 | &sin.sin_port, | |
479 | secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3); | |
6b6a8cef CV |
480 | sin.sin_port = htons (sin.sin_port); |
481 | sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
482 | *out = sin; | |
483 | *outlen = sizeof sin; | |
484 | ret = 1; | |
462f4eff | 485 | } |
6b6a8cef CV |
486 | _close (fd); |
487 | return ret; | |
1fd5e000 CF |
488 | } |
489 | else | |
490 | { | |
491 | set_errno (EAFNOSUPPORT); | |
492 | return 0; | |
493 | } | |
494 | } | |
495 | ||
496 | /* exported as sendto: standards? */ | |
4e6a4ea8 | 497 | extern "C" int |
1fd5e000 CF |
498 | cygwin_sendto (int fd, |
499 | const void *buf, | |
500 | int len, | |
501 | unsigned int flags, | |
502 | const struct sockaddr *to, | |
503 | int tolen) | |
504 | { | |
a2cdb048 CV |
505 | int res; |
506 | wsock_event wsock_evt; | |
507 | LPWSAOVERLAPPED ovr; | |
0381fec6 | 508 | fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; |
1fd5e000 | 509 | sockaddr_in sin; |
3b0d65ea | 510 | sigframe thisframe (mainthread); |
1fd5e000 CF |
511 | |
512 | if (get_inet_addr (to, tolen, &sin, &tolen) == 0) | |
513 | return -1; | |
514 | ||
a2cdb048 | 515 | if (!(ovr = wsock_evt.prepare ())) |
1fd5e000 | 516 | { |
a2cdb048 CV |
517 | debug_printf ("Fallback to winsock 1 sendto call"); |
518 | if ((res = sendto (h->get_socket (), (const char *) buf, len, flags, | |
519 | to, tolen)) == SOCKET_ERROR) | |
520 | { | |
521 | set_winsock_errno (); | |
522 | res = -1; | |
523 | } | |
524 | } | |
525 | else | |
526 | { | |
527 | WSABUF wsabuf = { len, (char *) buf }; | |
528 | DWORD ret = 0; | |
529 | if (WSASendTo (h->get_socket (), &wsabuf, 1, &ret, (DWORD)flags, | |
462f4eff CF |
530 | to, tolen, ovr, NULL) != SOCKET_ERROR) |
531 | res = ret; | |
a2cdb048 | 532 | else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) |
462f4eff CF |
533 | { |
534 | set_winsock_errno (); | |
535 | res = -1; | |
536 | } | |
a2cdb048 | 537 | else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) |
462f4eff | 538 | set_winsock_errno (); |
1fd5e000 | 539 | } |
a2cdb048 CV |
540 | |
541 | syscall_printf ("%d = sendto (%d, %x, %x, %x)", res, fd, buf, len, flags); | |
542 | ||
1fd5e000 CF |
543 | return res; |
544 | } | |
545 | ||
546 | /* exported as recvfrom: standards? */ | |
4e6a4ea8 | 547 | extern "C" int |
1fd5e000 CF |
548 | cygwin_recvfrom (int fd, |
549 | char *buf, | |
550 | int len, | |
551 | int flags, | |
552 | struct sockaddr *from, | |
553 | int *fromlen) | |
554 | { | |
a2cdb048 CV |
555 | int res; |
556 | wsock_event wsock_evt; | |
557 | LPWSAOVERLAPPED ovr; | |
0381fec6 | 558 | fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; |
3b0d65ea | 559 | sigframe thisframe (mainthread); |
1fd5e000 | 560 | |
a2cdb048 | 561 | if (!(ovr = wsock_evt.prepare ())) |
1fd5e000 | 562 | { |
a2cdb048 CV |
563 | debug_printf ("Fallback to winsock 1 recvfrom call"); |
564 | if ((res = recvfrom (h->get_socket (), buf, len, flags, from, fromlen)) | |
462f4eff | 565 | == SOCKET_ERROR) |
a2cdb048 CV |
566 | { |
567 | set_winsock_errno (); | |
568 | res = -1; | |
569 | } | |
570 | } | |
571 | else | |
572 | { | |
573 | WSABUF wsabuf = { len, (char *) buf }; | |
574 | DWORD ret = 0; | |
575 | if (WSARecvFrom (h->get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags, | |
462f4eff CF |
576 | from, fromlen, ovr, NULL) != SOCKET_ERROR) |
577 | res = ret; | |
a2cdb048 | 578 | else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) |
462f4eff CF |
579 | { |
580 | set_winsock_errno (); | |
581 | res = -1; | |
582 | } | |
a2cdb048 | 583 | else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) |
462f4eff | 584 | set_winsock_errno (); |
1fd5e000 CF |
585 | } |
586 | ||
a2cdb048 CV |
587 | syscall_printf ("%d = recvfrom (%d, %x, %x, %x)", res, fd, buf, len, flags); |
588 | ||
1fd5e000 CF |
589 | return res; |
590 | } | |
591 | ||
592 | /* Cygwin internal */ | |
593 | fhandler_socket * | |
594 | get (int fd) | |
595 | { | |
0381fec6 | 596 | if (cygheap->fdtab.not_open (fd)) |
1fd5e000 CF |
597 | { |
598 | set_errno (EINVAL); | |
599 | return 0; | |
600 | } | |
601 | ||
0381fec6 | 602 | return cygheap->fdtab[fd]->is_socket (); |
1fd5e000 CF |
603 | } |
604 | ||
605 | /* exported as setsockopt: standards? */ | |
4e6a4ea8 | 606 | extern "C" int |
1fd5e000 CF |
607 | cygwin_setsockopt (int fd, |
608 | int level, | |
609 | int optname, | |
610 | const void *optval, | |
611 | int optlen) | |
612 | { | |
613 | fhandler_socket *h = get (fd); | |
614 | int res = -1; | |
615 | const char *name = "error"; | |
616 | ||
617 | if (h) | |
618 | { | |
619 | /* For the following debug_printf */ | |
620 | switch (optname) | |
621 | { | |
622 | case SO_DEBUG: | |
623 | name="SO_DEBUG"; | |
624 | break; | |
625 | case SO_ACCEPTCONN: | |
626 | name="SO_ACCEPTCONN"; | |
627 | break; | |
628 | case SO_REUSEADDR: | |
629 | name="SO_REUSEADDR"; | |
630 | break; | |
631 | case SO_KEEPALIVE: | |
632 | name="SO_KEEPALIVE"; | |
633 | break; | |
634 | case SO_DONTROUTE: | |
635 | name="SO_DONTROUTE"; | |
636 | break; | |
637 | case SO_BROADCAST: | |
638 | name="SO_BROADCAST"; | |
639 | break; | |
640 | case SO_USELOOPBACK: | |
641 | name="SO_USELOOPBACK"; | |
642 | break; | |
643 | case SO_LINGER: | |
644 | name="SO_LINGER"; | |
645 | break; | |
646 | case SO_OOBINLINE: | |
647 | name="SO_OOBINLINE"; | |
648 | break; | |
c90e420d CF |
649 | case SO_ERROR: |
650 | name="SO_ERROR"; | |
651 | break; | |
1fd5e000 CF |
652 | } |
653 | ||
654 | res = setsockopt (h->get_socket (), level, optname, | |
655 | (const char *) optval, optlen); | |
656 | ||
657 | if (optlen == 4) | |
658 | syscall_printf ("setsockopt optval=%x", *(long *) optval); | |
659 | ||
660 | if (res) | |
661 | set_winsock_errno (); | |
662 | } | |
663 | ||
664 | syscall_printf ("%d = setsockopt (%d, %d, %x (%s), %x, %d)", | |
665 | res, fd, level, optname, name, optval, optlen); | |
666 | return res; | |
667 | } | |
668 | ||
669 | /* exported as getsockopt: standards? */ | |
4e6a4ea8 | 670 | extern "C" int |
1fd5e000 CF |
671 | cygwin_getsockopt (int fd, |
672 | int level, | |
673 | int optname, | |
674 | void *optval, | |
675 | int *optlen) | |
676 | { | |
677 | fhandler_socket *h = get (fd); | |
678 | int res = -1; | |
679 | const char *name = "error"; | |
680 | if (h) | |
681 | { | |
682 | /* For the following debug_printf */ | |
683 | switch (optname) | |
684 | { | |
685 | case SO_DEBUG: | |
686 | name="SO_DEBUG"; | |
687 | break; | |
688 | case SO_ACCEPTCONN: | |
689 | name="SO_ACCEPTCONN"; | |
690 | break; | |
691 | case SO_REUSEADDR: | |
692 | name="SO_REUSEADDR"; | |
693 | break; | |
694 | case SO_KEEPALIVE: | |
695 | name="SO_KEEPALIVE"; | |
696 | break; | |
697 | case SO_DONTROUTE: | |
698 | name="SO_DONTROUTE"; | |
699 | break; | |
700 | case SO_BROADCAST: | |
701 | name="SO_BROADCAST"; | |
702 | break; | |
703 | case SO_USELOOPBACK: | |
704 | name="SO_USELOOPBACK"; | |
705 | break; | |
706 | case SO_LINGER: | |
707 | name="SO_LINGER"; | |
708 | break; | |
709 | case SO_OOBINLINE: | |
710 | name="SO_OOBINLINE"; | |
711 | break; | |
c90e420d CF |
712 | case SO_ERROR: |
713 | name="SO_ERROR"; | |
714 | break; | |
1fd5e000 CF |
715 | } |
716 | ||
717 | res = getsockopt (h->get_socket (), level, optname, | |
718 | (char *) optval, (int *) optlen); | |
719 | ||
c90e420d CF |
720 | if (optname == SO_ERROR) |
721 | { | |
722 | int *e = (int *) optval; | |
723 | *e = find_winsock_errno (*e); | |
724 | } | |
725 | ||
1fd5e000 CF |
726 | if (res) |
727 | set_winsock_errno (); | |
728 | } | |
729 | ||
730 | syscall_printf ("%d = getsockopt (%d, %d, %x (%s), %x, %d)", | |
731 | res, fd, level, optname, name, optval, optlen); | |
732 | return res; | |
733 | } | |
734 | ||
735 | /* exported as connect: standards? */ | |
4e6a4ea8 | 736 | extern "C" int |
1fd5e000 CF |
737 | cygwin_connect (int fd, |
738 | const struct sockaddr *name, | |
739 | int namelen) | |
740 | { | |
741 | int res; | |
619f7fa0 | 742 | BOOL secret_check_failed = FALSE; |
ae036f47 | 743 | BOOL in_progress = FALSE; |
1fd5e000 CF |
744 | fhandler_socket *sock = get (fd); |
745 | sockaddr_in sin; | |
619f7fa0 | 746 | int secret [4]; |
3b0d65ea | 747 | sigframe thisframe (mainthread); |
1fd5e000 | 748 | |
619f7fa0 | 749 | if (get_inet_addr (name, namelen, &sin, &namelen, secret) == 0) |
1fd5e000 CF |
750 | return -1; |
751 | ||
752 | if (!sock) | |
753 | { | |
754 | res = -1; | |
755 | } | |
756 | else | |
757 | { | |
758 | res = connect (sock->get_socket (), (sockaddr *) &sin, namelen); | |
759 | if (res) | |
462f4eff | 760 | { |
4c25744f CV |
761 | /* Special handling for connect to return the correct error code |
762 | when called to early on a non-blocking socket. */ | |
763 | if (WSAGetLastError () == WSAEWOULDBLOCK) | |
ae036f47 ED |
764 | { |
765 | WSASetLastError (WSAEINPROGRESS); | |
766 | in_progress = TRUE; | |
767 | } | |
4c25744f CV |
768 | |
769 | set_winsock_errno (); | |
462f4eff | 770 | } |
619f7fa0 | 771 | if (sock->get_addr_family () == AF_UNIX) |
462f4eff CF |
772 | { |
773 | if (!res || in_progress) | |
774 | { | |
775 | if (!sock->create_secret_event (secret)) | |
776 | { | |
619f7fa0 ED |
777 | secret_check_failed = TRUE; |
778 | } | |
ae036f47 ED |
779 | else if (in_progress) |
780 | sock->signal_secret_event (); | |
462f4eff | 781 | } |
619f7fa0 | 782 | |
462f4eff CF |
783 | if (!secret_check_failed && !res) |
784 | { | |
619f7fa0 ED |
785 | if (!sock->check_peer_secret_event (&sin, secret)) |
786 | { | |
787 | debug_printf ( "accept from unauthorized server" ); | |
788 | secret_check_failed = TRUE; | |
789 | } | |
462f4eff | 790 | } |
619f7fa0 | 791 | |
462f4eff CF |
792 | if (secret_check_failed) |
793 | { | |
619f7fa0 | 794 | sock->close_secret_event (); |
462f4eff CF |
795 | if (res) |
796 | closesocket (res); | |
619f7fa0 ED |
797 | set_errno (ECONNREFUSED); |
798 | res = -1; | |
462f4eff CF |
799 | } |
800 | } | |
1fd5e000 CF |
801 | } |
802 | return res; | |
803 | } | |
804 | ||
805 | /* exported as getservbyname: standards? */ | |
4e6a4ea8 | 806 | extern "C" struct servent * |
1fd5e000 CF |
807 | cygwin_getservbyname (const char *name, const char *proto) |
808 | { | |
809 | struct servent *p = getservbyname (name, proto); | |
810 | if (!p) | |
811 | set_winsock_errno (); | |
812 | ||
813 | syscall_printf ("%x = getservbyname (%s, %s)", p, name, proto); | |
814 | return p; | |
815 | } | |
816 | ||
817 | /* exported as getservbyport: standards? */ | |
4e6a4ea8 | 818 | extern "C" struct servent * |
1fd5e000 CF |
819 | cygwin_getservbyport (int port, const char *proto) |
820 | { | |
821 | struct servent *p = getservbyport (port, proto); | |
822 | if (!p) | |
823 | set_winsock_errno (); | |
824 | ||
825 | syscall_printf ("%x = getservbyport (%d, %s)", p, port, proto); | |
826 | return p; | |
827 | } | |
828 | ||
4e6a4ea8 | 829 | extern "C" int |
1fd5e000 CF |
830 | cygwin_gethostname (char *name, size_t len) |
831 | { | |
4e6a4ea8 | 832 | int PASCAL win32_gethostname (char*, int); |
1fd5e000 CF |
833 | |
834 | if (wsock32_handle == NULL || | |
835 | win32_gethostname (name, len) == SOCKET_ERROR) | |
836 | { | |
837 | DWORD local_len = len; | |
838 | ||
839 | if (!GetComputerNameA (name, &local_len)) | |
840 | { | |
841 | set_winsock_errno (); | |
842 | return -1; | |
843 | } | |
844 | } | |
845 | debug_printf ("name %s\n", name); | |
846 | h_errno = 0; | |
847 | return 0; | |
848 | } | |
849 | ||
850 | /* exported as gethostbyname: standards? */ | |
4e6a4ea8 | 851 | extern "C" struct hostent * |
1fd5e000 CF |
852 | cygwin_gethostbyname (const char *name) |
853 | { | |
854 | static unsigned char tmp_addr[4]; | |
855 | static struct hostent tmp; | |
856 | static char *tmp_aliases[1] = {0}; | |
4e6a4ea8 | 857 | static char *tmp_addr_list[2] = {0, 0}; |
1fd5e000 | 858 | static int a, b, c, d; |
4e6a4ea8 CF |
859 | |
860 | if (sscanf (name, "%d.%d.%d.%d", &a, &b, &c, &d) == 4) | |
1fd5e000 CF |
861 | { |
862 | /* In case you don't have DNS, at least x.x.x.x still works */ | |
4e6a4ea8 | 863 | memset (&tmp, 0, sizeof (tmp)); |
1fd5e000 CF |
864 | tmp_addr[0] = a; |
865 | tmp_addr[1] = b; | |
866 | tmp_addr[2] = c; | |
867 | tmp_addr[3] = d; | |
868 | tmp_addr_list[0] = (char *)tmp_addr; | |
869 | tmp.h_name = name; | |
870 | tmp.h_aliases = tmp_aliases; | |
871 | tmp.h_addrtype = 2; | |
872 | tmp.h_length = 4; | |
873 | tmp.h_addr_list = tmp_addr_list; | |
874 | return &tmp; | |
875 | } | |
876 | ||
877 | struct hostent *ptr = gethostbyname (name); | |
878 | if (!ptr) | |
879 | { | |
880 | set_winsock_errno (); | |
881 | set_host_errno (); | |
882 | } | |
883 | else | |
884 | { | |
885 | debug_printf ("h_name %s", ptr->h_name); | |
886 | h_errno = 0; | |
887 | } | |
888 | return ptr; | |
889 | } | |
890 | ||
891 | /* exported as accept: standards? */ | |
4e6a4ea8 | 892 | extern "C" int |
1fd5e000 CF |
893 | cygwin_accept (int fd, struct sockaddr *peer, int *len) |
894 | { | |
895 | int res = -1; | |
619f7fa0 | 896 | BOOL secret_check_failed = FALSE; |
ae036f47 | 897 | BOOL in_progress = FALSE; |
3b0d65ea | 898 | sigframe thisframe (mainthread); |
1fd5e000 CF |
899 | |
900 | fhandler_socket *sock = get (fd); | |
901 | if (sock) | |
902 | { | |
7eb971a5 CV |
903 | /* Allows NULL peer and len parameters. */ |
904 | struct sockaddr_in peer_dummy; | |
905 | int len_dummy; | |
906 | if (!peer) | |
96a3f4ae | 907 | peer = (struct sockaddr *) &peer_dummy; |
7eb971a5 | 908 | if (!len) |
96a3f4ae | 909 | { |
7eb971a5 CV |
910 | len_dummy = sizeof (struct sockaddr_in); |
911 | len = &len_dummy; | |
912 | } | |
913 | ||
1fd5e000 CF |
914 | /* accept on NT fails if len < sizeof (sockaddr_in) |
915 | * some programs set len to | |
4e6a4ea8 | 916 | * sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain |
1fd5e000 CF |
917 | */ |
918 | if (len && ((unsigned) *len < sizeof (struct sockaddr_in))) | |
919 | *len = sizeof (struct sockaddr_in); | |
920 | ||
921 | res = accept (sock->get_socket (), peer, len); // can't use a blocking call inside a lock | |
922 | ||
ae036f47 ED |
923 | if ((SOCKET) res == (SOCKET) INVALID_SOCKET && |
924 | WSAGetLastError () == WSAEWOULDBLOCK) | |
925 | in_progress = TRUE; | |
926 | ||
619f7fa0 | 927 | if (sock->get_addr_family () == AF_UNIX) |
462f4eff | 928 | { |
ae036f47 ED |
929 | if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress) |
930 | { | |
931 | if (!sock->create_secret_event ()) | |
932 | secret_check_failed = TRUE; | |
933 | else if (in_progress) | |
934 | sock->signal_secret_event (); | |
935 | } | |
936 | ||
937 | if (!secret_check_failed && | |
462f4eff CF |
938 | (SOCKET) res != (SOCKET) INVALID_SOCKET) |
939 | { | |
619f7fa0 ED |
940 | if (!sock->check_peer_secret_event ((struct sockaddr_in*) peer)) |
941 | { | |
942 | debug_printf ("connect from unauthorized client"); | |
943 | secret_check_failed = TRUE; | |
462f4eff CF |
944 | } |
945 | } | |
946 | ||
947 | if (secret_check_failed) | |
948 | { | |
949 | sock->close_secret_event (); | |
950 | if ((SOCKET) res != (SOCKET) INVALID_SOCKET) | |
951 | closesocket (res); | |
619f7fa0 | 952 | set_errno (ECONNABORTED); |
462f4eff CF |
953 | res = -1; |
954 | goto done; | |
955 | } | |
956 | } | |
619f7fa0 | 957 | |
4e6a4ea8 | 958 | SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept"); |
1fd5e000 | 959 | |
0381fec6 | 960 | int res_fd = cygheap->fdtab.find_unused_handle (); |
1fd5e000 CF |
961 | if (res_fd == -1) |
962 | { | |
963 | /* FIXME: what is correct errno? */ | |
964 | set_errno (EMFILE); | |
619f7fa0 | 965 | goto lock_done; |
1fd5e000 CF |
966 | } |
967 | if ((SOCKET) res == (SOCKET) INVALID_SOCKET) | |
968 | set_winsock_errno (); | |
969 | else | |
970 | { | |
619f7fa0 ED |
971 | fhandler_socket* res_fh = fdsock (res_fd, sock->get_name (), res); |
972 | res_fh->set_addr_family (sock->get_addr_family ()); | |
1fd5e000 CF |
973 | res = res_fd; |
974 | } | |
975 | } | |
619f7fa0 ED |
976 | lock_done: |
977 | ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept"); | |
1fd5e000 CF |
978 | done: |
979 | syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len); | |
1fd5e000 CF |
980 | return res; |
981 | } | |
982 | ||
983 | /* exported as bind: standards? */ | |
4e6a4ea8 | 984 | extern "C" int |
55ae1dff | 985 | cygwin_bind (int fd, const struct sockaddr *my_addr, int addrlen) |
1fd5e000 CF |
986 | { |
987 | int res = -1; | |
988 | ||
989 | fhandler_socket *sock = get (fd); | |
990 | if (sock) | |
991 | { | |
992 | if (my_addr->sa_family == AF_UNIX) | |
993 | { | |
994 | #define un_addr ((struct sockaddr_un *) my_addr) | |
995 | struct sockaddr_in sin; | |
996 | int len = sizeof sin; | |
997 | int fd; | |
998 | ||
b0e82b74 CF |
999 | if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN) |
1000 | { | |
1001 | set_errno (ENAMETOOLONG); | |
1002 | goto out; | |
1003 | } | |
1fd5e000 CF |
1004 | sin.sin_family = AF_INET; |
1005 | sin.sin_port = 0; | |
1006 | sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
1007 | if (bind (sock->get_socket (), (sockaddr *) &sin, len)) | |
1008 | { | |
1009 | syscall_printf ("AF_UNIX: bind failed %d", get_errno ()); | |
1010 | set_winsock_errno (); | |
1011 | goto out; | |
1012 | } | |
1013 | if (getsockname (sock->get_socket (), (sockaddr *) &sin, &len)) | |
1014 | { | |
1015 | syscall_printf ("AF_UNIX: getsockname failed %d", get_errno ()); | |
1016 | set_winsock_errno (); | |
1017 | goto out; | |
1018 | } | |
1019 | ||
1020 | sin.sin_port = ntohs (sin.sin_port); | |
1021 | debug_printf ("AF_UNIX: socket bound to port %u", sin.sin_port); | |
1022 | ||
b0e82b74 | 1023 | /* bind must fail if file system socket object already exists |
4e6a4ea8 | 1024 | so _open () is called with O_EXCL flag. */ |
1fd5e000 | 1025 | fd = _open (un_addr->sun_path, |
b0e82b74 CF |
1026 | O_WRONLY | O_CREAT | O_EXCL | O_BINARY, |
1027 | 0); | |
1fd5e000 | 1028 | if (fd < 0) |
b0e82b74 CF |
1029 | { |
1030 | if (get_errno () == EEXIST) | |
1031 | set_errno (EADDRINUSE); | |
1fd5e000 | 1032 | goto out; |
b0e82b74 | 1033 | } |
1fd5e000 | 1034 | |
462f4eff | 1035 | sock->set_connect_secret (); |
619f7fa0 ED |
1036 | |
1037 | char buf[sizeof (SOCKET_COOKIE) + 80]; | |
1038 | __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port); | |
462f4eff | 1039 | sock->get_connect_secret (strchr (buf, '\0')); |
b0e82b74 | 1040 | len = strlen (buf) + 1; |
1fd5e000 | 1041 | |
b0e82b74 CF |
1042 | /* Note that the terminating nul is written. */ |
1043 | if (_write (fd, buf, len) != len) | |
1044 | { | |
1fd5e000 | 1045 | save_errno here; |
b0e82b74 CF |
1046 | _close (fd); |
1047 | _unlink (un_addr->sun_path); | |
1048 | } | |
1049 | else | |
1050 | { | |
1051 | _close (fd); | |
1052 | chmod (un_addr->sun_path, | |
a4785603 | 1053 | (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask); |
1fd5e000 | 1054 | res = 0; |
b0e82b74 | 1055 | } |
1fd5e000 CF |
1056 | #undef un_addr |
1057 | } | |
1058 | else if (bind (sock->get_socket (), my_addr, addrlen)) | |
1059 | set_winsock_errno (); | |
1060 | else | |
1061 | res = 0; | |
1062 | } | |
1063 | ||
1064 | out: | |
1065 | syscall_printf ("%d = bind (%d, %x, %d)", res, fd, my_addr, addrlen); | |
1066 | return res; | |
1067 | } | |
1068 | ||
1069 | /* exported as getsockname: standards? */ | |
4e6a4ea8 | 1070 | extern "C" int |
1fd5e000 CF |
1071 | cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen) |
1072 | { | |
1073 | int res = -1; | |
1074 | ||
1075 | fhandler_socket *sock = get (fd); | |
1076 | if (sock) | |
1077 | { | |
1078 | res = getsockname (sock->get_socket (), addr, namelen); | |
1079 | if (res) | |
1080 | set_winsock_errno (); | |
1081 | ||
1082 | } | |
1083 | syscall_printf ("%d = getsockname (%d, %x, %d)", res, fd, addr, namelen); | |
1084 | return res; | |
1085 | } | |
1086 | ||
1087 | /* exported as gethostbyaddr: standards? */ | |
4e6a4ea8 | 1088 | extern "C" struct hostent * |
1fd5e000 CF |
1089 | cygwin_gethostbyaddr (const char *addr, int len, int type) |
1090 | { | |
1091 | struct hostent *ptr = gethostbyaddr (addr, len, type); | |
1092 | if (!ptr) | |
1093 | { | |
1094 | set_winsock_errno (); | |
1095 | set_host_errno (); | |
1096 | } | |
1097 | else | |
1098 | { | |
1099 | debug_printf ("h_name %s", ptr->h_name); | |
1100 | h_errno = 0; | |
1101 | } | |
1102 | return ptr; | |
1103 | } | |
1104 | ||
1105 | /* exported as listen: standards? */ | |
4e6a4ea8 | 1106 | extern "C" int |
1fd5e000 CF |
1107 | cygwin_listen (int fd, int backlog) |
1108 | { | |
1109 | int res = -1; | |
1110 | ||
1111 | ||
1112 | fhandler_socket *sock = get (fd); | |
1113 | if (sock) | |
1114 | { | |
1115 | res = listen (sock->get_socket (), backlog); | |
1116 | if (res) | |
1117 | set_winsock_errno (); | |
1118 | } | |
1119 | syscall_printf ("%d = listen (%d, %d)", res, fd, backlog); | |
1120 | return res; | |
1121 | } | |
1122 | ||
1123 | /* exported as shutdown: standards? */ | |
4e6a4ea8 | 1124 | extern "C" int |
1fd5e000 CF |
1125 | cygwin_shutdown (int fd, int how) |
1126 | { | |
1127 | int res = -1; | |
3b0d65ea | 1128 | sigframe thisframe (mainthread); |
1fd5e000 CF |
1129 | |
1130 | fhandler_socket *sock = get (fd); | |
1131 | if (sock) | |
1132 | { | |
1133 | res = shutdown (sock->get_socket (), how); | |
1134 | if (res) | |
1135 | set_winsock_errno (); | |
1136 | } | |
1137 | syscall_printf ("%d = shutdown (%d, %d)", res, fd, how); | |
1138 | return res; | |
1139 | } | |
1140 | ||
7d9688b7 CV |
1141 | /* exported as hstrerror: BSD 4.3 */ |
1142 | extern "C" const char * | |
1143 | cygwin_hstrerror (int err) | |
1144 | { | |
1145 | int i; | |
1146 | ||
1147 | for (i = 0; host_errmap[i].e != 0; ++i) | |
1148 | if (err == host_errmap[i].e) | |
1149 | break; | |
1150 | ||
1151 | return host_errmap[i].s; | |
1152 | } | |
1153 | ||
1154 | /* exported as herror: BSD 4.3 */ | |
4e6a4ea8 | 1155 | extern "C" void |
7d9688b7 | 1156 | cygwin_herror (const char *s) |
1fd5e000 | 1157 | { |
0381fec6 | 1158 | if (cygheap->fdtab.not_open (2)) |
7d9688b7 CV |
1159 | return; |
1160 | ||
1161 | if (s) | |
1162 | { | |
1163 | write (2, s, strlen (s)); | |
1164 | write (2, ": ", 2); | |
1165 | } | |
1166 | ||
1167 | const char *h_errstr = cygwin_hstrerror (h_errno); | |
1168 | ||
1169 | if (!h_errstr) | |
1170 | switch (h_errno) | |
1171 | { | |
1172 | case NETDB_INTERNAL: | |
462f4eff CF |
1173 | h_errstr = "Resolver internal error"; |
1174 | break; | |
7d9688b7 | 1175 | case NETDB_SUCCESS: |
462f4eff CF |
1176 | h_errstr = "Resolver error 0 (no error)"; |
1177 | break; | |
7d9688b7 | 1178 | default: |
462f4eff CF |
1179 | h_errstr = "Unknown resolver error"; |
1180 | break; | |
7d9688b7 CV |
1181 | } |
1182 | write (2, h_errstr, strlen (h_errstr)); | |
1183 | write (2, "\n", 1); | |
1fd5e000 CF |
1184 | } |
1185 | ||
1186 | /* exported as getpeername: standards? */ | |
4e6a4ea8 | 1187 | extern "C" int |
1fd5e000 CF |
1188 | cygwin_getpeername (int fd, struct sockaddr *name, int *len) |
1189 | { | |
0381fec6 | 1190 | fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; |
1fd5e000 CF |
1191 | |
1192 | debug_printf ("getpeername %d", h->get_socket ()); | |
1193 | int res = getpeername (h->get_socket (), name, len); | |
1194 | if (res) | |
1195 | set_winsock_errno (); | |
1196 | ||
1197 | debug_printf ("%d = getpeername %d", res, h->get_socket ()); | |
1198 | return res; | |
1199 | } | |
1200 | ||
1201 | /* exported as recv: standards? */ | |
4e6a4ea8 | 1202 | extern "C" int |
1fd5e000 CF |
1203 | cygwin_recv (int fd, void *buf, int len, unsigned int flags) |
1204 | { | |
a2cdb048 CV |
1205 | int res; |
1206 | wsock_event wsock_evt; | |
1207 | LPWSAOVERLAPPED ovr; | |
0381fec6 | 1208 | fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; |
3b0d65ea | 1209 | sigframe thisframe (mainthread); |
1fd5e000 | 1210 | |
a2cdb048 | 1211 | if (!(ovr = wsock_evt.prepare ())) |
1fd5e000 | 1212 | { |
a2cdb048 CV |
1213 | debug_printf ("Fallback to winsock 1 recv call"); |
1214 | if ((res = recv (h->get_socket (), (char *) buf, len, flags)) | |
462f4eff | 1215 | == SOCKET_ERROR) |
a2cdb048 CV |
1216 | { |
1217 | set_winsock_errno (); | |
1218 | res = -1; | |
1219 | } | |
1220 | } | |
1221 | else | |
1222 | { | |
1223 | WSABUF wsabuf = { len, (char *) buf }; | |
1224 | DWORD ret = 0; | |
1225 | if (WSARecv (h->get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags, | |
1226 | ovr, NULL) != SOCKET_ERROR) | |
1227 | res = ret; | |
1228 | else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) | |
1229 | { | |
1230 | set_winsock_errno (); | |
1231 | res = -1; | |
1232 | } | |
1233 | else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) | |
1234 | set_winsock_errno (); | |
1fd5e000 | 1235 | } |
1fd5e000 CF |
1236 | |
1237 | syscall_printf ("%d = recv (%d, %x, %x, %x)", res, fd, buf, len, flags); | |
1238 | ||
1239 | return res; | |
1240 | } | |
1241 | ||
1242 | /* exported as send: standards? */ | |
4e6a4ea8 | 1243 | extern "C" int |
1fd5e000 CF |
1244 | cygwin_send (int fd, const void *buf, int len, unsigned int flags) |
1245 | { | |
a2cdb048 CV |
1246 | int res; |
1247 | wsock_event wsock_evt; | |
1248 | LPWSAOVERLAPPED ovr; | |
0381fec6 | 1249 | fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; |
3b0d65ea | 1250 | sigframe thisframe (mainthread); |
1fd5e000 | 1251 | |
a2cdb048 | 1252 | if (!(ovr = wsock_evt.prepare ())) |
1fd5e000 | 1253 | { |
a2cdb048 CV |
1254 | debug_printf ("Fallback to winsock 1 send call"); |
1255 | if ((res = send (h->get_socket (), (const char *) buf, len, flags)) | |
1256 | == SOCKET_ERROR) | |
1257 | { | |
1258 | set_winsock_errno (); | |
1259 | res = -1; | |
1260 | } | |
1261 | } | |
1262 | else | |
1263 | { | |
1264 | WSABUF wsabuf = { len, (char *) buf }; | |
1265 | DWORD ret = 0; | |
1266 | if (WSASend (h->get_socket (), &wsabuf, 1, &ret, (DWORD)flags, | |
462f4eff CF |
1267 | ovr, NULL) != SOCKET_ERROR) |
1268 | res = ret; | |
a2cdb048 | 1269 | else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) |
462f4eff CF |
1270 | { |
1271 | set_winsock_errno (); | |
1272 | res = -1; | |
1273 | } | |
a2cdb048 | 1274 | else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) |
462f4eff | 1275 | set_winsock_errno (); |
1fd5e000 CF |
1276 | } |
1277 | ||
1278 | syscall_printf ("%d = send (%d, %x, %d, %x)", res, fd, buf, len, flags); | |
1279 | ||
1280 | return res; | |
1281 | } | |
1282 | ||
1283 | /* getdomainname: standards? */ | |
4e6a4ea8 | 1284 | extern "C" int |
1fd5e000 CF |
1285 | getdomainname (char *domain, int len) |
1286 | { | |
1287 | /* | |
1288 | * This works for Win95 only if the machine is configured to use MS-TCP. | |
1289 | * If a third-party TCP is being used this will fail. | |
1290 | * FIXME: On Win95, is there a way to portably check the TCP stack | |
1291 | * in use and include paths for the Domain name in each ? | |
1292 | * Punt for now and assume MS-TCP on Win95. | |
1293 | */ | |
1294 | reg_key r (HKEY_LOCAL_MACHINE, KEY_READ, | |
e5ba4c06 | 1295 | (!iswinnt) ? "System" : "SYSTEM", |
1fd5e000 | 1296 | "CurrentControlSet", "Services", |
e5ba4c06 | 1297 | (!iswinnt) ? "MSTCP" : "Tcpip", |
1fd5e000 CF |
1298 | NULL); |
1299 | ||
1300 | /* FIXME: Are registry keys case sensitive? */ | |
1301 | if (r.error () || r.get_string ("Domain", domain, len, "") != ERROR_SUCCESS) | |
1302 | { | |
1303 | __seterrno (); | |
1304 | return -1; | |
1305 | } | |
1306 | ||
1307 | return 0; | |
1308 | } | |
1309 | ||
1310 | /* Cygwin internal */ | |
52b5a971 CV |
1311 | /* Fill out an ifconf struct. */ |
1312 | ||
1313 | /* | |
9182099c CV |
1314 | * IFCONF 98/ME, NTSP4, W2K: |
1315 | * Use IP Helper Library | |
1fd5e000 | 1316 | */ |
7326d4e4 | 1317 | static void |
52b5a971 | 1318 | get_2k_ifconf (struct ifconf *ifc, int what) |
1fd5e000 | 1319 | { |
9182099c CV |
1320 | int cnt = 0; |
1321 | char eth[2] = "/", ppp[2] = "/", slp[2] = "/"; | |
7326d4e4 CV |
1322 | |
1323 | /* Union maps buffer to correct struct */ | |
1324 | struct ifreq *ifr = ifc->ifc_req; | |
1325 | ||
9182099c CV |
1326 | DWORD if_cnt, ip_cnt, lip, lnp; |
1327 | DWORD siz_if_table = 0; | |
1328 | DWORD siz_ip_table = 0; | |
1329 | PMIB_IFTABLE ift; | |
1330 | PMIB_IPADDRTABLE ipt; | |
1331 | struct sockaddr_in *sa = NULL; | |
1332 | struct sockaddr *so = NULL; | |
1333 | ||
1334 | if (GetIfTable(NULL, &siz_if_table, TRUE) == ERROR_INSUFFICIENT_BUFFER && | |
1335 | GetIpAddrTable(NULL, &siz_ip_table, TRUE) == ERROR_INSUFFICIENT_BUFFER && | |
1336 | (ift = (PMIB_IFTABLE) alloca (siz_if_table)) && | |
1337 | (ipt = (PMIB_IPADDRTABLE) alloca (siz_ip_table)) && | |
1338 | !GetIfTable(ift, &siz_if_table, TRUE) && | |
1339 | !GetIpAddrTable(ipt, &siz_ip_table, TRUE)) | |
1fd5e000 | 1340 | { |
9182099c | 1341 | for (if_cnt = 0; if_cnt < ift->dwNumEntries; ++if_cnt) |
462f4eff | 1342 | { |
9182099c CV |
1343 | switch (ift->table[if_cnt].dwType) |
1344 | { | |
1345 | case MIB_IF_TYPE_ETHERNET: | |
1346 | ++*eth; | |
1347 | strcpy (ifr->ifr_name, "eth"); | |
1348 | strcat (ifr->ifr_name, eth); | |
1349 | break; | |
1350 | case MIB_IF_TYPE_PPP: | |
1351 | ++*ppp; | |
1352 | strcpy (ifr->ifr_name, "ppp"); | |
1353 | strcat (ifr->ifr_name, ppp); | |
1354 | break; | |
1355 | case MIB_IF_TYPE_SLIP: | |
1356 | ++*slp; | |
1357 | strcpy (ifr->ifr_name, "slp"); | |
1358 | strcat (ifr->ifr_name, slp); | |
1359 | break; | |
1360 | case MIB_IF_TYPE_LOOPBACK: | |
1361 | strcpy (ifr->ifr_name, "lo"); | |
1362 | break; | |
1363 | default: | |
1364 | continue; | |
1365 | } | |
462f4eff CF |
1366 | for (ip_cnt = 0; ip_cnt < ipt->dwNumEntries; ++ip_cnt) |
1367 | if (ipt->table[ip_cnt].dwIndex == ift->table[if_cnt].dwIndex) | |
9182099c | 1368 | { |
462f4eff CF |
1369 | switch (what) |
1370 | { | |
1371 | case SIOCGIFCONF: | |
1372 | case SIOCGIFADDR: | |
1373 | sa = (struct sockaddr_in *) &ifr->ifr_addr; | |
1374 | sa->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr; | |
9182099c CV |
1375 | sa->sin_family = AF_INET; |
1376 | sa->sin_port = 0; | |
462f4eff CF |
1377 | break; |
1378 | case SIOCGIFBRDADDR: | |
1379 | sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; | |
9182099c CV |
1380 | #if 0 |
1381 | /* Unfortunately, the field returns only crap. */ | |
462f4eff | 1382 | sa->sin_addr.s_addr = ipt->table[ip_cnt].dwBCastAddr; |
9182099c | 1383 | #else |
462f4eff CF |
1384 | lip = ipt->table[ip_cnt].dwAddr; |
1385 | lnp = ipt->table[ip_cnt].dwMask; | |
1386 | sa->sin_addr.s_addr = lip & lnp | ~lnp; | |
9182099c CV |
1387 | sa->sin_family = AF_INET; |
1388 | sa->sin_port = 0; | |
1389 | #endif | |
462f4eff CF |
1390 | break; |
1391 | case SIOCGIFNETMASK: | |
1392 | sa = (struct sockaddr_in *) &ifr->ifr_netmask; | |
1393 | sa->sin_addr.s_addr = ipt->table[ip_cnt].dwMask; | |
9182099c CV |
1394 | sa->sin_family = AF_INET; |
1395 | sa->sin_port = 0; | |
462f4eff | 1396 | break; |
9182099c | 1397 | case SIOCGIFHWADDR: |
462f4eff | 1398 | so = &ifr->ifr_hwaddr; |
9182099c CV |
1399 | for (UINT i = 0; i < IFHWADDRLEN; ++i) |
1400 | if (i >= ift->table[if_cnt].dwPhysAddrLen) | |
462f4eff | 1401 | so->sa_data[i] = '\0'; |
9182099c | 1402 | else |
462f4eff | 1403 | so->sa_data[i] = ift->table[if_cnt].bPhysAddr[i]; |
9182099c CV |
1404 | so->sa_family = AF_INET; |
1405 | break; | |
1406 | case SIOCGIFMETRIC: | |
1407 | ifr->ifr_metric = 1; | |
1408 | break; | |
1409 | case SIOCGIFMTU: | |
1410 | ifr->ifr_mtu = ift->table[if_cnt].dwMtu; | |
1411 | break; | |
462f4eff CF |
1412 | } |
1413 | ++cnt; | |
1414 | if ((caddr_t) ++ifr > | |
9182099c CV |
1415 | ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) |
1416 | goto done; | |
462f4eff CF |
1417 | break; |
1418 | } | |
9182099c | 1419 | } |
7326d4e4 | 1420 | } |
9182099c | 1421 | done: |
7326d4e4 CV |
1422 | /* Set the correct length */ |
1423 | ifc->ifc_len = cnt * sizeof (struct ifreq); | |
1424 | } | |
1fd5e000 | 1425 | |
52b5a971 | 1426 | /* |
9182099c | 1427 | * IFCONF Windows NT < SP4: |
52b5a971 CV |
1428 | * Look at the Bind value in |
1429 | * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage\ | |
1430 | * This is a REG_MULTI_SZ with strings of the form: | |
1431 | * \Device\<Netcard>, where netcard is the name of the net device. | |
1432 | * Then look under: | |
1433 | * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<NetCard>\ | |
1434 | * Parameters\Tcpip | |
1435 | * at the IPAddress, Subnetmask and DefaultGateway values for the | |
1436 | * required values. | |
1437 | */ | |
7326d4e4 | 1438 | static void |
52b5a971 | 1439 | get_nt_ifconf (struct ifconf *ifc, int what) |
7326d4e4 CV |
1440 | { |
1441 | HKEY key; | |
1442 | unsigned long lip, lnp; | |
52b5a971 | 1443 | struct sockaddr_in *sa = NULL; |
9182099c | 1444 | struct sockaddr *so = NULL; |
52b5a971 | 1445 | DWORD size; |
7326d4e4 CV |
1446 | int cnt = 1; |
1447 | char *binding = (char *) 0; | |
1448 | ||
1449 | /* Union maps buffer to correct struct */ | |
1450 | struct ifreq *ifr = ifc->ifc_req; | |
1451 | ||
1452 | if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, | |
462f4eff CF |
1453 | "SYSTEM\\" |
1454 | "CurrentControlSet\\" | |
1455 | "Services\\" | |
1456 | "Tcpip\\" | |
1457 | "Linkage", | |
1458 | 0, KEY_READ, &key) == ERROR_SUCCESS) | |
7326d4e4 CV |
1459 | { |
1460 | if (RegQueryValueEx (key, "Bind", | |
462f4eff CF |
1461 | NULL, NULL, |
1462 | NULL, &size) == ERROR_SUCCESS) | |
1463 | { | |
1464 | binding = (char *) alloca (size); | |
1465 | if (RegQueryValueEx (key, "Bind", | |
1466 | NULL, NULL, | |
1467 | (unsigned char *) binding, | |
1468 | &size) != ERROR_SUCCESS) | |
1469 | { | |
1470 | binding = NULL; | |
1471 | } | |
1472 | } | |
7326d4e4 CV |
1473 | RegCloseKey (key); |
1474 | } | |
1fd5e000 | 1475 | |
7326d4e4 CV |
1476 | if (binding) |
1477 | { | |
1478 | char *bp, eth[2] = "/"; | |
1479 | char cardkey[256], ipaddress[256], netmask[256]; | |
1480 | ||
4e6a4ea8 | 1481 | for (bp = binding; *bp; bp += strlen (bp) + 1) |
462f4eff CF |
1482 | { |
1483 | bp += strlen ("\\Device\\"); | |
1484 | strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\"); | |
1485 | strcat (cardkey, bp); | |
1486 | strcat (cardkey, "\\Parameters\\Tcpip"); | |
1487 | ||
1488 | if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey, | |
1489 | 0, KEY_READ, &key) != ERROR_SUCCESS) | |
1490 | continue; | |
1491 | ||
1492 | if (RegQueryValueEx (key, "IPAddress", | |
1493 | NULL, NULL, | |
1494 | (unsigned char *) ipaddress, | |
1495 | (size = 256, &size)) == ERROR_SUCCESS | |
1496 | && RegQueryValueEx (key, "SubnetMask", | |
1497 | NULL, NULL, | |
1498 | (unsigned char *) netmask, | |
1499 | (size = 256, &size)) == ERROR_SUCCESS) | |
1500 | { | |
1501 | char *ip, *np; | |
1502 | char dhcpaddress[256], dhcpnetmask[256]; | |
1503 | ||
1504 | for (ip = ipaddress, np = netmask; | |
1505 | *ip && *np; | |
1506 | ip += strlen (ip) + 1, np += strlen (np) + 1) | |
1507 | { | |
1508 | if ((caddr_t) ++ifr > ifc->ifc_buf | |
1509 | + ifc->ifc_len | |
1510 | - sizeof (struct ifreq)) | |
1511 | break; | |
1512 | ||
1513 | if (! strncmp (bp, "NdisWan", 7)) | |
1514 | { | |
1515 | strcpy (ifr->ifr_name, "ppp"); | |
1516 | strcat (ifr->ifr_name, bp + 7); | |
1517 | } | |
1518 | else | |
1519 | { | |
1520 | ++*eth; | |
1521 | strcpy (ifr->ifr_name, "eth"); | |
1522 | strcat (ifr->ifr_name, eth); | |
1523 | } | |
1524 | memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr); | |
1525 | if (cygwin_inet_addr (ip) == 0L | |
1526 | && RegQueryValueEx (key, "DhcpIPAddress", | |
1527 | NULL, NULL, | |
1528 | (unsigned char *) dhcpaddress, | |
1529 | (size = 256, &size)) | |
1530 | == ERROR_SUCCESS | |
1531 | && RegQueryValueEx (key, "DhcpSubnetMask", | |
1532 | NULL, NULL, | |
1533 | (unsigned char *) dhcpnetmask, | |
1534 | (size = 256, &size)) | |
1535 | == ERROR_SUCCESS) | |
1536 | { | |
1537 | switch (what) | |
1538 | { | |
1539 | case SIOCGIFCONF: | |
1540 | case SIOCGIFADDR: | |
1541 | sa = (struct sockaddr_in *) &ifr->ifr_addr; | |
1542 | sa->sin_addr.s_addr = cygwin_inet_addr (dhcpaddress); | |
9182099c CV |
1543 | sa->sin_family = AF_INET; |
1544 | sa->sin_port = 0; | |
462f4eff CF |
1545 | break; |
1546 | case SIOCGIFBRDADDR: | |
1547 | lip = cygwin_inet_addr (dhcpaddress); | |
1548 | lnp = cygwin_inet_addr (dhcpnetmask); | |
1549 | sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; | |
1550 | sa->sin_addr.s_addr = lip & lnp | ~lnp; | |
9182099c CV |
1551 | sa->sin_family = AF_INET; |
1552 | sa->sin_port = 0; | |
462f4eff CF |
1553 | break; |
1554 | case SIOCGIFNETMASK: | |
1555 | sa = (struct sockaddr_in *) &ifr->ifr_netmask; | |
1556 | sa->sin_addr.s_addr = | |
1557 | cygwin_inet_addr (dhcpnetmask); | |
9182099c CV |
1558 | sa->sin_family = AF_INET; |
1559 | sa->sin_port = 0; | |
462f4eff CF |
1560 | break; |
1561 | case SIOCGIFHWADDR: | |
9182099c CV |
1562 | so = &ifr->ifr_hwaddr; |
1563 | memset (so->sa_data, 0, IFHWADDRLEN); | |
1564 | so->sa_family = AF_INET; | |
1565 | break; | |
462f4eff | 1566 | case SIOCGIFMETRIC: |
9182099c CV |
1567 | ifr->ifr_metric = 1; |
1568 | break; | |
1569 | case SIOCGIFMTU: | |
1570 | ifr->ifr_mtu = 1500; | |
1571 | break; | |
462f4eff CF |
1572 | } |
1573 | } | |
1574 | else | |
1575 | { | |
1576 | switch (what) | |
1577 | { | |
1578 | case SIOCGIFCONF: | |
1579 | case SIOCGIFADDR: | |
1580 | sa = (struct sockaddr_in *) &ifr->ifr_addr; | |
1581 | sa->sin_addr.s_addr = cygwin_inet_addr (ip); | |
9182099c CV |
1582 | sa->sin_family = AF_INET; |
1583 | sa->sin_port = 0; | |
462f4eff CF |
1584 | break; |
1585 | case SIOCGIFBRDADDR: | |
1586 | lip = cygwin_inet_addr (ip); | |
1587 | lnp = cygwin_inet_addr (np); | |
1588 | sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; | |
1589 | sa->sin_addr.s_addr = lip & lnp | ~lnp; | |
9182099c CV |
1590 | sa->sin_family = AF_INET; |
1591 | sa->sin_port = 0; | |
462f4eff CF |
1592 | break; |
1593 | case SIOCGIFNETMASK: | |
1594 | sa = (struct sockaddr_in *) &ifr->ifr_netmask; | |
1595 | sa->sin_addr.s_addr = cygwin_inet_addr (np); | |
9182099c CV |
1596 | sa->sin_family = AF_INET; |
1597 | sa->sin_port = 0; | |
462f4eff CF |
1598 | break; |
1599 | case SIOCGIFHWADDR: | |
9182099c CV |
1600 | so = &ifr->ifr_hwaddr; |
1601 | memset (so->sa_data, 0, IFHWADDRLEN); | |
1602 | so->sa_family = AF_INET; | |
1603 | break; | |
462f4eff | 1604 | case SIOCGIFMETRIC: |
9182099c CV |
1605 | ifr->ifr_metric = 1; |
1606 | break; | |
1607 | case SIOCGIFMTU: | |
1608 | ifr->ifr_mtu = 1500; | |
1609 | break; | |
462f4eff CF |
1610 | } |
1611 | } | |
1612 | ++cnt; | |
1613 | } | |
1614 | } | |
1615 | RegCloseKey (key); | |
1616 | } | |
7326d4e4 | 1617 | } |
1fd5e000 | 1618 | |
7326d4e4 CV |
1619 | /* Set the correct length */ |
1620 | ifc->ifc_len = cnt * sizeof (struct ifreq); | |
1621 | } | |
1fd5e000 | 1622 | |
52b5a971 | 1623 | /* |
9182099c | 1624 | * IFCONF Windows 95: |
52b5a971 CV |
1625 | * HKLM/Enum/Network/MSTCP/"*" |
1626 |