]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* net.cc: network-related routines. |
2 | ||
1fd5e000 CF |
3 | This file is part of Cygwin. |
4 | ||
5 | This software is a copyrighted work licensed under the terms of the | |
6 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
7 | details. */ | |
8 | ||
9 | /* #define DEBUG_NEST_ON 1 */ | |
10 | ||
11 | #define __INSIDE_CYGWIN_NET__ | |
acddda4b CV |
12 | #define USE_SYS_TYPES_FD_SET |
13 | #define __WSA_ERR_MACROS_DEFINED | |
4c8d72de | 14 | #include "winsup.h" |
8e220283 CV |
15 | /* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte) |
16 | because a redefinition for LP64 systems is missing. This leads to a wrong | |
acc5f02c | 17 | definition and size of sockaddr_in6 when building with winsock headers. */ |
8e220283 CV |
18 | #undef u_long |
19 | #define u_long __ms_u_long | |
25ea6af1 CV |
20 | #include <w32api/ws2tcpip.h> |
21 | #include <w32api/mswsock.h> | |
22 | #include <w32api/iphlpapi.h> | |
68115c74 | 23 | #define gethostname cygwin_gethostname |
84c7d409 | 24 | #include <unistd.h> |
68115c74 | 25 | #undef gethostname |
25ea6af1 | 26 | #include <ifaddrs.h> |
1fd5e000 | 27 | #include <netdb.h> |
2895b8b5 | 28 | #include <asm/byteorder.h> |
db5ae618 | 29 | #include "shared_info.h" |
bccd5e0d | 30 | #include "path.h" |
7ac61736 | 31 | #include "fhandler.h" |
e2ebe117 | 32 | #include "dtable.h" |
0381fec6 | 33 | #include "cygheap.h" |
ba047ace | 34 | #include "tls_pbuf.h" |
acddda4b CV |
35 | |
36 | /* Unfortunately defined in Windows header files and arpa/nameser_compat.h. */ | |
37 | #undef NOERROR | |
38 | #undef DELETE | |
0a20e5a0 | 39 | #define _CYGWIN_IN_H |
6f57cb4a | 40 | #include <resolv.h> |
1fd5e000 | 41 | |
79224853 CV |
42 | extern "C" |
43 | { | |
44 | int h_errno; | |
1fd5e000 | 45 | |
79224853 | 46 | int sscanf (const char *, const char *, ...); |
64f8b4ca | 47 | int cygwin_inet_pton(int, const char *, void *); |
72203114 | 48 | const char *cygwin_inet_ntop (int, const void *, char *, socklen_t); |
6f57cb4a CV |
49 | int dn_length1(const unsigned char *, const unsigned char *, |
50 | const unsigned char *); | |
79224853 | 51 | } /* End of "C" section */ |
1fd5e000 | 52 | |
aaa7d1f1 AP |
53 | const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; |
54 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | |
70e476d2 | 55 | |
5a64d869 | 56 | static fhandler_socket * |
b4f06520 | 57 | get (const int fd) |
5a64d869 CF |
58 | { |
59 | cygheap_fdget cfd (fd); | |
79224853 | 60 | |
5a64d869 | 61 | if (cfd < 0) |
7f601990 | 62 | return NULL; |
5a64d869 | 63 | |
b4f06520 | 64 | fhandler_socket *const fh = cfd->is_socket (); |
79224853 | 65 | |
141437d3 KB |
66 | if (!fh || (fh->get_flags () & O_PATH)) |
67 | { | |
68 | set_errno (ENOTSOCK); | |
69 | return NULL; | |
70 | } | |
b4f06520 CS |
71 | |
72 | return fh; | |
5a64d869 CF |
73 | } |
74 | ||
0bec0119 | 75 | /* exported as inet_ntoa: BSD 4.3 */ |
4e6a4ea8 | 76 | extern "C" char * |
1fd5e000 CF |
77 | cygwin_inet_ntoa (struct in_addr in) |
78 | { | |
72203114 CV |
79 | char buf[20]; |
80 | const char *res = cygwin_inet_ntop (AF_INET, &in, buf, sizeof buf); | |
79224853 | 81 | |
29d52c8a | 82 | if (_my_tls.locals.ntoa_buf) |
1fdc8df9 | 83 | { |
29d52c8a CF |
84 | free (_my_tls.locals.ntoa_buf); |
85 | _my_tls.locals.ntoa_buf = NULL; | |
1fdc8df9 CV |
86 | } |
87 | if (res) | |
29d52c8a CF |
88 | _my_tls.locals.ntoa_buf = strdup (res); |
89 | return _my_tls.locals.ntoa_buf; | |
1fd5e000 CF |
90 | } |
91 | ||
1fd5e000 CF |
92 | /* inet_netof is in the standard BSD sockets library. It is useless |
93 | for modern networks, since it assumes network values which are no | |
94 | longer meaningful, but some existing code calls it. */ | |
95 | ||
4e6a4ea8 | 96 | extern "C" unsigned long |
1fd5e000 CF |
97 | inet_netof (struct in_addr in) |
98 | { | |
99 | unsigned long i, res; | |
100 | ||
1fd5e000 CF |
101 | i = ntohl (in.s_addr); |
102 | if (IN_CLASSA (i)) | |
103 | res = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT; | |
104 | else if (IN_CLASSB (i)) | |
105 | res = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT; | |
106 | else | |
107 | res = (i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT; | |
108 | ||
1fd5e000 CF |
109 | return res; |
110 | } | |
111 | ||
112 | /* inet_makeaddr is in the standard BSD sockets library. It is | |
113 | useless for modern networks, since it assumes network values which | |
114 | are no longer meaningful, but some existing code calls it. */ | |
115 | ||
4e6a4ea8 | 116 | extern "C" struct in_addr |
1fd5e000 CF |
117 | inet_makeaddr (int net, int lna) |
118 | { | |
119 | unsigned long i; | |
53a12585 | 120 | struct in_addr in; |
1fd5e000 CF |
121 | |
122 | if (net < IN_CLASSA_MAX) | |
123 | i = (net << IN_CLASSA_NSHIFT) | (lna & IN_CLASSA_HOST); | |
124 | else if (net < IN_CLASSB_MAX) | |
125 | i = (net << IN_CLASSB_NSHIFT) | (lna & IN_CLASSB_HOST); | |
126 | else if (net < 0x1000000) | |
127 | i = (net << IN_CLASSC_NSHIFT) | (lna & IN_CLASSC_HOST); | |
128 | else | |
129 | i = net | lna; | |
130 | ||
131 | in.s_addr = htonl (i); | |
132 | ||
133 | ||
134 | return in; | |
135 | } | |
136 | ||
70c7e8c1 CV |
137 | static const int wsock_errmap[] = |
138 | { | |
139 | 0, /* WSABASEERR (10000) */ | |
140 | 0, /* 10001 */ | |
141 | 0, /* 10002 */ | |
142 | 0, /* 10003 */ | |
143 | EINTR, /* WSAEINTR */ | |
144 | 0, /* 10005 */ | |
145 | 0, /* 10006 */ | |
146 | 0, /* 10007 */ | |
147 | 0, /* 10008 */ | |
148 | EBADF, /* WSAEBADF */ | |
149 | 0, /* 10010 */ | |
150 | 0, /* 10011 */ | |
151 | 0, /* 10012 */ | |
152 | EACCES, /* WSAEACCES */ | |
153 | EFAULT, /* WSAEFAULT */ | |
154 | 0, /* 10015 */ | |
155 | 0, /* 10016 */ | |
156 | 0, /* 10017 */ | |
157 | 0, /* 10018 */ | |
158 | 0, /* 10019 */ | |
159 | 0, /* 10020 */ | |
160 | 0, /* 10021 */ | |
161 | EINVAL, /* WSAEINVAL */ | |
162 | 0, /* 10023 */ | |
163 | EMFILE, /* WSAEMFILE */ | |
164 | 0, /* 10025 */ | |
165 | 0, /* 10026 */ | |
166 | 0, /* 10027 */ | |
167 | 0, /* 10028 */ | |
168 | 0, /* 10029 */ | |
169 | 0, /* 10030 */ | |
170 | 0, /* 10031 */ | |
171 | 0, /* 10032 */ | |
172 | 0, /* 10033 */ | |
173 | 0, /* 10034 */ | |
174 | EWOULDBLOCK, /* WSAEWOULDBLOCK */ | |
175 | EINPROGRESS, /* WSAEINPROGRESS */ | |
176 | EALREADY, /* WSAEALREADY */ | |
177 | ENOTSOCK, /* WSAENOTSOCK */ | |
178 | EDESTADDRREQ, /* WSAEDESTADDRREQ */ | |
179 | EMSGSIZE, /* WSAEMSGSIZE */ | |
180 | EPROTOTYPE, /* WSAEPROTOTYPE */ | |
181 | ENOPROTOOPT, /* WSAENOPROTOOPT */ | |
182 | EPROTONOSUPPORT, /* WSAEPROTONOSUPPORT */ | |
183 | ESOCKTNOSUPPORT, /* WSAESOCKTNOSUPPORT */ | |
184 | EOPNOTSUPP, /* WSAEOPNOTSUPP */ | |
185 | EPFNOSUPPORT, /* WSAEPFNOSUPPORT */ | |
186 | EAFNOSUPPORT, /* WSAEAFNOSUPPORT */ | |
187 | EADDRINUSE, /* WSAEADDRINUSE */ | |
188 | EADDRNOTAVAIL, /* WSAEADDRNOTAVAIL */ | |
189 | ENETDOWN, /* WSAENETDOWN */ | |
190 | ENETUNREACH, /* WSAENETUNREACH */ | |
191 | ENETRESET, /* WSAENETRESET */ | |
192 | ECONNABORTED, /* WSAECONNABORTED */ | |
193 | ECONNRESET, /* WSAECONNRESET */ | |
194 | ENOBUFS, /* WSAENOBUFS */ | |
195 | EISCONN, /* WSAEISCONN */ | |
196 | ENOTCONN, /* WSAENOTCONN */ | |
197 | ESHUTDOWN, /* WSAESHUTDOWN */ | |
198 | ETOOMANYREFS, /* WSAETOOMANYREFS */ | |
199 | ETIMEDOUT, /* WSAETIMEDOUT */ | |
200 | ECONNREFUSED, /* WSAECONNREFUSED */ | |
201 | ELOOP, /* WSAELOOP */ | |
202 | ENAMETOOLONG, /* WSAENAMETOOLONG */ | |
203 | EHOSTDOWN, /* WSAEHOSTDOWN */ | |
204 | EHOSTUNREACH, /* WSAEHOSTUNREACH */ | |
205 | ENOTEMPTY, /* WSAENOTEMPTY */ | |
206 | EPROCLIM, /* WSAEPROCLIM */ | |
207 | EUSERS, /* WSAEUSERS */ | |
208 | EDQUOT, /* WSAEDQUOT */ | |
209 | ESTALE, /* WSAESTALE */ | |
210 | EREMOTE, /* WSAEREMOTE */ | |
1fd5e000 CF |
211 | }; |
212 | ||
ea1e5318 | 213 | int |
044ab77d | 214 | find_winsock_errno (DWORD why) |
c90e420d | 215 | { |
70c7e8c1 CV |
216 | if (!why) |
217 | return 0; | |
218 | if (why < WSABASEERR) | |
219 | geterrno_from_win_error (why, EACCES); | |
220 | ||
221 | why -= WSABASEERR; | |
222 | if (why < sizeof wsock_errmap / sizeof wsock_errmap[0]) | |
223 | return wsock_errmap[why]; | |
c90e420d | 224 | |
489e7e20 | 225 | return EACCES; |
c90e420d CF |
226 | } |
227 | ||
1fd5e000 | 228 | void |
829425c9 | 229 | __set_winsock_errno (const char *fn, int ln) |
1fd5e000 | 230 | { |
c90e420d CF |
231 | DWORD werr = WSAGetLastError (); |
232 | int err = find_winsock_errno (werr); | |
79224853 | 233 | |
c90e420d | 234 | set_errno (err); |
61522196 | 235 | syscall_printf ("%s:%d - winsock error %u -> errno %d", fn, ln, werr, err); |
1fd5e000 CF |
236 | } |
237 | ||
a8c1dd2c CV |
238 | static const struct host_errmap_t |
239 | { | |
240 | DWORD w; /* windows version of error */ | |
241 | const char *s; /* error text returned by herror and hstrerror */ | |
242 | int e; /* errno version of error */ | |
243 | } host_errmap[] = { | |
7d9688b7 CV |
244 | {WSAHOST_NOT_FOUND, "Unknown host", HOST_NOT_FOUND}, |
245 | {WSATRY_AGAIN, "Host name lookup failure", TRY_AGAIN}, | |
246 | {WSANO_RECOVERY, "Unknown server error", NO_RECOVERY}, | |
247 | {WSANO_DATA, "No address associated with name", NO_DATA}, | |
01cf5d0f | 248 | {0, NULL, 0} |
1fd5e000 CF |
249 | }; |
250 | ||
1fd5e000 CF |
251 | static void |
252 | set_host_errno () | |
253 | { | |
254 | int i; | |
255 | ||
044ab77d | 256 | DWORD why = WSAGetLastError (); |
79224853 | 257 | |
7d9688b7 | 258 | for (i = 0; host_errmap[i].w != 0; ++i) |
1fd5e000 CF |
259 | if (why == host_errmap[i].w) |
260 | break; | |
261 | ||
262 | if (host_errmap[i].w != 0) | |
263 | h_errno = host_errmap[i].e; | |
264 | else | |
265 | h_errno = NETDB_INTERNAL; | |
266 | } | |
267 | ||
edf16a29 CF |
268 | inline int |
269 | DWORD_round (int n) | |
1fdc8df9 | 270 | { |
edf16a29 | 271 | return sizeof (DWORD) * (((n + sizeof (DWORD) - 1)) / sizeof (DWORD)); |
1fdc8df9 CV |
272 | } |
273 | ||
edf16a29 CF |
274 | inline int |
275 | strlen_round (const char *s) | |
1fdc8df9 | 276 | { |
edf16a29 CF |
277 | if (!s) |
278 | return 0; | |
279 | return DWORD_round (strlen (s) + 1); | |
1fdc8df9 CV |
280 | } |
281 | ||
edf16a29 CF |
282 | #pragma pack(push,2) |
283 | struct pservent | |
5d0fe635 | 284 | { |
edf16a29 CF |
285 | char *s_name; |
286 | char **s_aliases; | |
287 | short s_port; | |
288 | char *s_proto; | |
289 | }; | |
290 | #pragma pack(pop) | |
1ff9f4b9 | 291 | |
a3de4e19 CF |
292 | static const char *entnames[] = {"host", "proto", "serv"}; |
293 | ||
6f57cb4a CV |
294 | static unionent * |
295 | realloc_ent (unionent *&dst, int sz) | |
296 | { | |
297 | /* Allocate the storage needed. Allocate a rounded size to attempt to force | |
298 | reuse of this buffer so that a poorly-written caller will not be using | |
299 | a freed buffer. */ | |
300 | unsigned rsz = 256 * ((sz + 255) / 256); | |
301 | unionent * ptr; | |
302 | if ((ptr = (unionent *) realloc (dst, rsz))) | |
303 | dst = ptr; | |
304 | return ptr; | |
305 | } | |
306 | ||
307 | static inline hostent * | |
308 | realloc_ent (int sz, hostent *) | |
309 | { | |
310 | return (hostent *) realloc_ent (_my_tls.locals.hostent_buf, sz); | |
311 | } | |
312 | ||
edf16a29 CF |
313 | /* Generic "dup a {host,proto,serv}ent structure" function. |
314 | This is complicated because we need to be able to free the | |
315 | structure at any point and we can't rely on the pointer contents | |
316 | being untouched by callers. So, we allocate a chunk of memory | |
317 | large enough to hold the structure and all of the stuff it points | |
318 | to then we copy the source into this new block of memory. | |
319 | The 'unionent' struct is a union of all of the currently used | |
320 | *ent structure. */ | |
321 | ||
61522196 CV |
322 | /* For some baffling reason, somebody at Microsoft decided that it would be |
323 | a good idea to exchange the s_port and s_proto members in the servent | |
324 | structure. */ | |
325 | struct win64_servent | |
326 | { | |
327 | char *s_name; | |
328 | char **s_aliases; | |
329 | char *s_proto; | |
330 | short s_port; | |
331 | }; | |
332 | #define WIN_SERVENT(x) ((win64_servent *)(x)) | |
61522196 | 333 | |
edf16a29 CF |
334 | #ifdef DEBUGGING |
335 | static void * | |
336 | #else | |
337 | static inline void * | |
338 | #endif | |
f2c11dad | 339 | dup_ent (unionent *&dst, unionent *src, unionent::struct_type type) |
1fdc8df9 | 340 | { |
fe836470 CF |
341 | if (dst) |
342 | debug_printf ("old %sent structure \"%s\" %p\n", entnames[type], | |
f2c11dad | 343 | dst->name, dst); |
fe836470 CF |
344 | |
345 | if (!src) | |
a3de4e19 | 346 | { |
fe836470 CF |
347 | set_winsock_errno (); |
348 | return NULL; | |
a3de4e19 CF |
349 | } |
350 | ||
8b59143f | 351 | debug_printf ("duping %sent \"%s\", %p", entnames[type], src->name, src); |
1fdc8df9 | 352 | |
edf16a29 CF |
353 | /* Find the size of the raw structure minus any character strings, etc. */ |
354 | int sz, struct_sz; | |
355 | switch (type) | |
356 | { | |
f2c11dad | 357 | case unionent::t_protoent: |
edf16a29 CF |
358 | struct_sz = sizeof (protoent); |
359 | break; | |
f2c11dad | 360 | case unionent::t_servent: |
edf16a29 CF |
361 | struct_sz = sizeof (servent); |
362 | break; | |
f2c11dad | 363 | case unionent::t_hostent: |
edf16a29 CF |
364 | struct_sz = sizeof (hostent); |
365 | break; | |
366 | default: | |
367 | api_fatal ("called with invalid value %d", type); | |
368 | break; | |
1fdc8df9 | 369 | } |
1fdc8df9 | 370 | |
6f57cb4a | 371 | /* Every *ent begins with a name. Calculate its length. */ |
edf16a29 CF |
372 | int namelen = strlen_round (src->name); |
373 | sz = struct_sz + namelen; | |
1fdc8df9 | 374 | |
edf16a29 CF |
375 | char **av; |
376 | /* The next field in every *ent is an argv list of "something". | |
377 | Calculate the number of components and how much space the | |
378 | character strings will take. */ | |
379 | int list_len = 0; | |
380 | for (av = src->list; av && *av; av++) | |
381 | { | |
382 | list_len++; | |
383 | sz += sizeof (char **) + strlen_round (*av); | |
384 | } | |
79224853 | 385 | |
edf16a29 CF |
386 | /* NULL terminate if there actually was a list */ |
387 | if (av) | |
388 | { | |
389 | sz += sizeof (char **); | |
390 | list_len++; | |
391 | } | |
1fdc8df9 | 392 | |
edf16a29 CF |
393 | /* Do servent/hostent specific processing */ |
394 | int protolen = 0; | |
395 | int addr_list_len = 0; | |
f2c11dad | 396 | if (type == unionent::t_servent) |
dff017b2 | 397 | { |
61522196 CV |
398 | if (WIN_SERVENT (src)->s_proto) |
399 | sz += (protolen = strlen_round (WIN_SERVENT (src)->s_proto)); | |
dff017b2 | 400 | } |
f2c11dad | 401 | else if (type == unionent::t_hostent) |
edf16a29 CF |
402 | { |
403 | /* Calculate the length and storage used for h_addr_list */ | |
404 | for (av = src->h_addr_list; av && *av; av++) | |
405 | { | |
406 | addr_list_len++; | |
407 | sz += sizeof (char **) + DWORD_round (src->h_len); | |
408 | } | |
409 | if (av) | |
410 | { | |
411 | sz += sizeof (char **); | |
412 | addr_list_len++; | |
413 | } | |
414 | } | |
1fdc8df9 | 415 | |
6f57cb4a CV |
416 | /* Allocate the storage needed. */ |
417 | if (realloc_ent (dst, sz)) | |
edf16a29 | 418 | { |
fe836470 | 419 | memset (dst, 0, sz); |
edf16a29 | 420 | /* This field is common to all *ent structures but named differently |
61522196 CV |
421 | in each, of course. Also, take 64 bit Windows servent weirdness |
422 | into account. */ | |
423 | if (type == unionent::t_servent) | |
424 | dst->port_proto_addrtype = WIN_SERVENT (src)->s_port; | |
425 | else | |
426 | dst->port_proto_addrtype = src->port_proto_addrtype; | |
edf16a29 | 427 | |
edf16a29 | 428 | char *dp = ((char *) dst) + struct_sz; |
8b59143f CF |
429 | if (namelen) |
430 | { | |
431 | /* Copy the name field to dst, using space just beyond the end of | |
432 | the dst structure. */ | |
433 | strcpy (dst->name = dp, src->name); | |
434 | dp += namelen; | |
435 | } | |
edf16a29 CF |
436 | |
437 | /* Copy the 'list' type to dst, using space beyond end of structure | |
438 | + storage for name. */ | |
439 | if (src->list) | |
440 | { | |
441 | char **dav = dst->list = (char **) dp; | |
442 | dp += sizeof (char **) * list_len; | |
443 | for (av = src->list; av && *av; av++) | |
444 | { | |
445 | int len = strlen (*av) + 1; | |
446 | memcpy (*dav++ = dp, *av, len); | |
447 | dp += DWORD_round (len); | |
448 | } | |
449 | } | |
1fdc8df9 | 450 | |
fe836470 | 451 | /* Do servent/protoent/hostent specific processing. */ |
f2c11dad | 452 | if (type == unionent::t_protoent) |
61522196 | 453 | debug_printf ("protoent %s %p %y", dst->name, dst->list, dst->port_proto_addrtype); |
f2c11dad | 454 | else if (type == unionent::t_servent) |
edf16a29 | 455 | { |
61522196 | 456 | if (WIN_SERVENT (src)->s_proto) |
edf16a29 | 457 | { |
61522196 | 458 | strcpy (dst->s_proto = dp, WIN_SERVENT (src)->s_proto); |
edf16a29 CF |
459 | dp += protolen; |
460 | } | |
461 | } | |
f2c11dad | 462 | else if (type == unionent::t_hostent) |
edf16a29 CF |
463 | { |
464 | /* Transfer h_len and duplicate contents of h_addr_list, using | |
465 | memory after 'list' allocation. */ | |
466 | dst->h_len = src->h_len; | |
467 | char **dav = dst->h_addr_list = (char **) dp; | |
468 | dp += sizeof (char **) * addr_list_len; | |
469 | for (av = src->h_addr_list; av && *av; av++) | |
470 | { | |
471 | memcpy (*dav++ = dp, *av, src->h_len); | |
472 | dp += DWORD_round (src->h_len); | |
473 | } | |
474 | } | |
edf16a29 | 475 | } |
a3de4e19 | 476 | debug_printf ("duped %sent \"%s\", %p", entnames[type], dst ? dst->name : "<null!>", dst); |
1fdc8df9 | 477 | return dst; |
1fdc8df9 CV |
478 | } |
479 | ||
f2c11dad CF |
480 | static inline hostent * |
481 | dup_ent (hostent *src) | |
482 | { | |
483 | return (hostent *) dup_ent (_my_tls.locals.hostent_buf, (unionent *) src, unionent::t_hostent); | |
484 | } | |
485 | ||
486 | static inline protoent * | |
487 | dup_ent (protoent *src) | |
488 | { | |
489 | return (protoent *) dup_ent (_my_tls.locals.protoent_buf, (unionent *) src, unionent::t_protoent); | |
490 | } | |
491 | ||
492 | static inline servent * | |
493 | dup_ent (servent *src) | |
494 | { | |
495 | return (servent *) dup_ent (_my_tls.locals.servent_buf, (unionent *) src, unionent::t_servent); | |
496 | } | |
497 | ||
f881942d | 498 | /* exported as getprotobyname: POSIX.1-2001, POSIX.1-2008, 4.3BSD */ |
4e6a4ea8 | 499 | extern "C" struct protoent * |
1fd5e000 CF |
500 | cygwin_getprotobyname (const char *p) |
501 | { | |
3f3bd101 CV |
502 | __try |
503 | { | |
504 | return dup_ent (getprotobyname (p)); | |
505 | } | |
506 | __except (EFAULT) {} | |
507 | __endtry | |
508 | return NULL; | |
1fd5e000 CF |
509 | } |
510 | ||
f881942d | 511 | /* exported as getprotobynumber: POSIX.1-2001, POSIX.1-2008, 4.3BSD */ |
4e6a4ea8 | 512 | extern "C" struct protoent * |
1fd5e000 CF |
513 | cygwin_getprotobynumber (int number) |
514 | { | |
f2c11dad | 515 | return dup_ent (getprotobynumber (number)); |
1fd5e000 CF |
516 | } |
517 | ||
f881942d | 518 | /* exported as socket: POSIX.1-2001, POSIX.1-2008, 4.4BSD */ |
4e6a4ea8 | 519 | extern "C" int |
1fd5e000 CF |
520 | cygwin_socket (int af, int type, int protocol) |
521 | { | |
522 | int res = -1; | |
913c6ca2 CV |
523 | const device *dev; |
524 | fhandler_socket *fh; | |
1fd5e000 | 525 | |
0d653155 CV |
526 | int flags = type & _SOCK_FLAG_MASK; |
527 | type &= ~_SOCK_FLAG_MASK; | |
528 | ||
61522196 | 529 | debug_printf ("socket (%d, %d (flags %y), %d)", af, type, flags, protocol); |
0d653155 | 530 | |
913c6ca2 | 531 | switch (af) |
0d653155 | 532 | { |
913c6ca2 | 533 | case AF_LOCAL: |
6c55be9d CV |
534 | #ifndef __WITH_AF_UNIX |
535 | dev = af_local_dev; | |
536 | #else | |
7f7532fa | 537 | case AF_UNIX: |
7f7532fa | 538 | dev = (af == AF_LOCAL) ? af_local_dev : af_unix_dev; |
6c55be9d | 539 | #endif /* __WITH_AF_UNIX */ |
913c6ca2 CV |
540 | break; |
541 | case AF_INET: | |
542 | case AF_INET6: | |
03f380c2 | 543 | dev = af_inet_dev; |
913c6ca2 CV |
544 | break; |
545 | default: | |
546 | set_errno (EAFNOSUPPORT); | |
0d653155 CV |
547 | goto done; |
548 | } | |
1fd5e000 | 549 | |
913c6ca2 | 550 | if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) |
518f5d49 | 551 | { |
913c6ca2 | 552 | set_errno (EINVAL); |
518f5d49 CV |
553 | goto done; |
554 | } | |
1fd5e000 | 555 | |
913c6ca2 CV |
556 | { |
557 | cygheap_fdnew fd; | |
79224853 | 558 | |
913c6ca2 CV |
559 | if (fd < 0) |
560 | goto done; | |
561 | fh = (fhandler_socket *) build_fh_dev (*dev); | |
562 | if (fh && fh->socket (af, type, protocol, flags) == 0) | |
563 | { | |
564 | fd = fh; | |
565 | if (fd <= 2) | |
566 | set_std_handle (fd); | |
567 | res = fd; | |
568 | } | |
569 | else | |
2bbe8697 | 570 | delete fh; |
913c6ca2 | 571 | } |
1fd5e000 CF |
572 | |
573 | done: | |
61522196 | 574 | syscall_printf ("%R = socket(%d, %d (flags %y), %d)", |
0d653155 | 575 | res, af, type, flags, protocol); |
1fd5e000 CF |
576 | return res; |
577 | } | |
578 | ||
f881942d | 579 | /* exported as sendto: 4.4BSD, SVr4, POSIX.1-2001 */ |
61522196 | 580 | extern "C" ssize_t |
78db7dff CV |
581 | cygwin_sendto (int fd, const void *buf, size_t len, int flags, |
582 | const struct sockaddr *to, socklen_t tolen) | |
1fd5e000 | 583 | { |
3f3bd101 | 584 | ssize_t res = -1; |
61522196 CV |
585 | |
586 | pthread_testcancel (); | |
0a642325 | 587 | |
3f3bd101 CV |
588 | __try |
589 | { | |
590 | fhandler_socket *fh = get (fd); | |
591 | if (fh) | |
592 | res = fh->sendto (buf, len, flags, to, tolen); | |
593 | } | |
594 | __except (EFAULT) {} | |
595 | __endtry | |
61522196 | 596 | syscall_printf ("%lR = sendto(%d, %p, %ld, %y, %p, %d)", |
c250f914 | 597 | res, fd, buf, len, flags, to, tolen); |
1fd5e000 CF |
598 | return res; |
599 | } | |
600 | ||
f881942d | 601 | /* exported as recvfrom: 4.4BSD, SVr4, POSIX.1-2001 */ |
61522196 | 602 | extern "C" ssize_t |
78db7dff CV |
603 | cygwin_recvfrom (int fd, void *buf, size_t len, int flags, |
604 | struct sockaddr *from, socklen_t *fromlen) | |
1fd5e000 | 605 | { |
3f3bd101 | 606 | ssize_t res = -1; |
61522196 CV |
607 | |
608 | pthread_testcancel (); | |
0a642325 | 609 | |
3f3bd101 CV |
610 | __try |
611 | { | |
612 | fhandler_socket *fh = get (fd); | |
613 | if (fh) | |
614 | /* Originally we shortcircuited here if res == 0. | |
615 | Allow 0 bytes buffer. This is valid in POSIX and handled in | |
616 | fhandler_socket::recv_internal. If we shortcircuit, we fail | |
617 | to deliver valid error conditions and peer address. */ | |
618 | res = fh->recvfrom (buf, len, flags, from, fromlen); | |
619 | } | |
620 | __except (EFAULT) {} | |
621 | __endtry | |
61522196 | 622 | syscall_printf ("%lR = recvfrom(%d, %p, %ld, %y, %p, %p)", |
c250f914 | 623 | res, fd, buf, len, flags, from, fromlen); |
1fd5e000 CF |
624 | return res; |
625 | } | |
626 | ||
f881942d | 627 | /* exported as setsockopt: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 628 | extern "C" int |
be5007aa | 629 | cygwin_setsockopt (int fd, int level, int optname, const void *optval, |
78db7dff | 630 | socklen_t optlen) |
1fd5e000 | 631 | { |
ea1e5318 | 632 | int ret = -1; |
1fd5e000 | 633 | |
3f3bd101 | 634 | __try |
b4f06520 | 635 | { |
3f3bd101 | 636 | fhandler_socket *fh = get (fd); |
ea1e5318 CV |
637 | if (fh) |
638 | ret = fh->setsockopt (level, optname, optval, optlen); | |
3f3bd101 | 639 | } |
ea1e5318 | 640 | __except (EFAULT) {} |
3f3bd101 | 641 | __endtry |
61522196 | 642 | syscall_printf ("%R = setsockopt(%d, %d, %y, %p, %d)", |
ea1e5318 CV |
643 | ret, fd, level, optname, optval, optlen); |
644 | return ret; | |
1fd5e000 CF |
645 | } |
646 | ||
f881942d | 647 | /* exported as getsockopt: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 648 | extern "C" int |
78db7dff CV |
649 | cygwin_getsockopt (int fd, int level, int optname, void *optval, |
650 | socklen_t *optlen) | |
1fd5e000 | 651 | { |
ea1e5318 | 652 | int ret = -1; |
1fd5e000 | 653 | |
3f3bd101 | 654 | __try |
b4f06520 | 655 | { |
3f3bd101 | 656 | fhandler_socket *fh = get (fd); |
ea1e5318 CV |
657 | if (fh) |
658 | ret = fh->getsockopt (level, optname, optval, optlen); | |
3f3bd101 | 659 | } |
ea1e5318 | 660 | __except (EFAULT) {} |
3f3bd101 | 661 | __endtry |
61522196 | 662 | syscall_printf ("%R = getsockopt(%d, %d, %y, %p, %p)", |
ea1e5318 CV |
663 | ret, fd, level, optname, optval, optlen); |
664 | return ret; | |
1fd5e000 CF |
665 | } |
666 | ||
d2264bce CV |
667 | /* POSIX.1-2001 */ |
668 | extern "C" int | |
669 | sockatmark (int fd) | |
670 | { | |
671 | int ret; | |
141437d3 | 672 | cygheap_fdget cfd (fd); |
d2264bce | 673 | |
141437d3 KB |
674 | if (cfd < 0) |
675 | return -1; | |
676 | ||
677 | fhandler_socket *const fh = cfd->is_socket (); | |
678 | if (!fh) | |
679 | set_errno (ENOTSOCK); | |
680 | else if (fh->get_flags () & O_PATH) | |
681 | set_errno (EBADF); | |
682 | else if (fh->ioctl (SIOCATMARK, &ret) != -1) | |
d2264bce CV |
683 | return ret; |
684 | return -1; | |
685 | } | |
686 | ||
687 | /* BSD */ | |
c8b404bf | 688 | extern "C" int |
61522196 | 689 | getpeereid (int fd, uid_t *euid, gid_t *egid) |
c8b404bf | 690 | { |
c8b404bf CV |
691 | fhandler_socket *fh = get (fd); |
692 | if (fh) | |
693 | return fh->getpeereid (NULL, euid, egid); | |
694 | return -1; | |
695 | } | |
696 | ||
f881942d | 697 | /* exported as connect: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 698 | extern "C" int |
78db7dff | 699 | cygwin_connect (int fd, const struct sockaddr *name, socklen_t namelen) |
1fd5e000 | 700 | { |
3f3bd101 | 701 | int res = -1; |
0a642325 | 702 | |
61522196 CV |
703 | pthread_testcancel (); |
704 | ||
3f3bd101 CV |
705 | __try |
706 | { | |
707 | fhandler_socket *fh = get (fd); | |
708 | if (fh) | |
709 | res = fh->connect (name, namelen); | |
710 | } | |
711 | __except (EFAULT) {} | |
712 | __endtry | |
b9aa8149 | 713 | syscall_printf ("%R = connect(%d, %p, %d)", res, fd, name, namelen); |
1fd5e000 CF |
714 | return res; |
715 | } | |
716 | ||
f881942d | 717 | /* exported as getservbyname: POSIX.1-2001, POSIX.1-2008, 4.3BSD */ |
4e6a4ea8 | 718 | extern "C" struct servent * |
1fd5e000 CF |
719 | cygwin_getservbyname (const char *name, const char *proto) |
720 | { | |
3f3bd101 | 721 | servent *res = NULL; |
5a64d869 | 722 | |
3f3bd101 CV |
723 | __try |
724 | { | |
725 | res = dup_ent (getservbyname (name, proto)); | |
726 | } | |
727 | __except (EFAULT) {} | |
728 | __endtry | |
4ef6a27a CF |
729 | syscall_printf ("%p = getservbyname (%s, %s)", res, name, proto); |
730 | return res; | |
1fd5e000 CF |
731 | } |
732 | ||
f881942d | 733 | /* exported as getservbyport: POSIX.1-2001, POSIX.1-2008, 4.3BSD */ |
4e6a4ea8 | 734 | extern "C" struct servent * |
1fd5e000 CF |
735 | cygwin_getservbyport (int port, const char *proto) |
736 | { | |
3f3bd101 | 737 | servent *res = NULL; |
5a64d869 | 738 | |
3f3bd101 CV |
739 | __try |
740 | { | |
741 | res = dup_ent (getservbyport (port, proto)); | |
742 | } | |
743 | __except (EFAULT) {} | |
744 | __endtry | |
f2c11dad | 745 | syscall_printf ("%p = getservbyport (%d, %s)", res, port, proto); |
4ef6a27a | 746 | return res; |
1fd5e000 CF |
747 | } |
748 | ||
4e6a4ea8 | 749 | extern "C" int |
1fd5e000 CF |
750 | cygwin_gethostname (char *name, size_t len) |
751 | { | |
3f3bd101 | 752 | __try |
1fd5e000 | 753 | { |
2166f7dc CV |
754 | PFIXED_INFO info = NULL; |
755 | ULONG size = 0; | |
3f3bd101 | 756 | |
2166f7dc CV |
757 | if (GetNetworkParams(info, &size) == ERROR_BUFFER_OVERFLOW |
758 | && (info = (PFIXED_INFO) alloca(size)) | |
759 | && GetNetworkParams(info, &size) == ERROR_SUCCESS) | |
760 | { | |
761 | strncpy(name, info->HostName, len); | |
762 | debug_printf ("gethostname %s", name); | |
763 | return 0; | |
1fd5e000 | 764 | } |
2166f7dc | 765 | __seterrno (); |
1fd5e000 | 766 | } |
2166f7dc | 767 | __except (EFAULT) |
3f3bd101 | 768 | __endtry |
2166f7dc | 769 | return -1; |
1fd5e000 CF |
770 | } |
771 | ||
50b00d2b CV |
772 | extern "C" int |
773 | sethostname (const char *name, size_t len) | |
774 | { | |
775 | WCHAR wname[MAX_COMPUTERNAME_LENGTH + 1]; | |
776 | ||
777 | sys_mbstowcs (wname, MAX_COMPUTERNAME_LENGTH + 1, name, len); | |
778 | if (!SetComputerNameExW (ComputerNamePhysicalDnsHostname, wname)) | |
779 | { | |
780 | __seterrno (); | |
781 | return -1; | |
782 | } | |
783 | return 0; | |
784 | } | |
785 | ||
2166f7dc CV |
786 | /* getdomainname: 4.4BSD */ |
787 | extern "C" int | |
788 | getdomainname (char *domain, size_t len) | |
789 | { | |
790 | __try | |
791 | { | |
792 | PFIXED_INFO info = NULL; | |
793 | ULONG size = 0; | |
794 | ||
795 | if (GetNetworkParams(info, &size) == ERROR_BUFFER_OVERFLOW | |
796 | && (info = (PFIXED_INFO) alloca(size)) | |
797 | && GetNetworkParams(info, &size) == ERROR_SUCCESS) | |
798 | { | |
799 | strncpy(domain, info->DomainName, len); | |
6c9c37d0 | 800 | debug_printf ("getdomainname %s", domain); |
2166f7dc CV |
801 | return 0; |
802 | } | |
803 | __seterrno (); | |
804 | } | |
805 | __except (EFAULT) | |
806 | __endtry | |
807 | return -1; | |
808 | } | |
809 | ||
f881942d | 810 | /* exported as gethostbyname: POSIX.1-2001 */ |
4e6a4ea8 | 811 | extern "C" struct hostent * |
1fd5e000 CF |
812 | cygwin_gethostbyname (const char *name) |
813 | { | |
a694f079 CF |
814 | unsigned char tmp_addr[4]; |
815 | struct hostent tmp, *h; | |
816 | char *tmp_aliases[1] = {0}; | |
817 | char *tmp_addr_list[2] = {0,0}; | |
818 | unsigned int a, b, c, d; | |
819 | char dummy; | |
3f3bd101 | 820 | hostent *res = NULL; |
4e6a4ea8 | 821 | |
3f3bd101 | 822 | __try |
1fd5e000 | 823 | { |
3f3bd101 CV |
824 | if (sscanf (name, "%u.%u.%u.%u%c", &a, &b, &c, &d, &dummy) != 4 |
825 | || a >= 256 || b >= 256 || c >= 256 || d >= 256) | |
826 | h = gethostbyname (name); | |
827 | else | |
828 | { | |
829 | /* In case you don't have DNS, at least x.x.x.x still works */ | |
830 | memset (&tmp, 0, sizeof (tmp)); | |
831 | tmp_addr[0] = a; | |
832 | tmp_addr[1] = b; | |
833 | tmp_addr[2] = c; | |
834 | tmp_addr[3] = d; | |
835 | tmp_addr_list[0] = (char *) tmp_addr; | |
836 | tmp.h_name = name; | |
837 | tmp.h_aliases = tmp_aliases; | |
838 | tmp.h_addrtype = 2; | |
839 | tmp.h_length = 4; | |
840 | tmp.h_addr_list = tmp_addr_list; | |
841 | h = &tmp; | |
842 | } | |
843 | ||
844 | res = dup_ent (h); | |
845 | if (res) | |
846 | debug_printf ("h_name %s", res->h_name); | |
847 | else | |
848 | { | |
849 | debug_printf ("dup_ent returned NULL for name %s, h %p", name, h); | |
850 | set_host_errno (); | |
851 | } | |
852 | } | |
853 | __except (EFAULT) | |
1fd5e000 | 854 | { |
3f3bd101 | 855 | res = NULL; |
1fd5e000 | 856 | } |
3f3bd101 | 857 | __endtry |
4ef6a27a | 858 | return res; |
cb19ccf4 CV |
859 | } |
860 | ||
f881942d | 861 | /* exported as gethostbyaddr: POSIX.1-2001 */ |
cb19ccf4 | 862 | extern "C" struct hostent * |
747f3185 | 863 | cygwin_gethostbyaddr (const void *addr, socklen_t len, int type) |
cb19ccf4 | 864 | { |
3f3bd101 | 865 | hostent *res = NULL; |
5a64d869 | 866 | |
3f3bd101 CV |
867 | __try |
868 | { | |
747f3185 | 869 | res = dup_ent (gethostbyaddr ((const char *) addr, len, type)); |
3f3bd101 CV |
870 | if (res) |
871 | debug_printf ("h_name %s", res->h_name); | |
872 | else | |
873 | set_host_errno (); | |
874 | } | |
875 | __except (EFAULT) | |
876 | { | |
877 | res = NULL; | |
878 | } | |
879 | __endtry | |
4ef6a27a | 880 | return res; |
1fd5e000 CF |
881 | } |
882 | ||
0a20e5a0 | 883 | static void |
acc5f02c | 884 | memcpy4to6 (char *dst, const u_int8_t *src) |
6f57cb4a CV |
885 | { |
886 | const unsigned int h[] = {0, 0, htonl (0xFFFF)}; | |
887 | memcpy (dst, h, 12); | |
888 | memcpy (dst + 12, src, NS_INADDRSZ); | |
889 | } | |
890 | ||
b74bc883 CV |
891 | /* gethostby_specials: RFC 6761 |
892 | Handles numerical addresses and special names for gethostbyname2 */ | |
64f8b4ca CV |
893 | static hostent * |
894 | gethostby_specials (const char *name, const int af, | |
895 | const int addrsize_in, const int addrsize_out) | |
896 | { | |
897 | int namelen = strlen (name); | |
898 | /* Ignore a final '.' */ | |
b74bc883 | 899 | if ((namelen == 0) || ((namelen -= (name[namelen - 1] == '.')) == 0)) |
64f8b4ca CV |
900 | { |
901 | set_errno (EINVAL); | |
902 | h_errno = NETDB_INTERNAL; | |
903 | return NULL; | |
904 | } | |
905 | ||
906 | int res; | |
acc5f02c | 907 | u_int8_t address[NS_IN6ADDRSZ]; |
64f8b4ca CV |
908 | /* Test for numerical addresses */ |
909 | res = cygwin_inet_pton(af, name, address); | |
910 | /* Test for special domain names */ | |
911 | if (res != 1) | |
912 | { | |
913 | { | |
914 | char const match[] = "invalid"; | |
915 | int const matchlen = sizeof(match) - 1; | |
916 | int start = namelen - matchlen; | |
917 | if ((start >= 0) && ((start == 0) || (name[start-1] == '.')) | |
918 | && (strncasecmp (&name[start], match , matchlen) == 0)) | |
919 | { | |
920 | h_errno = HOST_NOT_FOUND; | |
921 | return NULL; | |
922 | } | |
923 | } | |
924 | { | |
925 | char const match[] = "localhost"; | |
926 | int const matchlen = sizeof(match) - 1; | |
927 | int start = namelen - matchlen; | |
928 | if ((start >= 0) && ((start == 0) || (name[start-1] == '.')) | |
929 | && (strncasecmp (&name[start], match , matchlen) == 0)) | |
930 | { | |
931 | res = 1; | |
932 | if (af == AF_INET) | |
933 | { | |
934 | address[0] = 127; | |
935 | address[1] = address[2] = 0; | |
936 | address[3] = 1; | |
937 | } | |
938 | else | |
939 | { | |
940 | memset (address, 0, NS_IN6ADDRSZ); | |
941 | address[NS_IN6ADDRSZ-1] = 1; | |
942 | } | |
943 | } | |
944 | } | |
945 | } | |
946 | if (res != 1) | |
b74bc883 | 947 | return NULL; |
64f8b4ca CV |
948 | |
949 | int const alias_count = 0, address_count = 1; | |
950 | char * string_ptr; | |
951 | int sz = DWORD_round (sizeof(hostent)) | |
952 | + sizeof (char *) * (alias_count + address_count + 2) | |
953 | + namelen + 1 | |
954 | + address_count * addrsize_out; | |
955 | hostent *ret = realloc_ent (sz, (hostent *) NULL); | |
956 | if (!ret) | |
957 | { | |
958 | /* errno is already set */ | |
959 | h_errno = NETDB_INTERNAL; | |
960 | return NULL; | |
961 | } | |
962 | ||
963 | ret->h_addrtype = af; | |
964 | ret->h_length = addrsize_out; | |
965 | ret->h_aliases = (char **) (((char *) ret) + DWORD_round (sizeof(hostent))); | |
966 | ret->h_addr_list = ret->h_aliases + alias_count + 1; | |
967 | string_ptr = (char *) (ret->h_addr_list + address_count + 1); | |
968 | ret->h_name = string_ptr; | |
969 | ||
970 | memcpy (string_ptr, name, namelen); | |
971 | string_ptr[namelen] = 0; | |
972 | string_ptr += namelen + 1; | |
973 | ||
974 | ret->h_addr_list[0] = string_ptr; | |
975 | if (addrsize_in != addrsize_out) | |
976 | { | |
977 | memcpy4to6 (string_ptr, address); | |
978 | ret->h_addrtype = AF_INET6; | |
979 | } | |
980 | else | |
981 | memcpy (string_ptr, address, addrsize_out); | |
982 | ||
983 | ret->h_aliases[alias_count] = NULL; | |
984 | ret->h_addr_list[address_count] = NULL; | |
985 | ||
986 | return ret; | |
987 | } | |
988 | ||
0a20e5a0 | 989 | static hostent * |
6f57cb4a CV |
990 | gethostby_helper (const char *name, const int af, const int type, |
991 | const int addrsize_in, const int addrsize_out) | |
992 | { | |
993 | /* Get the data from the name server */ | |
994 | const int maxcount = 3; | |
995 | int old_errno, ancount = 0, anlen = 1024, msgsize = 0; | |
acc5f02c | 996 | unsigned char *ptr, *msg = NULL; |
6f57cb4a CV |
997 | int sz; |
998 | hostent *ret; | |
999 | char *string_ptr; | |
1000 | ||
1001 | while ((anlen > msgsize) && (ancount++ < maxcount)) | |
1002 | { | |
1003 | msgsize = anlen; | |
acc5f02c | 1004 | ptr = (unsigned char *) realloc (msg, msgsize); |
6f57cb4a CV |
1005 | if (ptr == NULL ) |
1006 | { | |
1007 | old_errno = errno; | |
1008 | free (msg); | |
1009 | set_errno (old_errno); | |
1010 | h_errno = NETDB_INTERNAL; | |
1011 | return NULL; | |
1012 | } | |
1013 | msg = ptr; | |
1014 | anlen = res_search (name, ns_c_in, type, msg, msgsize); | |
0a20e5a0 | 1015 | } |
6f57cb4a CV |
1016 | |
1017 | if (ancount >= maxcount) | |
1018 | { | |
1019 | free (msg); | |
1020 | h_errno = NO_RECOVERY; | |
1021 | return NULL; | |
1022 | } | |
1023 | if (anlen < 0) /* errno and h_errno are set */ | |
1024 | { | |
1025 | old_errno = errno; | |
1026 | free (msg); | |
1027 | set_errno (old_errno); | |
0a20e5a0 | 1028 | return NULL; |
6f57cb4a | 1029 | } |
acc5f02c | 1030 | unsigned char *eomsg = msg + anlen - 1; |
6f57cb4a | 1031 | |
0a20e5a0 | 1032 | /* We scan the answer records to determine the required memory size. |
6f57cb4a CV |
1033 | They can be corrupted and we don't fully trust that the message |
1034 | follows the standard exactly. glibc applies some checks that | |
1035 | we emulate. | |
1036 | The answers are copied in the hostent structure in a second scan. | |
1037 | To simplify the second scan we store information as follows: | |
1038 | - "class" is replaced by the compressed name size | |
0a20e5a0 | 1039 | - the first 16 bits of the "ttl" store the expanded name size + 1 |
6f57cb4a CV |
1040 | - the last 16 bits of the "ttl" store the offset to the next valid record. |
1041 | Note that "type" is rewritten in host byte order. */ | |
0a20e5a0 | 1042 | |
6f57cb4a CV |
1043 | class record { |
1044 | public: | |
1045 | unsigned type: 16; // type | |
1046 | unsigned complen: 16; // class or compressed length | |
1047 | unsigned namelen1: 16; // expanded length (with final 0) | |
1048 | unsigned next_o: 16; // offset to next valid | |
1049 | unsigned size: 16; // data size | |
acc5f02c | 1050 | unsigned char data[]; // data |
6f57cb4a CV |
1051 | record * next () { return (record *) (((char *) this) + next_o); } |
1052 | void set_next ( record * nxt) { next_o = ((char *) nxt) - ((char *) this); } | |
acc5f02c CV |
1053 | unsigned char *name () { return (unsigned char *) |
1054 | (((char *) this) - complen); } | |
6f57cb4a CV |
1055 | }; |
1056 | ||
1057 | record * anptr = NULL, * prevptr = NULL, * curptr; | |
1058 | int i, alias_count = 0, string_size = 0, address_count = 0; | |
0a20e5a0 CF |
1059 | int namelen1 = 0, address_len = 0, antype, anclass, ansize; |
1060 | unsigned complen; | |
6f57cb4a CV |
1061 | |
1062 | /* Get the count of answers */ | |
1063 | ancount = ntohs (((HEADER *) msg)->ancount); | |
1064 | ||
1065 | /* Skip the question, it was verified by res_send */ | |
1066 | ptr = msg + sizeof (HEADER); | |
1067 | if ((complen = dn_skipname (ptr, eomsg)) < 0) | |
0a20e5a0 | 1068 | goto corrupted; |
6f57cb4a CV |
1069 | /* Point to the beginning of the answer section */ |
1070 | ptr += complen + NS_QFIXEDSZ; | |
0a20e5a0 | 1071 | |
6f57cb4a CV |
1072 | /* Scan the answer records to determine the sizes */ |
1073 | for (i = 0; i < ancount; i++, ptr = curptr->data + ansize) | |
1074 | { | |
1075 | if ((complen = dn_skipname (ptr, eomsg)) < 0) | |
1076 | goto corrupted; | |
1077 | ||
1078 | curptr = (record *) (ptr + complen); | |
1079 | antype = ntohs (curptr->type); | |
1080 | anclass = ntohs (curptr->complen); | |
1081 | ansize = ntohs (curptr->size); | |
1082 | /* Class must be internet */ | |
1083 | if (anclass != ns_c_in) | |
1084 | continue; | |
1085 | ||
1086 | curptr->complen = complen; | |
1087 | if ((namelen1 = dn_length1 (msg, eomsg, curptr-> name())) <= 0) | |
1088 | goto corrupted; | |
1089 | ||
0a20e5a0 | 1090 | if (antype == ns_t_cname) |
6f57cb4a CV |
1091 | { |
1092 | alias_count++; | |
1093 | string_size += namelen1; | |
1094 | } | |
1095 | else if (antype == type) | |
1096 | { | |
1097 | ansize = ntohs (curptr->size); | |
1098 | if (ansize != addrsize_in) | |
1099 | continue; | |
1100 | if (address_count == 0) | |
1101 | { | |
1102 | address_len = namelen1; | |
1103 | string_size += namelen1; | |
1104 | } | |
1105 | else if (address_len != namelen1) | |
1106 | continue; | |
1107 | address_count++; | |
1108 | } | |
1109 | /* Update the records */ | |
1110 | curptr->type = antype; /* Host byte order */ | |
1111 | curptr->namelen1 = namelen1; | |
1112 | if (! anptr) | |
1113 | anptr = prevptr = curptr; | |
1114 | else | |
1115 | { | |
1116 | prevptr->set_next (curptr); | |
1117 | prevptr = curptr; | |
1118 | } | |
1119 | } | |
1120 | ||
1121 | /* If there is no address, quit */ | |
1122 | if (address_count == 0) | |
1123 | { | |
1124 | free (msg); | |
1125 | h_errno = NO_DATA; | |
1126 | return NULL; | |
1127 | } | |
0a20e5a0 | 1128 | |
6f57cb4a CV |
1129 | /* Determine the total size */ |
1130 | sz = DWORD_round (sizeof(hostent)) | |
1131 | + sizeof (char *) * (alias_count + address_count + 2) | |
1132 | + string_size | |
1133 | + address_count * addrsize_out; | |
1134 | ||
1135 | ret = realloc_ent (sz, (hostent *) NULL); | |
0a20e5a0 | 1136 | if (! ret) |
6f57cb4a CV |
1137 | { |
1138 | old_errno = errno; | |
1139 | free (msg); | |
1140 | set_errno (old_errno); | |
1141 | h_errno = NETDB_INTERNAL; | |
1142 | return NULL; | |
1143 | } | |
1144 | ||
1145 | ret->h_addrtype = af; | |
1146 | ret->h_length = addrsize_out; | |
1147 | ret->h_aliases = (char **) (((char *) ret) + DWORD_round (sizeof(hostent))); | |
1148 | ret->h_addr_list = ret->h_aliases + alias_count + 1; | |
1149 | string_ptr = (char *) (ret->h_addr_list + address_count + 1); | |
0a20e5a0 | 1150 | |
6f57cb4a | 1151 | /* Rescan the answers */ |
6f57cb4a | 1152 | alias_count = address_count = 0; |
927761a4 | 1153 | prevptr->set_next (prevptr + 1); |
6f57cb4a | 1154 | |
927761a4 | 1155 | for (curptr = anptr; curptr <= prevptr; curptr = curptr->next ()) |
6f57cb4a CV |
1156 | { |
1157 | antype = curptr->type; | |
0a20e5a0 | 1158 | if (antype == ns_t_cname) |
6f57cb4a | 1159 | { |
927761a4 | 1160 | dn_expand (msg, eomsg, curptr->name (), string_ptr, curptr->namelen1); |
6f57cb4a | 1161 | ret->h_aliases[alias_count++] = string_ptr; |
927761a4 | 1162 | string_ptr += curptr->namelen1; |
6f57cb4a | 1163 | } |
927761a4 PH |
1164 | else |
1165 | { | |
1166 | if (address_count == 0) | |
6f57cb4a | 1167 | { |
64f8b4ca CV |
1168 | dn_expand (msg, eomsg, curptr->name (), string_ptr, |
1169 | curptr->namelen1); | |
927761a4 PH |
1170 | ret->h_name = string_ptr; |
1171 | string_ptr += curptr->namelen1; | |
6f57cb4a | 1172 | } |
927761a4 PH |
1173 | ret->h_addr_list[address_count++] = string_ptr; |
1174 | if (addrsize_in != addrsize_out) | |
64f8b4ca CV |
1175 | { |
1176 | memcpy4to6 (string_ptr, curptr->data); | |
1177 | ret->h_addrtype = AF_INET6; | |
1178 | } | |
927761a4 PH |
1179 | else |
1180 | memcpy (string_ptr, curptr->data, addrsize_in); | |
1181 | string_ptr += addrsize_out; | |
1182 | } | |
6f57cb4a | 1183 | } |
0a20e5a0 | 1184 | |
6f57cb4a CV |
1185 | free (msg); |
1186 | ||
1187 | ret->h_aliases[alias_count] = NULL; | |
1188 | ret->h_addr_list[address_count] = NULL; | |
0a20e5a0 | 1189 | |
6f57cb4a CV |
1190 | return ret; |
1191 | ||
64f8b4ca | 1192 | corrupted: |
6f57cb4a CV |
1193 | free (msg); |
1194 | /* Hopefully message corruption errors are temporary. | |
1195 | Should it be NO_RECOVERY ? */ | |
1196 | h_errno = TRY_AGAIN; | |
1197 | return NULL; | |
6f57cb4a CV |
1198 | } |
1199 | ||
f881942d | 1200 | /* gethostbyname2: GNU extension */ |
6f57cb4a CV |
1201 | extern "C" struct hostent * |
1202 | gethostbyname2 (const char *name, int af) | |
1203 | { | |
3f3bd101 | 1204 | hostent *res = NULL; |
6f57cb4a | 1205 | |
3f3bd101 | 1206 | __try |
6f57cb4a | 1207 | { |
3f3bd101 | 1208 | if (!(_res.options & RES_INIT)) |
64f8b4ca | 1209 | res_init(); |
3f3bd101 | 1210 | |
64f8b4ca | 1211 | bool v4to6 = _res.options & RES_USE_INET6; |
3f3bd101 | 1212 | int type, addrsize_in, addrsize_out; |
64f8b4ca | 1213 | |
3f3bd101 CV |
1214 | switch (af) |
1215 | { | |
1216 | case AF_INET: | |
1217 | addrsize_in = NS_INADDRSZ; | |
1218 | addrsize_out = (v4to6) ? NS_IN6ADDRSZ : NS_INADDRSZ; | |
1219 | type = ns_t_a; | |
1220 | break; | |
1221 | case AF_INET6: | |
1222 | addrsize_in = addrsize_out = NS_IN6ADDRSZ; | |
1223 | type = ns_t_aaaa; | |
1224 | break; | |
1225 | default: | |
1226 | set_errno (EAFNOSUPPORT); | |
1227 | h_errno = NETDB_INTERNAL; | |
1228 | __leave; | |
1229 | } | |
0a20e5a0 | 1230 | |
64f8b4ca CV |
1231 | h_errno = NETDB_SUCCESS; |
1232 | res = gethostby_specials (name, af, addrsize_in, addrsize_out); | |
1233 | if ((res == NULL) && (h_errno == NETDB_SUCCESS)) | |
1234 | res = gethostby_helper (name, af, type, addrsize_in, addrsize_out); | |
3f3bd101 CV |
1235 | } |
1236 | __except (EFAULT) {} | |
1237 | __endtry | |
1238 | return res; | |
6f57cb4a CV |
1239 | } |
1240 | ||
f881942d | 1241 | /* exported as accept: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 1242 | extern "C" int |
78db7dff | 1243 | cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len) |
1fd5e000 | 1244 | { |
3f3bd101 | 1245 | int res = -1; |
0a642325 | 1246 | |
61522196 CV |
1247 | pthread_testcancel (); |
1248 | ||
3f3bd101 CV |
1249 | __try |
1250 | { | |
1251 | fhandler_socket *fh = get (fd); | |
1252 | if (fh) | |
1253 | res = fh->accept4 (peer, len, | |
1254 | fh->is_nonblocking () ? SOCK_NONBLOCK : 0); | |
1255 | } | |
1256 | __except (EFAULT) {} | |
1257 | __endtry | |
b9aa8149 | 1258 | syscall_printf ("%R = accept(%d, %p, %p)", res, fd, peer, len); |
1fd5e000 CF |
1259 | return res; |
1260 | } | |
1261 | ||
f881942d | 1262 | /* accept4: GNU extension */ |
0d653155 CV |
1263 | extern "C" int |
1264 | accept4 (int fd, struct sockaddr *peer, socklen_t *len, int flags) | |
1265 | { | |
3f3bd101 | 1266 | int res = -1; |
0d653155 | 1267 | |
61522196 CV |
1268 | pthread_testcancel (); |
1269 | ||
3f3bd101 | 1270 | __try |
0d653155 | 1271 | { |
3f3bd101 CV |
1272 | fhandler_socket *fh = get (fd); |
1273 | if (!fh) | |
1274 | __leave; | |
1275 | if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) | |
1276 | set_errno (EINVAL); | |
1277 | else | |
1278 | res = fh->accept4 (peer, len, flags); | |
0d653155 | 1279 | } |
3f3bd101 CV |
1280 | __except (EFAULT) {} |
1281 | __endtry | |
61522196 | 1282 | syscall_printf ("%R = accept4(%d, %p, %p, %y)", res, fd, peer, len, flags); |
0d653155 CV |
1283 | return res; |
1284 | } | |
1285 | ||
f881942d | 1286 | /* exported as bind: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 1287 | extern "C" int |
78db7dff | 1288 | cygwin_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen) |
1fd5e000 | 1289 | { |
3f3bd101 | 1290 | int res = -1; |
1fd5e000 | 1291 | |
3f3bd101 CV |
1292 | __try |
1293 | { | |
1294 | fhandler_socket *fh = get (fd); | |
1295 | if (fh) | |
1296 | res = fh->bind (my_addr, addrlen); | |
1297 | } | |
1298 | __except (EFAULT) {} | |
1299 | __endtry | |
b9aa8149 | 1300 | syscall_printf ("%R = bind(%d, %p, %d)", res, fd, my_addr, addrlen); |
1fd5e000 CF |
1301 | return res; |
1302 | } | |
1303 | ||
f881942d | 1304 | /* exported as getsockname: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 1305 | extern "C" int |
78db7dff | 1306 | cygwin_getsockname (int fd, struct sockaddr *addr, socklen_t *namelen) |
1fd5e000 | 1307 | { |
3f3bd101 | 1308 | int res = -1; |
be5007aa | 1309 | |
3f3bd101 CV |
1310 | __try |
1311 | { | |
1312 | fhandler_socket *fh = get (fd); | |
1313 | if (fh) | |
1314 | res = fh->getsockname (addr, namelen); | |
1315 | } | |
1316 | __except (EFAULT) {} | |
1317 | __endtry | |
b9aa8149 | 1318 | syscall_printf ("%R =getsockname (%d, %p, %p)", res, fd, addr, namelen); |
1fd5e000 CF |
1319 | return res; |
1320 | } | |
1321 | ||
f881942d | 1322 | /* exported as listen: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 1323 | extern "C" int |
1fd5e000 CF |
1324 | cygwin_listen (int fd, int backlog) |
1325 | { | |
3f3bd101 | 1326 | int res = -1; |
1fd5e000 | 1327 | |
3f3bd101 CV |
1328 | __try |
1329 | { | |
1330 | fhandler_socket *fh = get (fd); | |
1331 | if (fh) | |
1332 | res = fh->listen (backlog); | |
1333 | } | |
1334 | __except (EFAULT) {} | |
1335 | __endtry | |
b9aa8149 | 1336 | syscall_printf ("%R = listen(%d, %d)", res, fd, backlog); |
1fd5e000 CF |
1337 | return res; |
1338 | } | |
1339 | ||
f881942d | 1340 | /* exported as shutdown: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 1341 | extern "C" int |
1fd5e000 CF |
1342 | cygwin_shutdown (int fd, int how) |
1343 | { | |
3f3bd101 | 1344 | int res = -1; |
0a642325 | 1345 | |
be5007aa | 1346 | fhandler_socket *fh = get (fd); |
3f3bd101 | 1347 | if (fh) |
be5007aa | 1348 | res = fh->shutdown (how); |
b9aa8149 | 1349 | syscall_printf ("%R = shutdown(%d, %d)", res, fd, how); |
1fd5e000 CF |
1350 | return res; |
1351 | } | |
1352 | ||
7d9688b7 CV |
1353 | /* exported as hstrerror: BSD 4.3 */ |
1354 | extern "C" const char * | |
1355 | cygwin_hstrerror (int err) | |
1356 | { | |
1357 | int i; | |
1358 | ||
1359 | for (i = 0; host_errmap[i].e != 0; ++i) | |
1360 | if (err == host_errmap[i].e) | |
1361 | break; | |
1362 | ||
1363 | return host_errmap[i].s; | |
1364 | } | |
1365 | ||
1366 | /* exported as herror: BSD 4.3 */ | |
4e6a4ea8 | 1367 | extern "C" void |
7d9688b7 | 1368 | cygwin_herror (const char *s) |
1fd5e000 | 1369 | { |
3f3bd101 | 1370 | __try |
7d9688b7 | 1371 | { |
3f3bd101 CV |
1372 | if (cygheap->fdtab.not_open (2)) |
1373 | return; | |
7d9688b7 | 1374 | |
3f3bd101 CV |
1375 | if (s) |
1376 | { | |
1377 | write (2, s, strlen (s)); | |
1378 | write (2, ": ", 2); | |
1379 | } | |
7d9688b7 | 1380 | |
3f3bd101 CV |
1381 | const char *h_errstr = cygwin_hstrerror (h_errno); |
1382 | ||
1383 | if (!h_errstr) | |
1384 | switch (h_errno) | |
1385 | { | |
1386 | case NETDB_INTERNAL: | |
1387 | h_errstr = "Resolver internal error"; | |
1388 | break; | |
1389 | case NETDB_SUCCESS: | |
1390 | h_errstr = "Resolver error 0 (no error)"; | |
1391 | break; | |
1392 | default: | |
1393 | h_errstr = "Unknown resolver error"; | |
1394 | break; | |
1395 | } | |
1396 | write (2, h_errstr, strlen (h_errstr)); | |
1397 | write (2, "\n", 1); | |
1398 | } | |
1399 | __except (NO_ERROR) {} | |
1400 | __endtry | |
1fd5e000 CF |
1401 | } |
1402 | ||
f881942d | 1403 | /* exported as getpeername: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
4e6a4ea8 | 1404 | extern "C" int |
78db7dff | 1405 | cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len) |
1fd5e000 | 1406 | { |
3f3bd101 CV |
1407 | int res = -1; |
1408 | fhandler_socket *fh = NULL; | |
5a64d869 | 1409 | |
3f3bd101 CV |
1410 | __try |
1411 | { | |
1412 | fh = get (fd); | |
1413 | if (fh) | |
1414 | res = fh->getpeername (name, len); | |
1415 | } | |
1416 | __except (EFAULT) {} | |
1417 | __endtry | |
b79018ee | 1418 | syscall_printf ("%R = getpeername(%d)", res, fd); |
1fd5e000 CF |
1419 | return res; |
1420 | } | |
1421 | ||
f881942d | 1422 | /* exported as recv: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
61522196 | 1423 | extern "C" ssize_t |
78db7dff | 1424 | cygwin_recv (int fd, void *buf, size_t len, int flags) |
1fd5e000 | 1425 | { |
3f3bd101 | 1426 | ssize_t res = -1; |
61522196 CV |
1427 | |
1428 | pthread_testcancel (); | |
291698e5 | 1429 | |
3f3bd101 CV |
1430 | __try |
1431 | { | |
1432 | fhandler_socket *fh = get (fd); | |
1433 | if (fh) | |
1434 | /* Originally we shortcircuited here if res == 0. | |
1435 | Allow 0 bytes buffer. This is valid in POSIX and handled in | |
1436 | fhandler_socket::recv_internal. If we shortcircuit, we fail | |
1437 | to deliver valid error conditions. */ | |
1438 | res = fh->recvfrom (buf, len, flags, NULL, NULL); | |
1439 | } | |
1440 | __except (EFAULT) {} | |
1441 | __endtry | |
61522196 | 1442 | syscall_printf ("%lR = recv(%d, %p, %ld, %y)", res, fd, buf, len, flags); |
291698e5 | 1443 | return res; |
1fd5e000 CF |
1444 | } |
1445 | ||
f881942d | 1446 | /* exported as send: POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD */ |
61522196 | 1447 | extern "C" ssize_t |
78db7dff | 1448 | cygwin_send (int fd, const void *buf, size_t len, int flags) |
1fd5e000 | 1449 | { |
3f3bd101 | 1450 | ssize_t res = -1; |
61522196 CV |
1451 | |
1452 | pthread_testcancel (); | |
291698e5 | 1453 | |
3f3bd101 CV |
1454 | __try |
1455 | { | |
1456 | fhandler_socket *fh = get (fd); | |
1457 | if (fh) | |
1458 | res = fh->sendto (buf, len, flags, NULL, 0); | |
1459 | } | |
1460 | __except (EFAULT) | |
1461 | __endtry | |
61522196 | 1462 | syscall_printf ("%lR = send(%d, %p, %ld, %y)", res, fd, buf, len, flags); |
291698e5 | 1463 | return res; |
1fd5e000 CF |
1464 | } |
1465 | ||
52b5a971 CV |
1466 | /* Fill out an ifconf struct. */ |
1467 | ||
974163bc CV |
1468 | bool |
1469 | get_adapters_addresses (PIP_ADAPTER_ADDRESSES *pa_ret, ULONG family) | |
bff43891 CV |
1470 | { |
1471 | DWORD ret, size = 0; | |
1472 | PIP_ADAPTER_ADDRESSES pa0 = NULL; | |
1473 | ||
974163bc CV |
1474 | if (!pa_ret) |
1475 | return GetAdaptersAddresses (family, GAA_FLAG_INCLUDE_PREFIX | |
1476 | | GAA_FLAG_INCLUDE_ALL_INTERFACES, | |
3e25449a | 1477 | NULL, NULL, &size); |
bff43891 CV |
1478 | do |
1479 | { | |
974163bc CV |
1480 | ret = GetAdaptersAddresses (family, GAA_FLAG_INCLUDE_PREFIX |
1481 | | GAA_FLAG_INCLUDE_ALL_INTERFACES, | |
bff43891 CV |
1482 | NULL, pa0, &size); |
1483 | if (ret == ERROR_BUFFER_OVERFLOW | |
1484 | && !(pa0 = (PIP_ADAPTER_ADDRESSES) realloc (pa0, size))) | |
1485 | break; | |
1486 | } | |
1487 | while (ret == ERROR_BUFFER_OVERFLOW); | |
3e25449a | 1488 | if (pa0) |
bff43891 | 1489 | { |
3e25449a CV |
1490 | if (ret != ERROR_SUCCESS) |
1491 | { | |
1492 | free (pa0); | |
974163bc | 1493 | *pa_ret = NULL; |
3e25449a CV |
1494 | } |
1495 | else | |
974163bc | 1496 | *pa_ret = pa0; |
3e25449a | 1497 | } |
3e25449a | 1498 | return ret == ERROR_SUCCESS || (!pa_ret && ret == ERROR_BUFFER_OVERFLOW); |
bff43891 CV |
1499 | } |
1500 | ||
34adefae | 1501 | static in_addr_t |
8e4a60b3 CV |
1502 | get_routedst (DWORD if_index) |
1503 | { | |
1504 | PMIB_IPFORWARDTABLE pift; | |
1505 | ULONG size = 0; | |
1506 | if (GetIpForwardTable (NULL, &size, FALSE) == ERROR_INSUFFICIENT_BUFFER | |
1507 | && (pift = (PMIB_IPFORWARDTABLE) alloca (size)) | |
1508 | && GetIpForwardTable (pift, &size, FALSE) == NO_ERROR) | |
1509 | for (DWORD i = 0; i < pift->dwNumEntries; ++i) | |
1510 | { | |
7b44665a | 1511 | if (pift->table[i].dwForwardIfIndex == if_index |
8e4a60b3 CV |
1512 | && pift->table[i].dwForwardMask == INADDR_BROADCAST) |
1513 | return pift->table[i].dwForwardDest; | |
1514 | } | |
1515 | return INADDR_ANY; | |
1516 | } | |
1517 | ||
a71ecb55 CV |
1518 | struct ifall { |
1519 | struct ifaddrs ifa_ifa; | |
1520 | char ifa_name[IFNAMSIZ]; | |
1521 | struct sockaddr_storage ifa_addr; | |
1522 | struct sockaddr_storage ifa_brddstaddr; | |
1523 | struct sockaddr_storage ifa_netmask; | |
65231f41 | 1524 | struct ifaddrs_hwdata ifa_hwdata; |
a71ecb55 CV |
1525 | }; |
1526 | ||
ea392307 CV |
1527 | static unsigned int |
1528 | get_flags (PIP_ADAPTER_ADDRESSES pap) | |
1529 | { | |
1530 | unsigned int flags = IFF_UP; | |
1531 | if (pap->IfType == IF_TYPE_SOFTWARE_LOOPBACK) | |
1532 | flags |= IFF_LOOPBACK; | |
943c59e3 CV |
1533 | else if (pap->IfType == IF_TYPE_PPP |
1534 | || pap->IfType == IF_TYPE_SLIP) | |
1535 | flags |= IFF_POINTOPOINT | IFF_NOARP; | |
ea392307 CV |
1536 | if (!(pap->Flags & IP_ADAPTER_NO_MULTICAST)) |
1537 | flags |= IFF_MULTICAST; | |
1538 | if (pap->OperStatus == IfOperStatusUp | |
1539 | || pap->OperStatus == IfOperStatusUnknown) | |
1540 | flags |= IFF_RUNNING; | |
1541 | if (pap->OperStatus != IfOperStatusLowerLayerDown) | |
1542 | flags |= IFF_LOWER_UP; | |
1543 | if (pap->OperStatus == IfOperStatusDormant) | |
1544 | flags |= IFF_DORMANT; | |
1545 | return flags; | |
1546 | } | |
1547 | ||
1548 | static ULONG | |
1549 | get_ipv4fromreg_ipcnt (const char *name) | |
1550 | { | |
cbc26145 CV |
1551 | WCHAR regkey[256], *c; |
1552 | ||
1553 | c = wcpcpy (regkey, L"Tcpip\\Parameters\\Interfaces\\"); | |
1554 | sys_mbstowcs (c, 220, name); | |
1555 | if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_SERVICES, regkey))) | |
1556 | return 0; | |
1557 | ||
ea392307 | 1558 | ULONG ifs = 1; |
cbc26145 CV |
1559 | DWORD dhcp = 0; |
1560 | UNICODE_STRING uipa = { 0, 0, NULL }; | |
1561 | RTL_QUERY_REGISTRY_TABLE tab[3] = { | |
1562 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING, | |
1563 | L"EnableDHCP", &dhcp, REG_NONE, NULL, 0 }, | |
1564 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, | |
1565 | L"IPAddress", &uipa, REG_NONE, NULL, 0 }, | |
1566 | { NULL, 0, NULL, NULL, 0, NULL, 0 } | |
1567 | }; | |
ea392307 | 1568 | |
ea392307 | 1569 | /* If DHCP is used, we have only one address. */ |
cbc26145 CV |
1570 | if (NT_SUCCESS (RtlQueryRegistryValues (RTL_REGISTRY_SERVICES, regkey, tab, |
1571 | NULL, NULL)) | |
1572 | && uipa.Buffer) | |
ea392307 | 1573 | { |
cbc26145 CV |
1574 | if (dhcp == 0) |
1575 | for (ifs = 0, c = uipa.Buffer; *c; c += wcslen (c) + 1) | |
ea392307 | 1576 | ifs++; |
cbc26145 | 1577 | RtlFreeUnicodeString (&uipa); |
ea392307 | 1578 | } |
ea392307 CV |
1579 | return ifs; |
1580 | } | |
1581 | ||
1582 | static void | |
1583 | get_ipv4fromreg (struct ifall *ifp, const char *name, DWORD idx) | |
1584 | { | |
cbc26145 | 1585 | WCHAR regkey[256], *c; |
b88d686a | 1586 | bool got_addr = false, got_mask = false; |
cbc26145 CV |
1587 | |
1588 | c = wcpcpy (regkey, L"Tcpip\\Parameters\\Interfaces\\"); | |
1589 | sys_mbstowcs (c, 220, name); | |
1590 | if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_SERVICES, regkey))) | |
1591 | return; | |
1592 | ||
1593 | ULONG ifs; | |
1594 | DWORD dhcp = 0; | |
1595 | UNICODE_STRING udipa = { 0, 0, NULL }; | |
1596 | UNICODE_STRING udsub = { 0, 0, NULL }; | |
1597 | UNICODE_STRING uipa = { 0, 0, NULL }; | |
1598 | UNICODE_STRING usub = { 0, 0, NULL }; | |
1599 | RTL_QUERY_REGISTRY_TABLE tab[6] = { | |
1600 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING, | |
1601 | L"EnableDHCP", &dhcp, REG_NONE, NULL, 0 }, | |
1602 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, | |
1603 | L"DhcpIPAddress", &udipa, REG_NONE, NULL, 0 }, | |
1604 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, | |
1605 | L"DhcpSubnetMask", &udsub, REG_NONE, NULL, 0 }, | |
1606 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, | |
1607 | L"IPAddress", &uipa, REG_NONE, NULL, 0 }, | |
1608 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, | |
1609 | L"SubnetMask", &usub, REG_NONE, NULL, 0 }, | |
1610 | { NULL, 0, NULL, NULL, 0, NULL, 0 } | |
1611 | }; | |
1612 | ||
1613 | if (NT_SUCCESS (RtlQueryRegistryValues (RTL_REGISTRY_SERVICES, regkey, tab, | |
1614 | NULL, NULL))) | |
ea392307 | 1615 | { |
cbc26145 CV |
1616 | # define addr ((struct sockaddr_in *) &ifp->ifa_addr) |
1617 | # define mask ((struct sockaddr_in *) &ifp->ifa_netmask) | |
1618 | # define brdc ((struct sockaddr_in *) &ifp->ifa_brddstaddr) | |
1619 | # define inet_uton(u, a) \ | |
1620 | { \ | |
1621 | char t[64]; \ | |
1622 | sys_wcstombs (t, 64, (u)); \ | |
dff3bc9a | 1623 | cygwin_inet_pton (AF_INET, t, (a)); \ |
cbc26145 CV |
1624 | } |
1625 | /* If DHCP is used, we have only one address. */ | |
ea392307 CV |
1626 | if (dhcp) |
1627 | { | |
cbc26145 | 1628 | if (udipa.Buffer) |
b88d686a KB |
1629 | { |
1630 | inet_uton (udipa.Buffer, &addr->sin_addr); | |
1631 | got_addr = true; | |
1632 | } | |
cbc26145 | 1633 | if (udsub.Buffer) |
b88d686a KB |
1634 | { |
1635 | inet_uton (udsub.Buffer, &mask->sin_addr); | |
1636 | got_mask = true; | |
1637 | } | |
ea392307 CV |
1638 | } |
1639 | else | |
1640 | { | |
cbc26145 | 1641 | if (uipa.Buffer) |
ea392307 | 1642 | { |
cbc26145 CV |
1643 | for (ifs = 0, c = uipa.Buffer; *c && ifs < idx; |
1644 | c += wcslen (c) + 1) | |
ea392307 CV |
1645 | ifs++; |
1646 | if (*c) | |
b88d686a KB |
1647 | { |
1648 | inet_uton (c, &addr->sin_addr); | |
1649 | got_addr = true; | |
1650 | } | |
ea392307 | 1651 | } |
cbc26145 | 1652 | if (usub.Buffer) |
ea392307 | 1653 | { |
cbc26145 CV |
1654 | for (ifs = 0, c = usub.Buffer; *c && ifs < idx; |
1655 | c += wcslen (c) + 1) | |
ea392307 CV |
1656 | ifs++; |
1657 | if (*c) | |
b88d686a KB |
1658 | { |
1659 | inet_uton (c, &mask->sin_addr); | |
1660 | got_mask = true; | |
1661 | } | |
ea392307 CV |
1662 | } |
1663 | } | |
b88d686a KB |
1664 | if (got_addr) |
1665 | ifp->ifa_ifa.ifa_addr = (struct sockaddr *) addr; | |
1666 | if (got_mask) | |
1667 | ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) mask; | |
ea392307 CV |
1668 | if (ifp->ifa_ifa.ifa_flags & IFF_BROADCAST) |
1669 | brdc->sin_addr.s_addr = (addr->sin_addr.s_addr | |
1670 | & mask->sin_addr.s_addr) | |
1671 | | ~mask->sin_addr.s_addr; | |
1672 | #undef addr | |
1673 | #undef mask | |
1674 | #undef brdc | |
cbc26145 CV |
1675 | #undef inet_uton |
1676 | if (udipa.Buffer) | |
1677 | RtlFreeUnicodeString (&udipa); | |
1678 | if (udsub.Buffer) | |
1679 | RtlFreeUnicodeString (&udsub); | |
1680 | if (uipa.Buffer) | |
1681 | RtlFreeUnicodeString (&uipa); | |
1682 | if (usub.Buffer) | |
1683 | RtlFreeUnicodeString (&usub); | |
ea392307 | 1684 | } |
ea392307 CV |
1685 | } |
1686 | ||
1687 | static void | |
1688 | get_friendlyname (struct ifall *ifp, PIP_ADAPTER_ADDRESSES pap) | |
1689 | { | |
1690 | struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *) | |
65231f41 | 1691 | &ifp->ifa_hwdata.ifa_frndlyname; |
ea392307 CV |
1692 | iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname, |
1693 | IFRF_FRIENDLYNAMESIZ, | |
ef750173 | 1694 | pap->FriendlyName) + 1; |
ea392307 CV |
1695 | } |
1696 | ||
1697 | static void | |
1698 | get_hwaddr (struct ifall *ifp, PIP_ADAPTER_ADDRESSES pap) | |
1699 | { | |
1700 | for (UINT i = 0; i < IFHWADDRLEN; ++i) | |
1701 | if (i >= pap->PhysicalAddressLength) | |
65231f41 | 1702 | ifp->ifa_hwdata.ifa_hwaddr.sa_data[i] = '\0'; |
ea392307 | 1703 | else |
65231f41 | 1704 | ifp->ifa_hwdata.ifa_hwaddr.sa_data[i] = pap->PhysicalAddress[i]; |
ea392307 | 1705 | } |
61522196 | 1706 | |
bff43891 | 1707 | /* |
61522196 | 1708 | * Get network interfaces. Use IP Helper function GetAdaptersAddresses. |
bff43891 | 1709 | */ |
a71ecb55 | 1710 | static struct ifall * |
61522196 | 1711 | get_ifs (ULONG family) |
bff43891 CV |
1712 | { |
1713 | PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; | |
1714 | PIP_ADAPTER_UNICAST_ADDRESS pua; | |
bff43891 | 1715 | int cnt = 0; |
a71ecb55 CV |
1716 | struct ifall *ifret = NULL, *ifp; |
1717 | struct sockaddr_in *if_sin; | |
1718 | struct sockaddr_in6 *if_sin6; | |
bff43891 | 1719 | |
a71ecb55 | 1720 | if (!get_adapters_addresses (&pa0, family)) |
bff43891 | 1721 | goto done; |
510a85cb | 1722 | |
bff43891 | 1723 | for (pap = pa0; pap; pap = pap->Next) |
ea392307 CV |
1724 | if (!pap->FirstUnicastAddress) |
1725 | { | |
1726 | /* FirstUnicastAddress is NULL for interfaces which are disconnected. | |
d3920e10 | 1727 | Fetch number of configured IPv4 addresses from registry and |
ea392307 CV |
1728 | store in an unused member of the adapter addresses structure. */ |
1729 | pap->Ipv6IfIndex = get_ipv4fromreg_ipcnt (pap->AdapterName); | |
1730 | cnt += pap->Ipv6IfIndex; | |
1731 | } | |
1732 | else for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next) | |
bff43891 | 1733 | ++cnt; |
510a85cb | 1734 | |
a71ecb55 CV |
1735 | if (!(ifret = (struct ifall *) calloc (cnt, sizeof (struct ifall)))) |
1736 | goto done; | |
1737 | ifp = ifret; | |
1738 | ||
bff43891 CV |
1739 | for (pap = pa0; pap; pap = pap->Next) |
1740 | { | |
ea392307 CV |
1741 | DWORD idx = 0; |
1742 | if (!pap->FirstUnicastAddress) | |
1743 | for (idx = 0; idx < pap->Ipv6IfIndex; ++idx) | |
1744 | { | |
1745 | /* Next in chain */ | |
1746 | ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa; | |
1747 | /* Interface name */ | |
ba763af5 | 1748 | |
fee7b24b | 1749 | if (idx) |
ea392307 CV |
1750 | __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx); |
1751 | else | |
1752 | strcpy (ifp->ifa_name, pap->AdapterName); | |
1753 | ifp->ifa_ifa.ifa_name = ifp->ifa_name; | |
1754 | /* Flags */ | |
1755 | ifp->ifa_ifa.ifa_flags = get_flags (pap); | |
943c59e3 CV |
1756 | if (pap->IfType != IF_TYPE_PPP |
1757 | && pap->IfType != IF_TYPE_SOFTWARE_LOOPBACK) | |
ea392307 CV |
1758 | ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST; |
1759 | /* Address */ | |
1760 | ifp->ifa_addr.ss_family = AF_INET; | |
b88d686a | 1761 | ifp->ifa_ifa.ifa_addr = NULL; |
ea392307 CV |
1762 | /* Broadcast/Destination address */ |
1763 | ifp->ifa_brddstaddr.ss_family = AF_INET; | |
1764 | ifp->ifa_ifa.ifa_dstaddr = NULL; | |
1765 | /* Netmask */ | |
1766 | ifp->ifa_netmask.ss_family = AF_INET; | |
b88d686a | 1767 | ifp->ifa_ifa.ifa_netmask = NULL; |
ea392307 CV |
1768 | /* Try to fetch real IPv4 address information from registry. */ |
1769 | get_ipv4fromreg (ifp, pap->AdapterName, idx); | |
1770 | /* Hardware address */ | |
1771 | get_hwaddr (ifp, pap); | |
1772 | /* Metric */ | |
65231f41 | 1773 | ifp->ifa_hwdata.ifa_metric = 1; |
ea392307 | 1774 | /* MTU */ |
65231f41 | 1775 | ifp->ifa_hwdata.ifa_mtu = pap->Mtu; |
ea392307 | 1776 | /* Interface index */ |
65231f41 | 1777 | ifp->ifa_hwdata.ifa_ifindex = pap->IfIndex; |
ea392307 CV |
1778 | /* Friendly name */ |
1779 | get_friendlyname (ifp, pap); | |
65231f41 CV |
1780 | /* Let ifa_data member point to "ifaddrs_hwdata" data. */ |
1781 | ifp->ifa_ifa.ifa_data = &ifp->ifa_hwdata; | |
ea392307 CV |
1782 | ++ifp; |
1783 | } | |
1784 | else | |
bdcc0b84 | 1785 | for (idx = 0, pua = pap->FirstUnicastAddress; pua; pua = pua->Next) |
ea392307 CV |
1786 | { |
1787 | struct sockaddr *sa = (struct sockaddr *) pua->Address.lpSockaddr; | |
a71ecb55 CV |
1788 | # define sin ((struct sockaddr_in *) sa) |
1789 | # define sin6 ((struct sockaddr_in6 *) sa) | |
ea392307 CV |
1790 | size_t sa_size = (sa->sa_family == AF_INET6 |
1791 | ? sizeof *sin6 : sizeof *sin); | |
1792 | /* Next in chain */ | |
1793 | ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa; | |
1794 | /* Interface name */ | |
fee7b24b | 1795 | if (sa->sa_family == AF_INET && idx) |
ea392307 | 1796 | __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx); |
a71ecb55 | 1797 | else |
ea392307 | 1798 | strcpy (ifp->ifa_name, pap->AdapterName); |
bdcc0b84 CV |
1799 | if (sa->sa_family == AF_INET) |
1800 | ++idx; | |
ea392307 CV |
1801 | ifp->ifa_ifa.ifa_name = ifp->ifa_name; |
1802 | /* Flags */ | |
1803 | ifp->ifa_ifa.ifa_flags = get_flags (pap); | |
1804 | if (sa->sa_family == AF_INET | |
1805 | && pap->IfType != IF_TYPE_SOFTWARE_LOOPBACK | |
1806 | && pap->IfType != IF_TYPE_PPP) | |
1807 | ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST; | |
ea392307 CV |
1808 | /* Address */ |
1809 | memcpy (&ifp->ifa_addr, sa, sa_size); | |
1810 | ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr; | |
1811 | /* Netmask */ | |
a7595584 | 1812 | int prefix = pua->OnLinkPrefixLength; |
ea392307 CV |
1813 | switch (sa->sa_family) |
1814 | { | |
1815 | case AF_INET: | |
1816 | if_sin = (struct sockaddr_in *) &ifp->ifa_netmask; | |
1817 | if_sin->sin_addr.s_addr = htonl (UINT32_MAX << (32 - prefix)); | |
1818 | if_sin->sin_family = AF_INET; | |
1819 | break; | |
1820 | case AF_INET6: | |
1821 | if_sin6 = (struct sockaddr_in6 *) &ifp->ifa_netmask; | |
e0f53cfe CV |
1822 | for (cnt = 0; cnt < 4 && prefix > 0; ++cnt, prefix -= 32) |
1823 | { | |
1824 | if_sin6->sin6_addr.s6_addr32[cnt] = UINT32_MAX; | |
1825 | if (prefix < 32) | |
1826 | if_sin6->sin6_addr.s6_addr32[cnt] <<= 32 - prefix; | |
1827 | } | |
c08ee10d | 1828 | if_sin6->sin6_family = AF_INET6; |
ea392307 CV |
1829 | break; |
1830 | } | |
1831 | ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask; | |
1832 | if (pap->IfType == IF_TYPE_PPP) | |
1833 | { | |
1834 | /* Destination address */ | |
1835 | if (sa->sa_family == AF_INET) | |
1836 | { | |
1837 | if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr; | |
1838 | if_sin->sin_addr.s_addr = get_routedst (pap->IfIndex); | |
1839 | if_sin->sin_family = AF_INET; | |
1840 | } | |
1841 | else | |
1842 | /* FIXME: No official way to get the dstaddr for ipv6? */ | |
1843 | memcpy (&ifp->ifa_addr, sa, sa_size); | |
1844 | ifp->ifa_ifa.ifa_dstaddr = (struct sockaddr *) | |
1845 | &ifp->ifa_brddstaddr; | |
1846 | } | |
1847 | else | |
1848 | { | |
1849 | /* Broadcast address */ | |
1850 | if (sa->sa_family == AF_INET) | |
1851 | { | |
1852 | if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr; | |
1853 | uint32_t mask = | |
1854 | ((struct sockaddr_in *) &ifp->ifa_netmask)->sin_addr.s_addr; | |
1855 | if_sin->sin_addr.s_addr = (sin->sin_addr.s_addr & mask) | |
1856 | | ~mask; | |
1857 | if_sin->sin_family = AF_INET; | |
1858 | ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *) | |
1859 | &ifp->ifa_brddstaddr; | |
1860 | } | |
1861 | else /* No IPv6 broadcast */ | |
1862 | ifp->ifa_ifa.ifa_broadaddr = NULL; | |
1863 | } | |
1864 | /* Hardware address */ | |
1865 | get_hwaddr (ifp, pap); | |
1866 | /* Metric */ | |
a7595584 CV |
1867 | ifp->ifa_hwdata.ifa_metric = (sa->sa_family == AF_INET |
1868 | ? pap->Ipv4Metric : pap->Ipv6Metric); | |
ea392307 | 1869 | /* MTU */ |
65231f41 | 1870 | ifp->ifa_hwdata.ifa_mtu = pap->Mtu; |
ea392307 | 1871 | /* Interface index */ |
65231f41 | 1872 | ifp->ifa_hwdata.ifa_ifindex = pap->IfIndex; |
ea392307 CV |
1873 | /* Friendly name */ |
1874 | get_friendlyname (ifp, pap); | |
65231f41 CV |
1875 | /* Let ifa_data member point to "ifaddrs_hwdata" data. */ |
1876 | ifp->ifa_ifa.ifa_data = &ifp->ifa_hwdata; | |
ea392307 | 1877 | ++ifp; |
a71ecb55 CV |
1878 | # undef sin |
1879 | # undef sin6 | |
ea392307 | 1880 | } |
bff43891 | 1881 | } |
a71ecb55 CV |
1882 | /* Since every entry is set to the next entry, the last entry points to an |
1883 | invalid next entry now. Fix it retroactively. */ | |
1884 | if (ifp > ifret) | |
1885 | ifp[-1].ifa_ifa.ifa_next = NULL; | |
bff43891 CV |
1886 | |
1887 | done: | |
1888 | if (pa0) | |
1889 | free (pa0); | |
a71ecb55 | 1890 | return ifret; |
bff43891 CV |
1891 | } |
1892 | ||
a71ecb55 CV |
1893 | extern "C" int |
1894 | getifaddrs (struct ifaddrs **ifap) | |
1895 | { | |
1896 | if (!ifap) | |
1897 | { | |
1898 | set_errno (EINVAL); | |
1899 | return -1; | |
1900 | } | |
1901 | struct ifall *ifp; | |
61522196 | 1902 | ifp = get_ifs (AF_UNSPEC); |
a71ecb55 CV |
1903 | *ifap = &ifp->ifa_ifa; |
1904 | return ifp ? 0 : -1; | |
7326d4e4 | 1905 | } |
1fd5e000 | 1906 | |
a71ecb55 CV |
1907 | extern "C" void |
1908 | freeifaddrs (struct ifaddrs *ifp) | |
7326d4e4 | 1909 | { |
a71ecb55 CV |
1910 | if (ifp) |
1911 | free (ifp); | |
1912 | } | |
1fd5e000 | 1913 | |
a71ecb55 CV |
1914 | int |
1915 | get_ifconf (struct ifconf *ifc, int what) | |
1916 | { | |
3f3bd101 | 1917 | __try |
7326d4e4 | 1918 | { |
3f3bd101 CV |
1919 | /* Ensure we have space for at least one struct ifreqs, fail if not. */ |
1920 | if (ifc->ifc_len < (int) sizeof (struct ifreq)) | |
1921 | { | |
1922 | set_errno (EINVAL); | |
1923 | __leave; | |
1924 | } | |
1fd5e000 | 1925 | |
3f3bd101 CV |
1926 | struct ifall *ifret, *ifp; |
1927 | ifret = get_ifs (AF_INET); | |
1928 | if (!ifret) | |
1929 | __leave; | |
a71ecb55 | 1930 | |
3f3bd101 CV |
1931 | struct sockaddr_in *sin; |
1932 | struct ifreq *ifr = ifc->ifc_req; | |
1933 | int cnt = 0; | |
1934 | for (ifp = ifret; ifp; ifp = (struct ifall *) ifp->ifa_ifa.ifa_next) | |
7b44665a | 1935 | { |
3f3bd101 CV |
1936 | ++cnt; |
1937 | strcpy (ifr->ifr_name, ifp->ifa_name); | |
1938 | switch (what) | |
a71ecb55 | 1939 | { |
3f3bd101 CV |
1940 | case SIOCGIFFLAGS: |
1941 | ifr->ifr_flags = ifp->ifa_ifa.ifa_flags; | |
1942 | break; | |
1943 | case SIOCGIFCONF: | |
1944 | case SIOCGIFADDR: | |
1945 | sin = (struct sockaddr_in *) &ifr->ifr_addr; | |
1946 | memcpy (sin, &ifp->ifa_addr, sizeof *sin); | |
1947 | break; | |
1948 | case SIOCGIFNETMASK: | |
1949 | sin = (struct sockaddr_in *) &ifr->ifr_netmask; | |
1950 | memcpy (sin, &ifp->ifa_netmask, sizeof *sin); | |
1951 | break; | |
1952 | case SIOCGIFDSTADDR: | |
1953 | sin = (struct sockaddr_in *) &ifr->ifr_dstaddr; | |
1954 | if (ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT) | |
1955 | memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); | |
1956 | else /* Return addr as on Linux. */ | |
1957 | memcpy (sin, &ifp->ifa_addr, sizeof *sin); | |
1958 | break; | |
1959 | case SIOCGIFBRDADDR: | |
1960 | sin = (struct sockaddr_in *) &ifr->ifr_broadaddr; | |
1961 | if (!(ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT)) | |
1962 | memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); | |
1963 | else | |
1964 | { | |
1965 | sin->sin_addr.s_addr = INADDR_ANY; | |
1966 | sin->sin_family = AF_INET; | |
1967 | sin->sin_port = 0; | |
1968 | } | |
1969 | break; | |
1970 | case SIOCGIFHWADDR: | |
65231f41 | 1971 | memcpy (&ifr->ifr_hwaddr, &ifp->ifa_hwdata.ifa_hwaddr, |
3f3bd101 CV |
1972 | sizeof ifr->ifr_hwaddr); |
1973 | break; | |
1974 | case SIOCGIFMETRIC: | |
65231f41 | 1975 | ifr->ifr_metric = ifp->ifa_hwdata.ifa_metric; |
3f3bd101 CV |
1976 | break; |
1977 | case SIOCGIFMTU: | |
65231f41 | 1978 | ifr->ifr_mtu = ifp->ifa_hwdata.ifa_mtu; |
3f3bd101 CV |
1979 | break; |
1980 | case SIOCGIFINDEX: | |
65231f41 | 1981 | ifr->ifr_ifindex = ifp->ifa_hwdata.ifa_ifindex; |
3f3bd101 CV |
1982 | break; |
1983 | case SIOCGIFFRNDLYNAM: | |
65231f41 | 1984 | memcpy (ifr->ifr_frndlyname, &ifp->ifa_hwdata.ifa_frndlyname, |
3f3bd101 | 1985 | sizeof (struct ifreq_frndlyname)); |
a71ecb55 | 1986 | } |
3f3bd101 CV |
1987 | if ((caddr_t) ++ifr > |
1988 | ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) | |
1989 | break; | |
bcdf7421 | 1990 | } |
3f3bd101 CV |
1991 | /* Set the correct length */ |
1992 | ifc->ifc_len = cnt * sizeof (struct ifreq); | |
1993 | free (ifret); | |
1994 | return 0; | |
1fd5e000 | 1995 | } |
3f3bd101 CV |
1996 | __except (EFAULT) {} |
1997 | __endtry | |
1998 | return -1; | |
1fd5e000 CF |
1999 | } |
2000 | ||
bff43891 | 2001 | extern "C" unsigned |
c356901f | 2002 | cygwin_if_nametoindex (const char *name) |
bff43891 | 2003 | { |
b91d38db TY |
2004 | PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; |
2005 | if (get_adapters_addresses (&pa0, AF_UNSPEC)) | |
2006 | for (pap = pa0; pap; pap = pap->Next) | |
2007 | if (strcmp (name, pap->AdapterName) == 0) | |
2008 | { | |
2009 | free (pa0); | |
2010 | return pap->IfIndex; | |
2011 | } | |
2012 | if (pa0) | |
2013 | free (pa0); | |
2014 | return 0; | |
bff43891 CV |
2015 | } |
2016 | ||
2017 | extern "C" char * | |
c356901f | 2018 | cygwin_if_indextoname (unsigned ifindex, char *ifname) |
bff43891 | 2019 | { |
b91d38db TY |
2020 | if (ifindex == 0 || ifname == NULL) |
2021 | { | |
2022 | set_errno (ENXIO); | |
2023 | return NULL; | |
2024 | } | |
2025 | PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; | |
2026 | if (get_adapters_addresses (&pa0, AF_UNSPEC)) | |
2027 | for (pap = pa0; pap; pap = pap->Next) | |
2028 | if (ifindex == pap->IfIndex) | |
2029 | { | |
2030 | strcpy (ifname, pap->AdapterName); | |
2031 | free (pa0); | |
2032 | return ifname; | |
2033 | } | |
2034 | if (pa0) | |
2035 | free (pa0); | |
2036 | set_errno (ENXIO); | |
2037 | return NULL; | |
bff43891 CV |
2038 | } |
2039 | ||
2040 | extern "C" struct if_nameindex * | |
2041 | if_nameindex (void) | |
2042 | { | |
2043 | PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; | |
2044 | struct if_nameindex *iflist = NULL; | |
2045 | char (*ifnamelist)[IF_NAMESIZE]; | |
2046 | ||
3f3bd101 | 2047 | __try |
bff43891 | 2048 | { |
3f3bd101 | 2049 | if (get_adapters_addresses (&pa0, AF_UNSPEC)) |
510a85cb | 2050 | { |
3f3bd101 CV |
2051 | int cnt = 0; |
2052 | for (pap = pa0; pap; pap = pap->Next) | |
2053 | ++cnt; | |
2054 | iflist = (struct if_nameindex *) | |
2055 | malloc ((cnt + 1) * sizeof (struct if_nameindex) | |
2056 | + cnt * IF_NAMESIZE); | |
2057 | if (!iflist) | |
2058 | set_errno (ENOBUFS); | |
2059 | else | |
4b13fd15 | 2060 | { |
3f3bd101 CV |
2061 | ifnamelist = (char (*)[IF_NAMESIZE]) (iflist + cnt + 1); |
2062 | for (pap = pa0, cnt = 0; pap; pap = pap->Next) | |
2063 | { | |
2064 | for (int i = 0; i < cnt; ++i) | |
2065 | if (iflist[i].if_index | |
2066 | == (pap->Ipv6IfIndex ?: pap->IfIndex)) | |
2067 | goto outer_loop; | |
2068 | iflist[cnt].if_index = pap->Ipv6IfIndex ?: pap->IfIndex; | |
2069 | strcpy (iflist[cnt].if_name = ifnamelist[cnt], | |
2070 | pap->AdapterName); | |
2071 | /* See comment in if_indextoname. */ | |
2072 | if (pap->IfIndex == 1 && pap->Ipv6IfIndex == 0) | |
2073 | for (PIP_ADAPTER_ADDRESSES pap2 = pa0; | |
2074 | pap2; | |
2075 | pap2 = pap2->Next) | |
2076 | if (pap2->Ipv6IfIndex == 1) | |
2077 | { | |
2078 | strcpy (ifnamelist[cnt], pap2->AdapterName); | |
2079 | break; | |
2080 | } | |
2081 | ++cnt; | |
2082 | outer_loop: | |
2083 | ; | |
2084 | } | |
2085 | iflist[cnt].if_index = 0; | |
2086 | iflist[cnt].if_name = NULL; | |
4b13fd15 | 2087 | } |
3f3bd101 | 2088 | free (pa0); |
bff43891 | 2089 | } |
3f3bd101 CV |
2090 | else |
2091 | set_errno (ENXIO); | |
bff43891 | 2092 | } |
3f3bd101 CV |
2093 | __except (EFAULT) {} |
2094 | __endtry | |
4b13fd15 | 2095 | return iflist; |
bff43891 CV |
2096 | } |
2097 | ||
2098 | extern "C" void | |
2099 | if_freenameindex (struct if_nameindex *ptr) | |
2100 | { | |
bff43891 CV |
2101 | free (ptr); |
2102 | } | |
2103 | ||
06a5dd43 CV |
2104 | #define PORT_LOW (IPPORT_EFSSERVER + 1) |
2105 | #define PORT_HIGH (IPPORT_RESERVED - 1) | |
2106 | #define NUM_PORTS (PORT_HIGH - PORT_LOW + 1) | |
2107 | ||
e9ff2d69 CV |
2108 | /* port is in host byte order */ |
2109 | static in_port_t | |
2110 | next_free_port (sa_family_t family, in_port_t in_port) | |
2111 | { | |
2112 | DWORD ret; | |
2113 | ULONG size = 0; | |
2114 | char *tab = NULL; | |
2115 | PMIB_TCPTABLE tab4 = NULL; | |
2116 | PMIB_TCP6TABLE tab6 = NULL; | |
2117 | ||
2118 | /* Start testing with incoming port number. */ | |
2119 | in_port_t tst_port = in_port; | |
2120 | in_port_t res_port = 0; | |
2121 | in_port_t tab_port; | |
2122 | ||
2123 | do | |
2124 | { | |
2125 | if (family == AF_INET) | |
2126 | ret = GetTcpTable ((PMIB_TCPTABLE) tab, &size, TRUE); | |
2127 | else | |
2128 | ret = GetTcp6Table ((PMIB_TCP6TABLE) tab, &size, TRUE); | |
2129 | ||
2130 | if (ret == ERROR_INSUFFICIENT_BUFFER) | |
2131 | tab = (char *) realloc (tab, size); | |
2132 | } | |
2133 | while (ret == ERROR_INSUFFICIENT_BUFFER); | |
2134 | ||
2135 | tab4 = (PMIB_TCPTABLE) tab; | |
2136 | tab6 = (PMIB_TCP6TABLE) tab; | |
2137 | ||
2138 | /* dwNumEntries has offset 0 in both structs. */ | |
2139 | for (int idx = tab4->dwNumEntries - 1; idx >= 0; --idx) | |
2140 | { | |
2141 | if (family == AF_INET) | |
2142 | tab_port = ntohs (tab4->table[idx].dwLocalPort); | |
2143 | else | |
2144 | tab_port = ntohs (tab6->table[idx].dwLocalPort); | |
2145 | /* Skip table entries with too high port number. */ | |
2146 | if (tab_port > tst_port) | |
2147 | continue; | |
2148 | /* Is the current port number free? */ | |
2149 | if (tab_port < tst_port) | |
2150 | { | |
2151 | res_port = tst_port; | |
2152 | break; | |
2153 | } | |
2154 | /* Decrement port and handle underflow of the reserved area. */ | |
2155 | if (--tst_port < PORT_LOW) | |
2156 | { | |
2157 | tst_port = PORT_HIGH; | |
2158 | idx = tab4->dwNumEntries; | |
2159 | } | |
2160 | /* Check if we're round to the incoming port. */ | |
2161 | if (tst_port == in_port) | |
2162 | break; | |
2163 | } | |
2164 | free (tab); | |
2165 | return res_port; | |
2166 | } | |
2167 | ||
4e6a4ea8 | 2168 | extern "C" int |
70e476d2 | 2169 | cygwin_bindresvport_sa (int fd, struct sockaddr *sa) |
1fd5e000 | 2170 | { |
70e476d2 CV |
2171 | struct sockaddr_storage sst; |
2172 | struct sockaddr_in *sin = NULL; | |
2173 | struct sockaddr_in6 *sin6 = NULL; | |
70e476d2 | 2174 | socklen_t salen; |
3f3bd101 | 2175 | int ret = -1; |
e9ff2d69 | 2176 | LONG port, next_port; |
70e476d2 | 2177 | |
3f3bd101 | 2178 | __try |
06a5dd43 | 2179 | { |
3f3bd101 CV |
2180 | fhandler_socket *fh = get (fd); |
2181 | if (!fh) | |
2182 | __leave; | |
06a5dd43 | 2183 | |
3f3bd101 CV |
2184 | if (!sa) |
2185 | { | |
2186 | sa = (struct sockaddr *) &sst; | |
2187 | memset (&sst, 0, sizeof sst); | |
2188 | sa->sa_family = fh->get_addr_family (); | |
2189 | } | |
2f61f656 CV |
2190 | else if (sa->sa_family != fh->get_addr_family ()) |
2191 | { | |
2192 | set_errno (EPFNOSUPPORT); | |
2193 | __leave; | |
2194 | } | |
79224853 | 2195 | |
3f3bd101 CV |
2196 | switch (sa->sa_family) |
2197 | { | |
2198 | case AF_INET: | |
2199 | salen = sizeof (struct sockaddr_in); | |
2200 | sin = (struct sockaddr_in *) sa; | |
3f3bd101 CV |
2201 | break; |
2202 | case AF_INET6: | |
2203 | salen = sizeof (struct sockaddr_in6); | |
2204 | sin6 = (struct sockaddr_in6 *) sa; | |
3f3bd101 CV |
2205 | break; |
2206 | default: | |
2207 | set_errno (EPFNOSUPPORT); | |
2208 | __leave; | |
2209 | } | |
df63bd49 | 2210 | |
34f03198 CV |
2211 | /* Originally we tried to use the incoming port number first here, |
2212 | but that may lead to EADDRINUSE scenarios when calling bindresvport | |
2213 | on the client side. So we ignore any port value that the caller | |
2214 | supplies, just like glibc. */ | |
70e476d2 | 2215 | |
e9ff2d69 CV |
2216 | /* Note that repeating this loop NUM_PORTS times is arbitrary. The |
2217 | job is mainly done by next_free_port() but it doesn't cover bound | |
2218 | sockets. And calling and checking GetTcpTable and subsequently | |
2219 | calling bind is inevitably racy. We have to continue if bind fails | |
2220 | with EADDRINUSE. */ | |
3f3bd101 CV |
2221 | for (int i = 0; i < NUM_PORTS; i++) |
2222 | { | |
e9ff2d69 | 2223 | while ((port = InterlockedExchange ( |
3f3bd101 CV |
2224 | &cygwin_shared->last_used_bindresvport, -1)) == -1) |
2225 | yield (); | |
e9ff2d69 CV |
2226 | next_port = port; |
2227 | if (next_port == 0 || --next_port < PORT_LOW) | |
2228 | next_port = PORT_HIGH; | |
2229 | /* Returns 0 if no reserved port is free. */ | |
2230 | next_port = next_free_port (sa->sa_family, next_port); | |
2231 | if (next_port) | |
2232 | port = next_port; | |
2233 | InterlockedExchange (&cygwin_shared->last_used_bindresvport, port); | |
2234 | if (next_port == 0) | |
2235 | { | |
2236 | set_errno (EADDRINUSE); | |
2237 | break; | |
2238 | } | |
3f3bd101 | 2239 | if (sa->sa_family == AF_INET6) |
e9ff2d69 | 2240 | sin6->sin6_port = htons (port); |
3f3bd101 | 2241 | else |
e9ff2d69 | 2242 | sin->sin_port = htons (port); |
3f3bd101 CV |
2243 | if (!(ret = fh->bind (sa, salen))) |
2244 | break; | |
2245 | if (get_errno () != EADDRINUSE && get_errno () != EINVAL) | |
2246 | break; | |
2247 | } | |
df63bd49 | 2248 | |
3f3bd101 CV |
2249 | } |
2250 | __except (EFAULT) {} | |
2251 | __endtry | |
70e476d2 CV |
2252 | return ret; |
2253 | } | |
2254 | ||
2255 | extern "C" int | |
2256 | cygwin_bindresvport (int fd, struct sockaddr_in *sin) | |
2257 | { | |
2f61f656 CV |
2258 | if (sin && sin->sin_family != AF_INET) |
2259 | { | |
2260 | set_errno (EAFNOSUPPORT); | |
2261 | return -1; | |
2262 | } | |
70e476d2 | 2263 | return cygwin_bindresvport_sa (fd, (struct sockaddr *) sin); |
1fd5e000 CF |
2264 | } |
2265 | ||
4e04751f | 2266 | /* socketpair: POSIX.1-2001, POSIX.1-2008, 4.4BSD. */ |
4e6a4ea8 | 2267 | extern "C" int |
f4a1a186 | 2268 | socketpair (int af, int type, int protocol, int sv[2]) |
1fd5e000 CF |
2269 | { |
2270 | int res = -1; | |
4e04751f | 2271 | const device *dev; |
1e5e44a9 | 2272 | fhandler_socket *fh_in, *fh_out; |
1fd5e000 | 2273 | |
4e04751f CV |
2274 | int flags = type & _SOCK_FLAG_MASK; |
2275 | type &= ~_SOCK_FLAG_MASK; | |
dc63cea5 | 2276 | |
4e04751f | 2277 | debug_printf ("socket (%d, %d (flags %y), %d)", af, type, flags, protocol); |
1fd5e000 | 2278 | |
4e04751f CV |
2279 | switch (af) |
2280 | { | |
2281 | case AF_LOCAL: | |
6c55be9d CV |
2282 | #ifndef __WITH_AF_UNIX |
2283 | dev = af_local_dev; | |
2284 | #else | |
7f7532fa | 2285 | case AF_UNIX: |
7f7532fa | 2286 | dev = (af == AF_LOCAL) ? af_local_dev : af_unix_dev; |
6c55be9d | 2287 | #endif /* __WITH_AF_UNIX */ |
4e04751f | 2288 | break; |
4e04751f CV |
2289 | default: |
2290 | set_errno (EAFNOSUPPORT); | |
2291 | goto done; | |
2292 | } | |
3f3bd101 | 2293 | |
4e04751f CV |
2294 | if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) |
2295 | { | |
2296 | set_errno (EINVAL); | |
2297 | goto done; | |
2298 | } | |
1fd5e000 | 2299 | |
4e04751f CV |
2300 | { |
2301 | cygheap_fdnew fd_in; | |
2302 | if (fd_in < 0) | |
2303 | goto done; | |
518f5d49 | 2304 | |
4e04751f CV |
2305 | cygheap_fdnew fd_out (fd_in, false); |
2306 | if (fd_out < 0) | |
2bbe8697 | 2307 | goto done; |
518f5d49 | 2308 | |
1e5e44a9 CV |
2309 | fh_in = reinterpret_cast<fhandler_socket *> (build_fh_dev (*dev)); |
2310 | fh_out = reinterpret_cast<fhandler_socket *> (build_fh_dev (*dev)); | |
4e04751f CV |
2311 | if (fh_in && fh_out |
2312 | && fh_in->socketpair (af, type, protocol, flags, fh_out) == 0) | |
3f3bd101 | 2313 | { |
4e04751f CV |
2314 | fd_in = fh_in; |
2315 | fd_out = fh_out; | |
2316 | if (fd_in <= 2) | |
2317 | set_std_handle (fd_in); | |
2318 | if (fd_out <= 2) | |
2319 | set_std_handle (fd_out); | |
2320 | __try | |
3f3bd101 | 2321 | { |
f4a1a186 CV |
2322 | sv[0] = fd_in; |
2323 | sv[1] = fd_out; | |
4e04751f | 2324 | res = 0; |
3f3bd101 | 2325 | } |
4e04751f CV |
2326 | __except (EFAULT) {} |
2327 | __endtry | |
3f3bd101 | 2328 | } |
3f3bd101 | 2329 | else |
3f3bd101 | 2330 | { |
b995936a CV |
2331 | delete fh_in; |
2332 | delete fh_out; | |
3f3bd101 CV |
2333 | } |
2334 | } | |
4e04751f CV |
2335 | |
2336 | done: | |
3f3bd101 | 2337 | syscall_printf ("%R = socketpair(...)", res); |
1fd5e000 CF |
2338 | return res; |
2339 | } | |
2340 | ||
f881942d | 2341 | /* sethostent: POSIX.1-2001 */ |
dd4f0b23 CV |
2342 | extern "C" void |
2343 | sethostent (int) | |
2344 | { | |
2345 | } | |
2346 | ||
f881942d | 2347 | /* endhostent: POSIX.1-2001 */ |
dd4f0b23 CV |
2348 | extern "C" void |
2349 | endhostent (void) | |
2350 | { | |
2351 | } | |
7d6be0d6 | 2352 | |
f881942d | 2353 | /* exported as recvmsg: POSIX.1-2001, POSIX.1-2008, 4.4BSD */ |
61522196 | 2354 | extern "C" ssize_t |
b4f06520 | 2355 | cygwin_recvmsg (int fd, struct msghdr *msg, int flags) |
be5007aa | 2356 | { |
3f3bd101 | 2357 | ssize_t res = -1; |
61522196 CV |
2358 | |
2359 | pthread_testcancel (); | |
0a642325 | 2360 | |
3f3bd101 | 2361 | __try |
4d147a03 | 2362 | { |
3f3bd101 CV |
2363 | fhandler_socket *fh = get (fd); |
2364 | if (fh) | |
2365 | { | |
2366 | res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen); | |
2367 | /* Originally we shortcircuited here if res == 0. | |
2368 | Allow 0 bytes buffer. This is valid in POSIX and handled in | |
2369 | fhandler_socket::recv_internal. If we shortcircuit, we fail | |
2370 | to deliver valid error conditions and peer address. */ | |
2371 | if (res >= 0) | |
2372 | res = fh->recvmsg (msg, flags); | |
2373 | } | |
4d147a03 | 2374 | } |
3f3bd101 CV |
2375 | __except (EFAULT) |
2376 | { | |
2377 | res = -1; | |
2378 | } | |
2379 | __endtry | |
61522196 | 2380 | syscall_printf ("%lR = recvmsg(%d, %p, %y)", res, fd, msg, flags); |
b4f06520 | 2381 | return res; |
7d6be0d6 CV |
2382 | } |
2383 | ||
f881942d | 2384 | /* exported as sendmsg: POSIX.1-2001, POSIX.1-2008, 4.4BSD */ |
61522196 | 2385 | extern "C" ssize_t |
b4f06520 | 2386 | cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) |
be5007aa | 2387 | { |
3f3bd101 | 2388 | ssize_t res = -1; |
61522196 CV |
2389 | |
2390 | pthread_testcancel (); | |
4d147a03 | 2391 | |
3f3bd101 | 2392 | __try |
4d147a03 | 2393 | { |
3f3bd101 CV |
2394 | fhandler_socket *fh = get (fd); |
2395 | if (fh) | |
2396 | { | |
2397 | res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen); | |
2398 | if (res >= 0) | |
2399 | res = fh->sendmsg (msg, flags); | |
2400 | } | |
4d147a03 | 2401 | } |
3f3bd101 CV |
2402 | __except (EFAULT) |
2403 | { | |
2404 | res = -1; | |
2405 | } | |
2406 | __endtry | |
61522196 | 2407 | syscall_printf ("%lR = sendmsg(%d, %p, %y)", res, fd, msg, flags); |
b4f06520 | 2408 | return res; |
1c657740 | 2409 | } |
b3ba5059 | 2410 | |
70e476d2 CV |
2411 | /* This is from the BIND 4.9.4 release, modified to compile by itself */ |
2412 | ||
2413 | /* Copyright (c) 1996 by Internet Software Consortium. | |
2414 | * | |
2415 | * Permission to use, copy, modify, and distribute this software for any | |
2416 | * purpose with or without fee is hereby granted, provided that the above | |
2417 | * copyright notice and this permission notice appear in all copies. | |
2418 | * | |
2419 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | |
2420 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
2421 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | |
2422 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
2423 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
2424 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
2425 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
2426 | * SOFTWARE. | |
2427 | */ | |
2428 | ||
70e476d2 CV |
2429 | /* int |
2430 | * inet_pton4(src, dst) | |
2431 | * like inet_aton() but without all the hexadecimal and shorthand. | |
2432 | * return: | |
2433 | * 1 if `src' is a valid dotted quad, else 0. | |
2434 | * notice: | |
2435 | * does not touch `dst' unless it's returning 1. | |
2436 | * author: | |
2437 | * Paul Vixie, 1996. | |
2438 | */ | |
2439 | static int | |
acc5f02c | 2440 | inet_pton4 (const char *src, u_int8_t *dst) |
70e476d2 CV |
2441 | { |
2442 | static const char digits[] = "0123456789"; | |
2443 | int saw_digit, octets, ch; | |
acc5f02c | 2444 | u_int8_t tmp[INADDRSZ], *tp; |
70e476d2 CV |
2445 | |
2446 | saw_digit = 0; | |
2447 | octets = 0; | |
2448 | *(tp = tmp) = 0; | |
2449 | while ((ch = *src++) != '\0') | |
2450 | { | |
2451 | const char *pch; | |
2452 | ||
2453 | if ((pch = strchr(digits, ch)) != NULL) | |
510a85cb | 2454 | { |
acc5f02c | 2455 | u_int32_t ret = *tp * 10 + (pch - digits); |
70e476d2 CV |
2456 | |
2457 | if (ret > 255) | |
2458 | return (0); | |
2459 | *tp = ret; | |
2460 | if (! saw_digit) | |
2461 | { | |
2462 | if (++octets > 4) | |
2463 | return (0); | |
2464 | saw_digit = 1; | |
2465 | } | |
2466 | } | |
2467 | else if (ch == '.' && saw_digit) | |
510a85cb | 2468 | { |
70e476d2 CV |
2469 | if (octets == 4) |
2470 | return (0); | |
2471 | *++tp = 0; | |
2472 | saw_digit = 0; | |
2473 | } | |
2474 | else | |
2475 | return (0); | |
2476 | } | |
2477 | if (octets < 4) | |
2478 | return (0); | |
2479 | ||
2480 | memcpy(dst, tmp, INADDRSZ); | |
2481 | return (1); | |
2482 | } | |
2483 | ||
2484 | /* int | |
2485 | * inet_pton6(src, dst) | |
2486 | * convert presentation level address to network order binary form. | |
2487 | * return: | |
2488 | * 1 if `src' is a valid [RFC1884 2.2] address, else 0. | |
2489 | * notice: | |
2490 | * (1) does not touch `dst' unless it's returning 1. | |
2491 | * (2) :: in a full address is silently ignored. | |
2492 | * credit: | |
2493 | * inspired by Mark Andrews. | |
2494 | * author: | |
2495 | * Paul Vixie, 1996. | |
2496 | */ | |
2497 | static int | |
acc5f02c | 2498 | inet_pton6 (const char *src, u_int8_t *dst) |
70e476d2 CV |
2499 | { |
2500 | static const char xdigits_l[] = "0123456789abcdef", | |
2501 | xdigits_u[] = "0123456789ABCDEF"; | |
acc5f02c | 2502 | u_int8_t tmp[IN6ADDRSZ], *tp, *endp, *colonp; |
70e476d2 CV |
2503 | const char *xdigits, *curtok; |
2504 | int ch, saw_xdigit; | |
acc5f02c | 2505 | u_int32_t val; |
70e476d2 CV |
2506 | |
2507 | memset((tp = tmp), 0, IN6ADDRSZ); | |
2508 | endp = tp + IN6ADDRSZ; | |
2509 | colonp = NULL; | |
2510 | /* Leading :: requires some special handling. */ | |
2511 | if (*src == ':') | |
2512 | if (*++src != ':') | |
2513 | return (0); | |
2514 | curtok = src; | |
2515 | saw_xdigit = 0; | |
2516 | val = 0; | |
2517 | while ((ch = *src++) != '\0') | |
2518 | { | |
2519 | const char *pch; | |
2520 | ||
2521 | if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) | |
2522 | pch = strchr((xdigits = xdigits_u), ch); | |
2523 | if (pch != NULL) | |
510a85cb | 2524 | { |
70e476d2 CV |
2525 | val <<= 4; |
2526 | val |= (pch - xdigits); | |
2527 | if (val > 0xffff) | |
2528 | return (0); | |
2529 | saw_xdigit = 1; | |
2530 | continue; | |
2531 | } | |
2532 | if (ch == ':') | |
510a85cb | 2533 | { |
70e476d2 CV |
2534 | curtok = src; |
2535 | if (!saw_xdigit) | |
2536 | { | |
2537 | if (colonp) | |
2538 | return (0); | |
2539 | colonp = tp; | |
2540 | continue; | |
2541 | } | |
2542 | if (tp + INT16SZ > endp) | |
2543 | return (0); | |
acc5f02c CV |
2544 | *tp++ = (u_int8_t) (val >> 8) & 0xff; |
2545 | *tp++ = (u_int8_t) val & 0xff; | |
70e476d2 CV |
2546 | saw_xdigit = 0; |
2547 | val = 0; | |
2548 | continue; | |
2549 | } | |
2550 | if (ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) | |
510a85cb | 2551 | { |
70e476d2 CV |
2552 | tp += INADDRSZ; |
2553 | saw_xdigit = 0; | |
2554 | break; /* '\0' was seen by inet_pton4(). */ | |
2555 | } | |
2556 | return (0); | |
2557 | } | |
2558 | if (saw_xdigit) | |
2559 | { | |
2560 | if (tp + INT16SZ > endp) | |
2561 | return (0); | |
acc5f02c CV |
2562 | *tp++ = (u_int8_t) (val >> 8) & 0xff; |
2563 | *tp++ = (u_int8_t) val & 0xff; | |
70e476d2 CV |
2564 | } |
2565 | if (colonp != NULL) | |
2566 | { | |
2567 | /* | |
2568 | * Since some memmove()'s erroneously fail to handle | |
2569 | * overlapping regions, we'll do the shift by hand. | |
2570 | */ | |
2571 | const int n = tp - colonp; | |
2572 | int i; | |
2573 | ||
2574 | for (i = 1; i <= n; i++) | |
510a85cb | 2575 | { |
70e476d2 CV |
2576 | endp[- i] = colonp[n - i]; |
2577 | colonp[n - i] = 0; | |
2578 | } | |
2579 | tp = endp; | |
2580 | } | |
2581 | if (tp != endp) | |
2582 | return (0); | |
2583 | ||
2584 | memcpy(dst, tmp, IN6ADDRSZ); | |
2585 | return (1); | |
2586 | } | |
2587 | ||
2588 | /* int | |
2589 | * inet_pton(af, src, dst) | |
2590 | * convert from presentation format (which usually means ASCII printable) | |
2591 | * to network format (which is usually some kind of binary format). | |
2592 | * return: | |
2593 | * 1 if the address was valid for the specified address family | |
2594 | * 0 if the address wasn't valid (`dst' is untouched in this case) | |
2595 | * -1 if some other error occurred (`dst' is untouched in this case, too) | |
2596 | * author: | |
2597 | * Paul Vixie, 1996. | |
2598 | */ | |
b3ba5059 | 2599 | extern "C" int |
70e476d2 | 2600 | cygwin_inet_pton (int af, const char *src, void *dst) |
b3ba5059 | 2601 | { |
70e476d2 | 2602 | switch (af) |
b3ba5059 | 2603 | { |
70e476d2 | 2604 | case AF_INET: |
acc5f02c | 2605 | return (inet_pton4(src, (u_int8_t *) dst)); |
70e476d2 | 2606 | case AF_INET6: |
acc5f02c | 2607 | return (inet_pton6(src, (u_int8_t *) dst)); |
70e476d2 CV |
2608 | default: |
2609 | errno = EAFNOSUPPORT; | |
2610 | return (-1); | |
2611 | } | |
2612 | /* NOTREACHED */ | |
2613 | } | |
2614 | ||
2615 | /* const char * | |
2616 | * inet_ntop4(src, dst, size) | |
2617 | * format an IPv4 address, more or less like inet_ntoa() | |
2618 | * return: | |
2619 | * `dst' (as a const) | |
2620 | * notes: | |
2621 | * (1) uses no statics | |
acc5f02c | 2622 | * (2) takes a u_int8_t* not an in_addr as input |
70e476d2 CV |
2623 | * author: |
2624 | * Paul Vixie, 1996. | |
2625 | */ | |
2626 | static const char * | |
acc5f02c | 2627 | inet_ntop4 (const u_int8_t *src, char *dst, size_t size) |
70e476d2 CV |
2628 | { |
2629 | static const char fmt[] = "%u.%u.%u.%u"; | |
2630 | char tmp[sizeof "255.255.255.255"]; | |
2631 | ||
2632 | __small_sprintf(tmp, fmt, src[0], src[1], src[2], src[3]); | |
2633 | if (strlen(tmp) > size) | |
2634 | { | |
2635 | errno = ENOSPC; | |
2636 | return (NULL); | |
2637 | } | |
2638 | strcpy(dst, tmp); | |
2639 | return (dst); | |
2640 | } | |
2641 | ||
2642 | /* const char * | |
2643 | * inet_ntop6(src, dst, size) | |
2644 | * convert IPv6 binary address into presentation (printable) format | |
2645 | * author: | |
2646 | * Paul Vixie, 1996. | |
2647 | */ | |
2648 | static const char * | |
acc5f02c | 2649 | inet_ntop6 (const u_int8_t *src, char *dst, size_t size) |
70e476d2 CV |
2650 | { |
2651 | /* | |
2652 | * Note that int32_t and int16_t need only be "at least" large enough | |
2653 | * to contain a value of the specified size. On some systems, like | |
2654 | * Crays, there is no such thing as an integer variable with 16 bits. | |
2655 | * Keep this in mind if you think this function should have been coded | |
2656 | * to use pointer overlays. All the world's not a VAX. | |
2657 | */ | |
2658 | char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; | |
2659 | struct { int base, len; } best, cur; | |
acc5f02c | 2660 | u_int32_t words[IN6ADDRSZ / INT16SZ]; |
70e476d2 | 2661 | int i; |
b3ba5059 | 2662 | |
70e476d2 CV |
2663 | /* |
2664 | * Preprocess: | |
2665 | * Copy the input (bytewise) array into a wordwise array. | |
2666 | * Find the longest run of 0x00's in src[] for :: shorthanding. | |
2667 | */ | |
2668 | memset(words, 0, sizeof words); | |
2669 | for (i = 0; i < IN6ADDRSZ; i++) | |
2670 | words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); | |
2671 | best.base = -1; | |
2672 | cur.base = -1; | |
1809b65e CF |
2673 | best.len = 0; |
2674 | cur.len = 0; | |
70e476d2 CV |
2675 | for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) |
2676 | { | |
2677 | if (words[i] == 0) | |
510a85cb | 2678 | { |
70e476d2 CV |
2679 | if (cur.base == -1) |
2680 | cur.base = i, cur.len = 1; | |
2681 | else | |
2682 | cur.len++; | |
2683 | } | |
2684 | else | |
510a85cb | 2685 | { |
70e476d2 CV |
2686 | if (cur.base != -1) |
2687 | { | |
2688 | if (best.base == -1 || cur.len > best.len) | |
2689 | best = cur; | |
2690 | cur.base = -1; | |
2691 | } | |
2692 | } | |
2693 | } | |
2694 | if (cur.base != -1) | |
2695 | { | |
2696 | if (best.base == -1 || cur.len > best.len) | |
2697 | best = cur; | |
2698 | } | |
2699 | if (best.base != -1 && best.len < 2) | |
2700 | best.base = -1; | |
2701 | ||
2702 | /* | |
2703 | * Format the result. | |
2704 | */ | |
2705 | tp = tmp; | |
2706 | for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) | |
2707 | { | |
2708 | /* Are we inside the best run of 0x00's? */ | |
2709 | if (best.base != -1 && i >= best.base && i < (best.base + best.len)) | |
510a85cb | 2710 | { |
70e476d2 CV |
2711 | if (i == best.base) |
2712 | *tp++ = ':'; | |
2713 | continue; | |
2714 | } | |
2715 | /* Are we following an initial run of 0x00s or any real hex? */ | |
2716 | if (i != 0) | |
2717 | *tp++ = ':'; | |
2718 | /* Is this address an encapsulated IPv4? */ | |
2719 | if (i == 6 && best.base == 0 && | |
2720 | (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) | |
1cd06583 | 2721 | { |
70e476d2 CV |
2722 | if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) |
2723 | return (NULL); | |
2724 | tp += strlen(tp); | |
2725 | break; | |
b3ba5059 | 2726 | } |
70e476d2 | 2727 | __small_sprintf(tp, "%x", words[i]); |
6f0c3cc8 CV |
2728 | while (*tp) |
2729 | { | |
2730 | if (isupper (*tp)) | |
2731 | *tp = _tolower (*tp); | |
2732 | ++tp; | |
2733 | } | |
b3ba5059 | 2734 | } |
70e476d2 CV |
2735 | /* Was it a trailing run of 0x00's? */ |
2736 | if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) | |
2737 | *tp++ = ':'; | |
2738 | *tp++ = '\0'; | |
2739 | ||
2740 | /* | |
2741 | * Check for overflow, copy, and we're done. | |
2742 | */ | |
2743 | if ((size_t) (tp - tmp) > size) | |
2744 | { | |
2745 | errno = ENOSPC; | |
2746 | return (NULL); | |
2747 | } | |
2748 | strcpy(dst, tmp); | |
2749 | return (dst); | |
b3ba5059 CV |
2750 | } |
2751 | ||
70e476d2 CV |
2752 | /* char * |
2753 | * inet_ntop(af, src, dst, size) | |
2754 | * convert a network format address to presentation format. | |
2755 | * return: | |
2756 | * pointer to presentation format address (`dst'), or NULL (see errno). | |
2757 | * author: | |
2758 | * Paul Vixie, 1996. | |
2759 | */ | |
b3ba5059 | 2760 | extern "C" const char * |
70e476d2 | 2761 | cygwin_inet_ntop (int af, const void *src, char *dst, socklen_t size) |
b3ba5059 | 2762 | { |
70e476d2 CV |
2763 | switch (af) |
2764 | { | |
2765 | case AF_INET: | |
acc5f02c | 2766 | return (inet_ntop4((const u_int8_t *) src, dst, size)); |
70e476d2 | 2767 | case AF_INET6: |
acc5f02c | 2768 | return (inet_ntop6((const u_int8_t *) src, dst, size)); |
70e476d2 CV |
2769 | default: |
2770 | errno = EAFNOSUPPORT; | |
2771 | return (NULL); | |
2772 | } | |
2773 | /* NOTREACHED */ | |
2774 | } | |
b3ba5059 | 2775 | |
f881942d | 2776 | /* Exported as freeaddrinfo: POSIX.1-2001, POSIX.1-2008, RFC 2553 */ |
5b56e9b0 CV |
2777 | extern "C" void |
2778 | cygwin_freeaddrinfo (struct addrinfo *addr) | |
70e476d2 | 2779 | { |
5b56e9b0 | 2780 | struct addrinfo *ai, *ainext; |
70e476d2 | 2781 | |
5b56e9b0 | 2782 | for (ai = addr; ai != NULL; ai = ainext) |
70e476d2 | 2783 | { |
5b56e9b0 CV |
2784 | if (ai->ai_addr != NULL) |
2785 | free (ai->ai_addr); /* socket address structure */ | |
70e476d2 | 2786 | |
5b56e9b0 CV |
2787 | if (ai->ai_canonname != NULL) |
2788 | free (ai->ai_canonname); | |
2789 | ||
2790 | ainext = ai->ai_next; /* can't fetch ai_next after free() */ | |
2791 | free (ai); /* the addrinfo{} itself */ | |
70e476d2 | 2792 | } |
70e476d2 CV |
2793 | } |
2794 | ||
70e476d2 | 2795 | static struct addrinfo * |
5b56e9b0 | 2796 | ga_dup (struct addrinfoW *ai, bool v4mapped, int idn_flags, int &err) |
70e476d2 CV |
2797 | { |
2798 | struct addrinfo *nai; | |
2799 | ||
2800 | if ((nai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL) | |
5b56e9b0 CV |
2801 | { |
2802 | err = EAI_MEMORY; | |
2803 | return NULL; | |
2804 | } | |
70e476d2 | 2805 | |
4815dd49 | 2806 | nai->ai_family = v4mapped ? AF_INET6 : ai->ai_family; |
70e476d2 CV |
2807 | nai->ai_socktype = ai->ai_socktype; |
2808 | nai->ai_protocol = ai->ai_protocol; | |
5b56e9b0 | 2809 | if (ai->ai_canonname) |
4815dd49 | 2810 | { |
5b56e9b0 CV |
2811 | tmp_pathbuf tp; |
2812 | wchar_t *canonname = ai->ai_canonname; | |
2813 | ||
2814 | if (idn_flags & AI_CANONIDN) | |
2815 | { | |
2816 | /* Map flags to equivalent IDN_* flags. */ | |
2817 | wchar_t *canonbuf = tp.w_get (); | |
2818 | if (IdnToUnicode (idn_flags >> 16, canonname, -1, | |
2819 | canonbuf, NT_MAX_PATH)) | |
2820 | canonname = canonbuf; | |
2821 | else if (GetLastError () != ERROR_PROC_NOT_FOUND) | |
2822 | { | |
2823 | free (nai); | |
2824 | err = EAI_IDN_ENCODE; | |
2825 | return NULL; | |
2826 | } | |
2827 | } | |
2828 | size_t len = wcstombs (NULL, canonname, 0); | |
2829 | if (len == (size_t) -1) | |
2830 | { | |
2831 | free (nai); | |
2832 | err = EAI_IDN_ENCODE; | |
2833 | return NULL; | |
2834 | } | |
2835 | nai->ai_canonname = (char *) malloc (len + 1); | |
2836 | if (!nai->ai_canonname) | |
2837 | { | |
2838 | free (nai); | |
2839 | err = EAI_MEMORY; | |
2840 | return NULL; | |
2841 | } | |
2842 | wcstombs (nai->ai_canonname, canonname, len + 1); | |
4815dd49 | 2843 | } |
3bb346d5 | 2844 | |
4815dd49 CV |
2845 | nai->ai_addrlen = v4mapped ? sizeof (struct sockaddr_in6) : ai->ai_addrlen; |
2846 | if ((nai->ai_addr = (struct sockaddr *) malloc (v4mapped | |
510a85cb | 2847 | ? sizeof (struct sockaddr_in6) |
4815dd49 CV |
2848 | : ai->ai_addrlen)) == NULL) |
2849 | { | |
2850 | if (nai->ai_canonname) | |
510a85cb | 2851 | free (nai->ai_canonname); |
4815dd49 | 2852 | free (nai); |
5b56e9b0 | 2853 | err = EAI_MEMORY; |
4815dd49 CV |
2854 | return NULL; |
2855 | } | |
2856 | if (v4mapped) | |
2857 | { | |
2858 | struct sockaddr_in6 *in = (struct sockaddr_in6 *) nai->ai_addr; | |
2859 | in->sin6_family = AF_INET6; | |
2860 | in->sin6_port = ((struct sockaddr_in *) ai->ai_addr)->sin_port; | |
2861 | in->sin6_flowinfo = 0; | |
2862 | in->sin6_addr.s6_addr32[0] = 0; | |
2863 | in->sin6_addr.s6_addr32[1] = 0; | |
2864 | in->sin6_addr.s6_addr32[2] = htonl (0xffff); | |
2865 | in->sin6_addr.s6_addr32[3] = ((struct sockaddr_in *) ai->ai_addr)->sin_addr.s_addr; | |
2866 | in->sin6_scope_id = 0; | |
2867 | } | |
2868 | else | |
2869 | memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen); | |
2870 | ||
2871 | return nai; | |
2872 | } | |
2873 | ||
2874 | static struct addrinfo * | |
5b56e9b0 | 2875 | ga_duplist (struct addrinfoW *ai, bool v4mapped, int idn_flags, int &err) |
4815dd49 | 2876 | { |
4815dd49 CV |
2877 | struct addrinfo *tmp, *nai = NULL, *nai0 = NULL; |
2878 | ||
582c7f96 CV |
2879 | for (; ai; ai = ai->ai_next) |
2880 | { | |
2881 | /* Workaround for a Windows weirdness. If a service is supported as | |
2882 | TCP and UDP service, GetAddrInfo does not return two entries, one | |
2883 | for TCP, one for UDP, as on Linux. Rather, it just returns a single | |
2884 | entry with ai_socktype and ai_protocol set to 0, kind of like a | |
2885 | placeholder. If the service only exists as TCP or UDP service, then | |
2886 | ai->ai_socktype is set, but ai_protocol isn't. Fix up the fields, | |
2887 | and in case ai_socktype and ai_protocol are 0 duplicate the entry | |
2888 | with valid values for ai_socktype and ai_protocol. */ | |
2889 | switch (ai->ai_socktype) | |
2890 | { | |
2891 | case SOCK_STREAM: | |
2892 | if (ai->ai_protocol == 0) | |
2893 | ai->ai_protocol = IPPROTO_TCP; | |
2894 | break; | |
2895 | case SOCK_DGRAM: | |
2896 | if (ai->ai_protocol == 0) | |
2897 | ai->ai_protocol = IPPROTO_UDP; | |
2898 | break; | |
2899 | case 0: | |
2900 | switch (ai->ai_protocol) | |
2901 | { | |
2902 | case IPPROTO_TCP: | |
2903 | ai->ai_socktype = SOCK_STREAM; | |
2904 | break; | |
2905 | case IPPROTO_UDP: | |
2906 | ai->ai_socktype = SOCK_DGRAM; | |
2907 | break; | |
2908 | case 0: | |
2909 | ai->ai_socktype = SOCK_STREAM; | |
2910 | ai->ai_protocol = IPPROTO_TCP; | |
2911 | if (!(tmp = ga_dup (ai, v4mapped, idn_flags, err))) | |
2912 | goto bad; | |
2913 | if (!nai0) | |
2914 | nai0 = tmp; | |
2915 | if (nai) | |
2916 | nai->ai_next = tmp; | |
2917 | nai = tmp; | |
2918 | ai->ai_socktype = SOCK_DGRAM; | |
2919 | ai->ai_protocol = IPPROTO_UDP; | |
2920 | break; | |
2921 | default: | |
2922 | break; | |
2923 | } | |
2924 | break; | |
2925 | default: | |
2926 | break; | |
2927 | } | |
5b56e9b0 | 2928 | if (!(tmp = ga_dup (ai, v4mapped, idn_flags, err))) |
510a85cb | 2929 | goto bad; |
4815dd49 | 2930 | if (!nai0) |
510a85cb | 2931 | nai0 = tmp; |
4815dd49 | 2932 | if (nai) |
510a85cb | 2933 | nai->ai_next = tmp; |
582c7f96 | 2934 | nai = tmp; |
4815dd49 CV |
2935 | } |
2936 | return nai0; | |
2937 | ||
2938 | bad: | |
5b56e9b0 | 2939 | cygwin_freeaddrinfo (nai0); |
4815dd49 | 2940 | return NULL; |
70e476d2 CV |
2941 | } |
2942 | ||
5b56e9b0 | 2943 | /* Cygwin specific wrappers around the gai functions. */ |
8053ccd4 | 2944 | static const struct gai_errmap_t |
70e476d2 CV |
2945 | { |
2946 | int w32_errval; | |
2947 | const char *errtxt; | |
5b56e9b0 | 2948 | } gai_errmap[] = |
70e476d2 | 2949 | { |
f28f68cc | 2950 | {0, "Success"}, |
5b56e9b0 | 2951 | /* EAI_ADDRFAMILY */ |
f28f68cc | 2952 | {0, "Address family for hostname not supported"}, |
5b56e9b0 | 2953 | /* EAI_AGAIN */ |
f28f68cc | 2954 | {WSATRY_AGAIN, "Temporary failure in name resolution"}, |
5b56e9b0 CV |
2955 | /* EAI_BADFLAGS */ |
2956 | {WSAEINVAL, "Bad value for ai_flags"}, | |
2957 | /* EAI_FAIL */ | |
f28f68cc | 2958 | {WSANO_RECOVERY, "Non-recoverable failure in name resolution"}, |
5b56e9b0 | 2959 | /* EAI_FAMILY */ |
f28f68cc | 2960 | {WSAEAFNOSUPPORT, "ai_family not supported"}, |
5b56e9b0 | 2961 | /* EAI_MEMORY */ |
70e476d2 | 2962 | {WSA_NOT_ENOUGH_MEMORY, "Memory allocation failure"}, |
5b56e9b0 | 2963 | /* EAI_NODATA */ |
f28f68cc | 2964 | {WSANO_DATA, "No address associated with hostname"}, |
5b56e9b0 CV |
2965 | /* EAI_NONAME */ |
2966 | {WSAHOST_NOT_FOUND, "Name or service not known"}, | |
2967 | /* EAI_SERVICE */ | |
2968 | {WSATYPE_NOT_FOUND, "Servname not supported for ai_socktype"}, | |
2969 | /* EAI_SOCKTYPE */ | |
f28f68cc | 2970 | {WSAESOCKTNOSUPPORT, "ai_socktype not supported"}, |
5b56e9b0 CV |
2971 | /* EAI_SYSTEM */ |
2972 | {0, "System error"}, | |
2973 | /* EAI_BADHINTS */ | |
2974 | {0, "Invalid value for hints"}, | |
2975 | /* EAI_PROTOCOL */ | |
f28f68cc | 2976 | {0, "Resolved protocol is unknown"}, |
5b56e9b0 CV |
2977 | /* EAI_OVERFLOW */ |
2978 | {WSAEFAULT, "An argument buffer overflowed"}, | |
2979 | /* EAI_IDN_ENCODE */ | |
2980 | {0, "Parameter string not correctly encoded"} | |
70e476d2 CV |
2981 | }; |
2982 | ||
f881942d | 2983 | /* Exported as gai_strerror: POSIX.1-2001, POSIX.1-2008 */ |
70e476d2 CV |
2984 | extern "C" const char * |
2985 | cygwin_gai_strerror (int err) | |
2986 | { | |
f28f68cc | 2987 | if (err >= 0 && err < (int) (sizeof gai_errmap / sizeof *gai_errmap)) |
70e476d2 CV |
2988 | return gai_errmap[err].errtxt; |
2989 | return "Unknown error"; | |
2990 | } | |
2991 | ||
2992 | static int | |
2993 | w32_to_gai_err (int w32_err) | |
2994 | { | |
2995 | if (w32_err >= WSABASEERR) | |
f28f68cc | 2996 | for (unsigned i = 0; i < sizeof gai_errmap / sizeof *gai_errmap; ++i) |
70e476d2 CV |
2997 | if (gai_errmap[i].w32_errval == w32_err) |
2998 | return i; | |
2999 | return w32_err; | |
3000 | } | |
3001 | ||
f881942d | 3002 | /* Exported as getaddrinfo: POSIX.1-2001, POSIX.1-2008, RFC 2553 */ |
70e476d2 CV |
3003 | extern "C" int |
3004 | cygwin_getaddrinfo (const char *hostname, const char *servname, | |
3005 | const struct addrinfo *hints, struct addrinfo **res) | |
3006 | { | |
3f3bd101 CV |
3007 | int ret = 0; |
3008 | ||
5b56e9b0 | 3009 | /* Windows' getaddrinfo implementations lets all possible values |
b74bc883 | 3010 | in ai_flags slip through and just ignores unknown values. So we |
5b56e9b0 CV |
3011 | check manually here. */ |
3012 | #define AI_IDN_MASK (AI_IDN | \ | |
3013 | AI_CANONIDN | \ | |
3014 | AI_IDN_ALLOW_UNASSIGNED | \ | |
3015 | AI_IDN_USE_STD3_ASCII_RULES) | |
3016 | #ifndef AI_DISABLE_IDN_ENCODING | |
3017 | #define AI_DISABLE_IDN_ENCODING 0x80000 | |
3018 | #endif | |
3f3bd101 CV |
3019 | __try |
3020 | { | |
3021 | if (hints && (hints->ai_flags | |
3022 | & ~(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_ALL | |
3023 | | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED | |
3024 | | AI_IDN_MASK))) | |
3025 | return EAI_BADFLAGS; | |
00e9bf2b CV |
3026 | /* AI_NUMERICSERV is not supported "by Microsoft providers". We just |
3027 | check the servname parameter by ourselves here. */ | |
3f3bd101 | 3028 | if (hints && (hints->ai_flags & AI_NUMERICSERV)) |
5b56e9b0 | 3029 | { |
3f3bd101 CV |
3030 | char *p; |
3031 | if (servname && *servname && (strtoul (servname, &p, 10), *p)) | |
3032 | return EAI_NONAME; | |
3033 | } | |
3034 | ||
3035 | int idn_flags = hints ? (hints->ai_flags & AI_IDN_MASK) : 0; | |
3036 | const char *src; | |
3037 | mbstate_t ps; | |
3038 | tmp_pathbuf tp; | |
3039 | wchar_t *whost = NULL, *wserv = NULL; | |
3040 | struct addrinfoW whints, *wres; | |
3041 | ||
3042 | if (hostname) | |
3043 | { | |
3044 | memset (&ps, 0, sizeof ps); | |
3045 | src = hostname; | |
3046 | whost = tp.w_get (); | |
3047 | if (mbsrtowcs (whost, &src, NT_MAX_PATH, &ps) == (size_t) -1) | |
5b56e9b0 | 3048 | return EAI_IDN_ENCODE; |
3f3bd101 CV |
3049 | if (src) |
3050 | return EAI_MEMORY; | |
3051 | if (idn_flags & AI_IDN) | |
3052 | { | |
3053 | /* Map flags to equivalent IDN_* flags. */ | |
3054 | wchar_t *ascbuf = tp.w_get (); | |
3055 | if (IdnToAscii (idn_flags >> 16, whost, -1, ascbuf, NT_MAX_PATH)) | |
3056 | whost = ascbuf; | |
3057 | else if (GetLastError () != ERROR_PROC_NOT_FOUND) | |
3058 | return EAI_IDN_ENCODE; | |
3059 | } | |
3060 | } | |
3061 | if (servname) | |
3062 | { | |
3063 | memset (&ps, 0, sizeof ps); | |
3064 | src = servname; | |
3065 | wserv = tp.w_get (); | |
3066 | if (mbsrtowcs (wserv, &src, NT_MAX_PATH, &ps) == (size_t) -1) | |
3067 | return EAI_IDN_ENCODE; | |
3068 | if (src) | |
3069 | return EAI_MEMORY; | |
5b56e9b0 | 3070 | } |
5b56e9b0 | 3071 | |
3f3bd101 CV |
3072 | if (!hints) |
3073 | { | |
3074 | /* Default settings per glibc man page. */ | |
3075 | memset (&whints, 0, sizeof whints); | |
3076 | whints.ai_family = PF_UNSPEC; | |
3077 | whints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; | |
3078 | } | |
3079 | else | |
3080 | { | |
3081 | /* sizeof addrinfo == sizeof addrinfoW */ | |
3082 | memcpy (&whints, hints, sizeof whints); | |
3083 | whints.ai_flags &= ~AI_IDN_MASK; | |
3f3bd101 CV |
3084 | /* ai_addrlen is socklen_t (4 bytes) in POSIX but size_t (8 bytes) in |
3085 | Winsock. Sert upper 4 bytes explicitely to 0 to avoid EAI_FAIL. */ | |
3086 | whints.ai_addrlen &= UINT32_MAX; | |
6f560555 | 3087 | /* On Windows, the default behaviour is as if AI_ADDRCONFIG is set, |
3f3bd101 CV |
3088 | apparently for performance reasons. To get the POSIX default |
3089 | behaviour, the AI_ALL flag has to be set. */ | |
6f560555 | 3090 | if (whints.ai_family == PF_UNSPEC |
3f3bd101 CV |
3091 | && !(whints.ai_flags & AI_ADDRCONFIG)) |
3092 | whints.ai_flags |= AI_ALL; | |
3093 | } | |
3094 | /* Disable automatic IDN conversion on W8 and later. */ | |
3095 | whints.ai_flags |= AI_DISABLE_IDN_ENCODING; | |
7176a85c CV |
3096 | ret = GetAddrInfoW (whost, wserv, &whints, &wres); |
3097 | /* Try to workaround an apparent shortcoming in Winsock's getaddrinfo | |
3098 | implementation. See this link for details: | |
3099 | https://communities.vmware.com/message/2577858#2577858 */ | |
3100 | if (ret == WSANO_RECOVERY && (whints.ai_flags & AI_ALL)) | |
3101 | { | |
3102 | whints.ai_flags &= ~AI_ALL; | |
3103 | ret = GetAddrInfoW (whost, wserv, &whints, &wres); | |
3104 | } | |
3105 | ret = w32_to_gai_err (ret); | |
3f3bd101 CV |
3106 | /* Always copy over to self-allocated memory. */ |
3107 | if (!ret) | |
510a85cb | 3108 | { |
3f3bd101 | 3109 | *res = ga_duplist (wres, false, idn_flags, ret); |
5b56e9b0 | 3110 | FreeAddrInfoW (wres); |
3f3bd101 CV |
3111 | if (!*res) |
3112 | __leave; | |
3113 | } | |
c2decfdc | 3114 | } |
3f3bd101 CV |
3115 | __except (EFAULT) |
3116 | { | |
3117 | ret = EAI_SYSTEM; | |
3118 | } | |
3119 | __endtry | |
6eedb2be | 3120 | return ret; |
70e476d2 CV |
3121 | } |
3122 | ||
f881942d | 3123 | /* Exported as getnameinfo: POSIX.1-2001, POSIX.1-2008, RFC 2553 */ |
70e476d2 CV |
3124 | extern "C" int |
3125 | cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen, | |
3126 | char *host, size_t hostlen, char *serv, | |
3127 | size_t servlen, int flags) | |
3128 | { | |
3f3bd101 | 3129 | int ret = 0; |
6eedb2be | 3130 | |
3f3bd101 | 3131 | __try |
70e476d2 | 3132 | { |
3f3bd101 CV |
3133 | /* We call GetNameInfoW with local buffers and convert to locale |
3134 | charset to allow RFC 3490 IDNs like glibc 2.3.4 and later. */ | |
5b56e9b0 CV |
3135 | #define NI_IDN_MASK (NI_IDN | \ |
3136 | NI_IDN_ALLOW_UNASSIGNED | \ | |
3137 | NI_IDN_USE_STD3_ASCII_RULES) | |
3f3bd101 CV |
3138 | int idn_flags = flags & NI_IDN_MASK; |
3139 | flags &= ~NI_IDN_MASK; | |
3140 | tmp_pathbuf tp; | |
3141 | wchar_t *whost = NULL, *wserv = NULL; | |
3142 | DWORD whlen = 0, wslen = 0; | |
5b56e9b0 | 3143 | |
3f3bd101 CV |
3144 | if (host && hostlen) |
3145 | { | |
3146 | whost = tp.w_get (); | |
3147 | whlen = NT_MAX_PATH; | |
3148 | } | |
3149 | if (serv && servlen) | |
3150 | { | |
3151 | wserv = tp.w_get (); | |
3152 | wslen = NT_MAX_PATH; | |
3153 | } | |
5b56e9b0 | 3154 | |
3f3bd101 | 3155 | ret = w32_to_gai_err (GetNameInfoW (sa, salen, whost, whlen, |
5b56e9b0 | 3156 | wserv, wslen, flags)); |
3f3bd101 | 3157 | if (!ret) |
5b56e9b0 | 3158 | { |
3f3bd101 CV |
3159 | const wchar_t *src; |
3160 | ||
3161 | if (whost) | |
5b56e9b0 | 3162 | { |
3f3bd101 CV |
3163 | if (idn_flags & NI_IDN) |
3164 | { | |
3165 | /* Map flags to equivalent IDN_* flags. */ | |
3166 | wchar_t *idnbuf = tp.w_get (); | |
3167 | if (IdnToUnicode (idn_flags >> 16, whost, -1, | |
3168 | idnbuf, NT_MAX_PATH)) | |
3169 | whost = idnbuf; | |
3170 | else if (GetLastError () != ERROR_PROC_NOT_FOUND) | |
3171 | return EAI_IDN_ENCODE; | |
3172 | } | |
3173 | src = whost; | |
3174 | if (wcsrtombs (host, &src, hostlen, NULL) == (size_t) -1) | |
5b56e9b0 | 3175 | return EAI_IDN_ENCODE; |
3f3bd101 CV |
3176 | if (src) |
3177 | return EAI_OVERFLOW; | |
3178 | } | |
3179 | if (wserv) | |
3180 | { | |
3181 | src = wserv; | |
3182 | if (wcsrtombs (serv, &src, servlen, NULL) == (size_t) -1) | |
3183 | return EAI_IDN_ENCODE; | |
3184 | if (src) | |
3185 | return EAI_OVERFLOW; | |
5b56e9b0 | 3186 | } |
5b56e9b0 | 3187 | } |
3f3bd101 CV |
3188 | else if (ret == EAI_SYSTEM) |
3189 | set_winsock_errno (); | |
3190 | } | |
3191 | __except (EFAULT) | |
3192 | { | |
3193 | ret = EAI_SYSTEM; | |
5b56e9b0 | 3194 | } |
3f3bd101 | 3195 | __endtry |
6eedb2be | 3196 | return ret; |
70e476d2 CV |
3197 | } |
3198 | ||
2895b8b5 CV |
3199 | /* These functions are stick to the end of this file so that the |
3200 | optimization in asm/byteorder.h can be used even here in net.cc. */ | |
3201 | ||
3202 | #undef htonl | |
3203 | #undef ntohl | |
3204 | #undef htons | |
3205 | #undef ntohs | |
3206 | ||
f881942d | 3207 | /* htonl: POSIX.1-2001, POSIX.1-2008 */ |
2895b8b5 CV |
3208 | extern "C" uint32_t |
3209 | htonl (uint32_t x) | |
3210 | { | |
3211 | return __htonl (x); | |
3212 | } | |
3213 | ||
f881942d | 3214 | /* ntohl: POSIX.1-2001, POSIX.1-2008 */ |
2895b8b5 CV |
3215 | extern "C" uint32_t |
3216 | ntohl (uint32_t x) | |
3217 | { | |
3218 | return __ntohl (x); | |
3219 | } | |
3220 | ||
f881942d | 3221 | /* htons: POSIX.1-2001, POSIX.1-2008 */ |
2895b8b5 CV |
3222 | extern "C" uint16_t |
3223 | htons (uint16_t x) | |
3224 | { | |
3225 | return __htons (x); | |
3226 | } | |
3227 | ||
f881942d | 3228 | /* ntohs: POSIX.1-2001, POSIX.1-2008 */ |
2895b8b5 CV |
3229 | extern "C" uint16_t |
3230 | ntohs (uint16_t x) | |
3231 | { | |
3232 | return __ntohs (x); | |
3233 | } |