]>
Commit | Line | Data |
---|---|---|
afd5033d CV |
1 | /* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes. |
2 | ||
a7d2cc16 | 3 | Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. |
afd5033d CV |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | /* #define DEBUG_NEST_ON 1 */ | |
12 | ||
13 | #define __INSIDE_CYGWIN_NET__ | |
14 | ||
afd5033d | 15 | #include "winsup.h" |
be5007aa | 16 | #include <sys/un.h> |
de81c046 | 17 | #include <asm/byteorder.h> |
afd5033d | 18 | |
619f7fa0 | 19 | #include <stdlib.h> |
a1299ba5 | 20 | #define USE_SYS_TYPES_FD_SET |
afd5033d | 21 | #include <winsock2.h> |
f2e6c508 | 22 | #include <iphlpapi.h> |
afd5033d | 23 | #include "cygerrno.h" |
6b91b8d5 | 24 | #include "security.h" |
96a3f4ae CF |
25 | #include "cygwin/version.h" |
26 | #include "perprocess.h" | |
47063f00 | 27 | #include "path.h" |
7ac61736 | 28 | #include "fhandler.h" |
afd5033d | 29 | #include "dtable.h" |
0381fec6 | 30 | #include "cygheap.h" |
70e476d2 | 31 | #include "shared_info.h" |
afd5033d | 32 | #include "sigproc.h" |
0c565ab3 | 33 | #include "wininfo.h" |
5ec14fe4 | 34 | #include <unistd.h> |
c2d0b9d8 | 35 | #include <sys/acl.h> |
893ac8e0 | 36 | #include "cygtls.h" |
70e476d2 | 37 | #include "cygwin/in6.h" |
d85bcb45 | 38 | #include "ntdll.h" |
afd5033d | 39 | |
ef82f76c | 40 | #define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT) |
70e476d2 | 41 | #define EVENT_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE) |
ef82f76c | 42 | |
7ac61736 | 43 | extern bool fdsock (cygheap_fdmanip& fd, const device *, SOCKET soc); |
be5007aa CV |
44 | extern "C" { |
45 | int sscanf (const char *, const char *, ...); | |
46 | } /* End of "C" section */ | |
47 | ||
08b78edf | 48 | fhandler_dev_random* entropy_source; |
619f7fa0 | 49 | |
f9a963b8 CV |
50 | static inline mode_t |
51 | adjust_socket_file_mode (mode_t mode) | |
52 | { | |
53 | /* Kludge: Don't allow to remove read bit on socket files for | |
54 | user/group/other, if the accompanying write bit is set. It would | |
55 | be nice to have exact permissions on a socket file, but it's | |
56 | necessary that somebody able to access the socket can always read | |
57 | the contents of the socket file to avoid spurious "permission | |
58 | denied" messages. */ | |
59 | return mode | ((mode & (S_IWUSR | S_IWGRP | S_IWOTH)) << 1); | |
60 | } | |
61 | ||
be5007aa CV |
62 | /* cygwin internal: map sockaddr into internet domain address */ |
63 | static int | |
64 | get_inet_addr (const struct sockaddr *in, int inlen, | |
70e476d2 | 65 | struct sockaddr_storage *out, int *outlen, |
a5bfc687 | 66 | int *type = NULL, int *secret = NULL) |
be5007aa CV |
67 | { |
68 | int secret_buf [4]; | |
69 | int* secret_ptr = (secret ? : secret_buf); | |
70 | ||
70e476d2 | 71 | if (in->sa_family == AF_INET || in->sa_family == AF_INET6) |
be5007aa | 72 | { |
70e476d2 | 73 | memcpy (out, in, inlen); |
be5007aa CV |
74 | *outlen = inlen; |
75 | return 1; | |
76 | } | |
77 | else if (in->sa_family == AF_LOCAL) | |
78 | { | |
d85bcb45 CV |
79 | NTSTATUS status; |
80 | HANDLE fh; | |
81 | OBJECT_ATTRIBUTES attr; | |
82 | IO_STATUS_BLOCK io; | |
83 | ||
9d913f07 CV |
84 | path_conv pc (in->sa_data, PC_SYM_FOLLOW); |
85 | if (pc.error) | |
a113a3c5 | 86 | { |
9d913f07 CV |
87 | set_errno (pc.error); |
88 | return 0; | |
89 | } | |
90 | if (!pc.exists ()) | |
a113a3c5 | 91 | { |
9d913f07 CV |
92 | set_errno (ENOENT); |
93 | return 0; | |
94 | } | |
95 | if (!pc.issocket ()) | |
a113a3c5 | 96 | { |
9d913f07 CV |
97 | set_errno (EBADF); |
98 | return 0; | |
99 | } | |
d85bcb45 CV |
100 | status = NtOpenFile (&fh, GENERIC_READ | SYNCHRONIZE, |
101 | pc.get_object_attr (attr, sec_none_nih), &io, | |
102 | FILE_SHARE_VALID_FLAGS, | |
103 | FILE_SYNCHRONOUS_IO_NONALERT | |
104 | | FILE_OPEN_FOR_BACKUP_INTENT); | |
105 | if (!NT_SUCCESS (status)) | |
a113a3c5 | 106 | { |
d85bcb45 | 107 | __seterrno_from_nt_status (status); |
9d913f07 CV |
108 | return 0; |
109 | } | |
be5007aa CV |
110 | int ret = 0; |
111 | char buf[128]; | |
112 | memset (buf, 0, sizeof buf); | |
d85bcb45 CV |
113 | status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, 128, NULL, NULL); |
114 | NtClose (fh); | |
115 | if (NT_SUCCESS (status)) | |
a113a3c5 | 116 | { |
a6099ff8 | 117 | struct sockaddr_in sin; |
a5bfc687 | 118 | char ctype; |
6cae97d5 | 119 | sin.sin_family = AF_INET; |
a5bfc687 | 120 | sscanf (buf + strlen (SOCKET_COOKIE), "%hu %c %08x-%08x-%08x-%08x", |
6cae97d5 | 121 | &sin.sin_port, |
a5bfc687 | 122 | &ctype, |
6cae97d5 CF |
123 | secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3); |
124 | sin.sin_port = htons (sin.sin_port); | |
125 | sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
70e476d2 | 126 | memcpy (out, &sin, sizeof sin); |
6cae97d5 | 127 | *outlen = sizeof sin; |
a5bfc687 CV |
128 | if (type) |
129 | *type = (ctype == 's' ? SOCK_STREAM : | |
05726ddd CF |
130 | ctype == 'd' ? SOCK_DGRAM |
131 | : 0); | |
6cae97d5 CF |
132 | ret = 1; |
133 | } | |
2ba719de | 134 | else |
d85bcb45 | 135 | __seterrno_from_nt_status (status); |
be5007aa CV |
136 | return ret; |
137 | } | |
138 | else | |
139 | { | |
140 | set_errno (EAFNOSUPPORT); | |
141 | return 0; | |
142 | } | |
143 | } | |
144 | ||
afd5033d CV |
145 | /**********************************************************************/ |
146 | /* fhandler_socket */ | |
147 | ||
b79f85c2 CV |
148 | fhandler_socket::fhandler_socket () : |
149 | fhandler_base (), | |
70e476d2 CV |
150 | wsock_events (NULL), |
151 | wsock_mtx (NULL), | |
152 | wsock_evt (NULL), | |
b79f85c2 | 153 | sun_path (NULL), |
7aa88267 | 154 | status () |
afd5033d | 155 | { |
56551a9b | 156 | need_fork_fixup (true); |
afd5033d CV |
157 | } |
158 | ||
159 | fhandler_socket::~fhandler_socket () | |
160 | { | |
2fe27909 CV |
161 | if (sun_path) |
162 | cfree (sun_path); | |
afd5033d CV |
163 | } |
164 | ||
b832c4cf CV |
165 | char * |
166 | fhandler_socket::get_proc_fd_name (char *buf) | |
167 | { | |
168 | __small_sprintf (buf, "socket:[%d]", get_socket ()); | |
169 | return buf; | |
170 | } | |
171 | ||
172 | int | |
173 | fhandler_socket::open (int flags, mode_t mode) | |
174 | { | |
175 | set_errno (ENXIO); | |
176 | return 0; | |
177 | } | |
178 | ||
ef82f76c | 179 | void |
2f9ae2ed | 180 | fhandler_socket::af_local_set_sockpair_cred () |
ef82f76c CV |
181 | { |
182 | sec_pid = sec_peer_pid = getpid (); | |
183 | sec_uid = sec_peer_uid = geteuid32 (); | |
184 | sec_gid = sec_peer_gid = getegid32 (); | |
185 | } | |
186 | ||
187 | void | |
b832c4cf | 188 | fhandler_socket::af_local_setblocking (bool &async, bool &nonblocking) |
ef82f76c CV |
189 | { |
190 | async = async_io (); | |
191 | nonblocking = is_nonblocking (); | |
70e476d2 CV |
192 | if (async) |
193 | { | |
194 | WSAAsyncSelect (get_socket (), winmsg, 0, 0); | |
195 | WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK); | |
196 | } | |
ef82f76c CV |
197 | set_nonblocking (false); |
198 | async_io (false); | |
199 | } | |
200 | ||
201 | void | |
b832c4cf | 202 | fhandler_socket::af_local_unsetblocking (bool async, bool nonblocking) |
ef82f76c CV |
203 | { |
204 | if (nonblocking) | |
70e476d2 | 205 | set_nonblocking (true); |
ef82f76c CV |
206 | if (async) |
207 | { | |
208 | WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, ASYNC_MASK); | |
209 | async_io (true); | |
210 | } | |
211 | } | |
212 | ||
213 | bool | |
2f9ae2ed | 214 | fhandler_socket::af_local_recv_secret () |
b832c4cf CV |
215 | { |
216 | int out[4] = { 0, 0, 0, 0 }; | |
217 | int rest = sizeof out; | |
218 | char *ptr = (char *) out; | |
219 | while (rest > 0) | |
220 | { | |
221 | int ret = recvfrom (ptr, rest, 0, NULL, NULL); | |
222 | if (ret <= 0) | |
223 | break; | |
224 | rest -= ret; | |
225 | ptr += ret; | |
226 | } | |
227 | if (rest == 0) | |
228 | { | |
229 | debug_printf ("Received af_local secret: %08x-%08x-%08x-%08x", | |
230 | out[0], out[1], out[2], out[3]); | |
231 | if (out[0] != connect_secret[0] || out[1] != connect_secret[1] | |
05726ddd | 232 | || out[2] != connect_secret[2] || out[3] != connect_secret[3]) |
b832c4cf CV |
233 | { |
234 | debug_printf ("Receiving af_local secret mismatch"); | |
235 | return false; | |
236 | } | |
237 | } | |
238 | else | |
239 | debug_printf ("Receiving af_local secret failed"); | |
240 | return rest == 0; | |
241 | } | |
242 | ||
243 | bool | |
2f9ae2ed | 244 | fhandler_socket::af_local_send_secret () |
b832c4cf CV |
245 | { |
246 | int rest = sizeof connect_secret; | |
247 | char *ptr = (char *) connect_secret; | |
248 | while (rest > 0) | |
249 | { | |
250 | int ret = sendto (ptr, rest, 0, NULL, 0); | |
251 | if (ret <= 0) | |
252 | break; | |
253 | rest -= ret; | |
254 | ptr += ret; | |
255 | } | |
256 | debug_printf ("Sending af_local secret %s", rest == 0 ? "succeeded" | |
257 | : "failed"); | |
258 | return rest == 0; | |
259 | } | |
260 | ||
261 | bool | |
2f9ae2ed | 262 | fhandler_socket::af_local_recv_cred () |
ef82f76c CV |
263 | { |
264 | struct ucred out = { (pid_t) 0, (__uid32_t) -1, (__gid32_t) -1 }; | |
265 | int rest = sizeof out; | |
266 | char *ptr = (char *) &out; | |
267 | while (rest > 0) | |
268 | { | |
269 | int ret = recvfrom (ptr, rest, 0, NULL, NULL); | |
270 | if (ret <= 0) | |
271 | break; | |
272 | rest -= ret; | |
273 | ptr += ret; | |
274 | } | |
275 | if (rest == 0) | |
276 | { | |
277 | debug_printf ("Received eid credentials: pid: %d, uid: %d, gid: %d", | |
278 | out.pid, out.uid, out.gid); | |
279 | sec_peer_pid = out.pid; | |
280 | sec_peer_uid = out.uid; | |
281 | sec_peer_gid = out.gid; | |
282 | } | |
283 | else | |
284 | debug_printf ("Receiving eid credentials failed"); | |
285 | return rest == 0; | |
286 | } | |
287 | ||
288 | bool | |
2f9ae2ed | 289 | fhandler_socket::af_local_send_cred () |
ef82f76c CV |
290 | { |
291 | struct ucred in = { sec_pid, sec_uid, sec_gid }; | |
292 | int rest = sizeof in; | |
293 | char *ptr = (char *) ∈ | |
294 | while (rest > 0) | |
295 | { | |
296 | int ret = sendto (ptr, rest, 0, NULL, 0); | |
297 | if (ret <= 0) | |
298 | break; | |
299 | rest -= ret; | |
300 | ptr += ret; | |
301 | } | |
302 | if (rest == 0) | |
303 | debug_printf ("Sending eid credentials succeeded"); | |
304 | else | |
305 | debug_printf ("Sending eid credentials failed"); | |
306 | return rest == 0; | |
307 | } | |
308 | ||
b832c4cf | 309 | int |
2f9ae2ed | 310 | fhandler_socket::af_local_connect () |
ef82f76c | 311 | { |
b832c4cf CV |
312 | /* This keeps the test out of select. */ |
313 | if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM) | |
314 | return 0; | |
315 | ||
316 | debug_printf ("af_local_connect called"); | |
ef82f76c | 317 | bool orig_async_io, orig_is_nonblocking; |
b832c4cf CV |
318 | af_local_setblocking (orig_async_io, orig_is_nonblocking); |
319 | if (!af_local_send_secret () || !af_local_recv_secret () | |
320 | || !af_local_send_cred () || !af_local_recv_cred ()) | |
321 | { | |
322 | debug_printf ("accept from unauthorized server"); | |
323 | ::shutdown (get_socket (), SD_BOTH); | |
324 | WSASetLastError (WSAECONNREFUSED); | |
325 | return -1; | |
326 | } | |
327 | af_local_unsetblocking (orig_async_io, orig_is_nonblocking); | |
328 | return 0; | |
ef82f76c CV |
329 | } |
330 | ||
b832c4cf | 331 | int |
2f9ae2ed | 332 | fhandler_socket::af_local_accept () |
ef82f76c | 333 | { |
b832c4cf | 334 | debug_printf ("af_local_accept called"); |
ef82f76c | 335 | bool orig_async_io, orig_is_nonblocking; |
b832c4cf CV |
336 | af_local_setblocking (orig_async_io, orig_is_nonblocking); |
337 | if (!af_local_recv_secret () || !af_local_send_secret () | |
338 | || !af_local_recv_cred () || !af_local_send_cred ()) | |
339 | { | |
340 | debug_printf ("connect from unauthorized client"); | |
341 | ::shutdown (get_socket (), SD_BOTH); | |
342 | ::closesocket (get_socket ()); | |
343 | WSASetLastError (WSAECONNABORTED); | |
344 | return -1; | |
345 | } | |
346 | af_local_unsetblocking (orig_async_io, orig_is_nonblocking); | |
347 | return 0; | |
ef82f76c CV |
348 | } |
349 | ||
b832c4cf | 350 | void |
2f9ae2ed | 351 | fhandler_socket::af_local_set_cred () |
4f27e288 | 352 | { |
b832c4cf CV |
353 | sec_pid = getpid (); |
354 | sec_uid = geteuid32 (); | |
355 | sec_gid = getegid32 (); | |
356 | sec_peer_pid = (pid_t) 0; | |
357 | sec_peer_uid = (__uid32_t) -1; | |
358 | sec_peer_gid = (__gid32_t) -1; | |
4f27e288 CV |
359 | } |
360 | ||
b832c4cf CV |
361 | void |
362 | fhandler_socket::af_local_copy (fhandler_socket *sock) | |
e8309efd | 363 | { |
b832c4cf CV |
364 | sock->connect_secret[0] = connect_secret[0]; |
365 | sock->connect_secret[1] = connect_secret[1]; | |
366 | sock->connect_secret[2] = connect_secret[2]; | |
367 | sock->connect_secret[3] = connect_secret[3]; | |
368 | sock->sec_pid = sec_pid; | |
369 | sock->sec_uid = sec_uid; | |
370 | sock->sec_gid = sec_gid; | |
371 | sock->sec_peer_pid = sec_peer_pid; | |
372 | sock->sec_peer_uid = sec_peer_uid; | |
373 | sock->sec_peer_gid = sec_peer_gid; | |
e8309efd CV |
374 | } |
375 | ||
619f7fa0 | 376 | void |
b832c4cf | 377 | fhandler_socket::af_local_set_secret (char *buf) |
619f7fa0 | 378 | { |
69b218bf ED |
379 | if (!entropy_source) |
380 | { | |
381 | void *buf = malloc (sizeof (fhandler_dev_random)); | |
7ac61736 CF |
382 | entropy_source = new (buf) fhandler_dev_random (); |
383 | entropy_source->dev () = *urandom_dev; | |
69b218bf ED |
384 | } |
385 | if (entropy_source && | |
7ac61736 | 386 | !entropy_source->open (O_RDONLY)) |
69b218bf ED |
387 | { |
388 | delete entropy_source; | |
389 | entropy_source = NULL; | |
390 | } | |
d4f3ce31 | 391 | if (entropy_source) |
8bce0d72 CF |
392 | { |
393 | size_t len = sizeof (connect_secret); | |
394 | entropy_source->read (connect_secret, len); | |
395 | if (len != sizeof (connect_secret)) | |
396 | bzero ((char*) connect_secret, sizeof (connect_secret)); | |
397 | } | |
619f7fa0 ED |
398 | __small_sprintf (buf, "%08x-%08x-%08x-%08x", |
399 | connect_secret [0], connect_secret [1], | |
400 | connect_secret [2], connect_secret [3]); | |
401 | } | |
402 | ||
70e476d2 | 403 | /* Maximum number of concurrently opened sockets from all Cygwin processes |
e21ac1eb | 404 | per session. Note that shared sockets (through dup/fork/exec) are |
70e476d2 CV |
405 | counted as one socket. */ |
406 | #define NUM_SOCKS (65536 / sizeof (wsa_event)) | |
407 | ||
408 | #define LOCK_EVENTS WaitForSingleObject (wsock_mtx, INFINITE) | |
409 | #define UNLOCK_EVENTS ReleaseMutex (wsock_mtx) | |
410 | ||
411 | static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared)) = { 0 }; | |
412 | ||
413 | static LONG socket_serial_number __attribute__((section (".cygwin_dll_common"), shared)) = 0; | |
414 | ||
415 | static HANDLE wsa_slot_mtx; | |
416 | ||
417 | static wsa_event * | |
418 | search_wsa_event_slot (LONG new_serial_number) | |
419 | { | |
5224a7bb | 420 | char name[MAX_PATH], searchname[MAX_PATH]; |
70e476d2 CV |
421 | |
422 | if (!wsa_slot_mtx) | |
423 | { | |
424 | wsa_slot_mtx = CreateMutex (&sec_all, FALSE, | |
e21ac1eb | 425 | shared_name (name, "sock", 0, true)); |
70e476d2 CV |
426 | if (!wsa_slot_mtx) |
427 | api_fatal ("Couldn't create/open shared socket mutex, %E"); | |
428 | } | |
429 | switch (WaitForSingleObject (wsa_slot_mtx, INFINITE)) | |
430 | { | |
431 | case WAIT_OBJECT_0: | |
432 | case WAIT_ABANDONED: | |
433 | break; | |
434 | default: | |
435 | api_fatal ("WFSO failed for shared socket mutex, %E"); | |
436 | break; | |
437 | } | |
438 | unsigned int slot = new_serial_number % NUM_SOCKS; | |
439 | while (wsa_events[slot].serial_number) | |
440 | { | |
441 | HANDLE searchmtx = OpenMutex (STANDARD_RIGHTS_READ, FALSE, | |
e21ac1eb CV |
442 | shared_name (searchname, "sock", wsa_events[slot].serial_number, |
443 | true)); | |
70e476d2 | 444 | if (!searchmtx) |
510a85cb | 445 | break; |
70e476d2 CV |
446 | /* Mutex still exists, attached socket is active, try next slot. */ |
447 | CloseHandle (searchmtx); | |
448 | slot = (slot + 1) % NUM_SOCKS; | |
449 | if (slot == (new_serial_number % NUM_SOCKS)) | |
510a85cb | 450 | { |
70e476d2 CV |
451 | /* Did the whole array once. Too bad. */ |
452 | debug_printf ("No free socket slot"); | |
453 | ReleaseMutex (wsa_slot_mtx); | |
454 | return NULL; | |
455 | } | |
456 | } | |
fd5879c1 | 457 | memset (&wsa_events[slot], 0, sizeof (wsa_event)); |
70e476d2 CV |
458 | wsa_events[slot].serial_number = new_serial_number; |
459 | ReleaseMutex (wsa_slot_mtx); | |
460 | return wsa_events + slot; | |
461 | } | |
462 | ||
463 | bool | |
464 | fhandler_socket::init_events () | |
465 | { | |
466 | LONG new_serial_number; | |
5224a7bb | 467 | char name[MAX_PATH]; |
70e476d2 CV |
468 | DWORD err = 0; |
469 | ||
470 | do | |
471 | { | |
472 | new_serial_number = InterlockedIncrement (&socket_serial_number); | |
473 | if (!new_serial_number) /* 0 is reserved for global mutex */ | |
474 | InterlockedIncrement (&socket_serial_number); | |
475 | wsock_mtx = CreateMutex (&sec_all, FALSE, | |
e21ac1eb CV |
476 | shared_name (name, "sock", new_serial_number, |
477 | true)); | |
70e476d2 CV |
478 | if (!wsock_mtx) |
479 | { | |
480 | debug_printf ("CreateMutex, %E"); | |
481 | set_errno (ENOBUFS); | |
482 | return false; | |
483 | } | |
484 | err = GetLastError (); | |
485 | if (err == ERROR_ALREADY_EXISTS) | |
510a85cb | 486 | CloseHandle (wsock_mtx); |
70e476d2 CV |
487 | } |
488 | while (err == ERROR_ALREADY_EXISTS); | |
489 | if ((wsock_evt = CreateEvent (&sec_all, TRUE, FALSE, NULL)) | |
490 | == WSA_INVALID_EVENT) | |
491 | { | |
492 | debug_printf ("WSACreateEvent, %E"); | |
493 | set_errno (ENOBUFS); | |
494 | CloseHandle (wsock_mtx); | |
495 | return false; | |
496 | } | |
497 | if (WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK) == SOCKET_ERROR) | |
498 | { | |
499 | debug_printf ("WSAEventSelect, %E"); | |
500 | set_winsock_errno (); | |
501 | CloseHandle (wsock_evt); | |
502 | CloseHandle (wsock_mtx); | |
503 | return false; | |
504 | } | |
505 | wsock_events = search_wsa_event_slot (new_serial_number); | |
fd5879c1 CV |
506 | /* sock type not yet set here. */ |
507 | if (pc.dev == FH_UDP || pc.dev == FH_DGRAM) | |
508 | wsock_events->events = FD_WRITE; | |
70e476d2 CV |
509 | return true; |
510 | } | |
511 | ||
512 | int | |
513 | fhandler_socket::evaluate_events (const long event_mask, long &events, | |
514 | bool erase) | |
515 | { | |
516 | int ret = 0; | |
1f7dbb01 | 517 | long events_now = 0; |
70e476d2 CV |
518 | |
519 | WSANETWORKEVENTS evts = { 0 }; | |
520 | if (!(WSAEnumNetworkEvents (get_socket (), wsock_evt, &evts))) | |
521 | { | |
522 | if (evts.lNetworkEvents) | |
510a85cb | 523 | { |
70e476d2 CV |
524 | LOCK_EVENTS; |
525 | wsock_events->events |= evts.lNetworkEvents; | |
1f7dbb01 | 526 | events_now = (wsock_events->events & event_mask); |
70e476d2 | 527 | if (evts.lNetworkEvents & FD_CONNECT) |
fd5879c1 | 528 | wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT]; |
70e476d2 CV |
529 | UNLOCK_EVENTS; |
530 | if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner) | |
531 | kill (wsock_events->owner, SIGURG); | |
532 | } | |
533 | } | |
534 | ||
535 | LOCK_EVENTS; | |
1f7dbb01 CV |
536 | if ((events = events_now) != 0 |
537 | || (events = (wsock_events->events & event_mask)) != 0) | |
70e476d2 | 538 | { |
fd5879c1 | 539 | if (events & FD_CONNECT) |
70e476d2 CV |
540 | { |
541 | int wsa_err = 0; | |
fd5879c1 | 542 | if ((wsa_err = wsock_events->connect_errorcode) != 0) |
70e476d2 CV |
543 | { |
544 | WSASetLastError (wsa_err); | |
545 | ret = SOCKET_ERROR; | |
546 | } | |
fd5879c1 CV |
547 | else |
548 | wsock_events->events |= FD_WRITE; | |
549 | wsock_events->events &= ~FD_CONNECT; | |
550 | wsock_events->connect_errorcode = 0; | |
70e476d2 CV |
551 | } |
552 | if (erase) | |
553 | wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE)); | |
554 | } | |
555 | UNLOCK_EVENTS; | |
556 | ||
557 | return ret; | |
558 | } | |
559 | ||
560 | int | |
561 | fhandler_socket::wait_for_events (const long event_mask) | |
562 | { | |
563 | if (async_io ()) | |
564 | return 0; | |
565 | ||
566 | int ret; | |
567 | long events; | |
568 | ||
569 | while (!(ret = evaluate_events (event_mask, events, true)) && !events) | |
570 | { | |
571 | if (is_nonblocking ()) | |
572 | { | |
573 | WSASetLastError (WSAEWOULDBLOCK); | |
574 | return SOCKET_ERROR; | |
575 | } | |
576 | ||
577 | WSAEVENT ev[2] = { wsock_evt, signal_arrived }; | |
578 | switch (WSAWaitForMultipleEvents (2, ev, FALSE, 50, FALSE)) | |
579 | { | |
580 | case WSA_WAIT_TIMEOUT: | |
581 | case WSA_WAIT_EVENT_0: | |
582 | break; | |
583 | ||
584 | case WSA_WAIT_EVENT_0 + 1: | |
585 | if (_my_tls.call_signal_handler ()) | |
586 | { | |
587 | sig_dispatch_pending (); | |
588 | break; | |
589 | } | |
590 | WSASetLastError (WSAEINTR); | |
591 | return SOCKET_ERROR; | |
592 | ||
593 | default: | |
594 | WSASetLastError (WSAEFAULT); | |
595 | return SOCKET_ERROR; | |
596 | } | |
597 | } | |
598 | ||
599 | return ret; | |
600 | } | |
601 | ||
602 | void | |
603 | fhandler_socket::release_events () | |
604 | { | |
605 | CloseHandle (wsock_evt); | |
606 | CloseHandle (wsock_mtx); | |
607 | } | |
608 | ||
afd5033d | 609 | void |
3d78e129 | 610 | fhandler_socket::fixup_after_fork (HANDLE parent) |
afd5033d | 611 | { |
9869e006 CV |
612 | fork_fixup (parent, wsock_mtx, "wsock_mtx"); |
613 | fork_fixup (parent, wsock_evt, "wsock_evt"); | |
614 | fhandler_base::fixup_after_fork (parent); | |
8e54fb88 CV |
615 | } |
616 | ||
afd5033d | 617 | int |
dcb091ca | 618 | fhandler_socket::dup (fhandler_base *child) |
afd5033d | 619 | { |
0476bae5 | 620 | debug_printf ("here"); |
afd5033d | 621 | fhandler_socket *fhs = (fhandler_socket *) child; |
70e476d2 CV |
622 | |
623 | if (!DuplicateHandle (hMainProc, wsock_mtx, hMainProc, &fhs->wsock_mtx, 0, | |
624 | TRUE, DUPLICATE_SAME_ACCESS)) | |
625 | { | |
70e476d2 CV |
626 | __seterrno (); |
627 | return -1; | |
628 | } | |
629 | if (!DuplicateHandle (hMainProc, wsock_evt, hMainProc, &fhs->wsock_evt, 0, | |
630 | TRUE, DUPLICATE_SAME_ACCESS)) | |
631 | { | |
70e476d2 CV |
632 | __seterrno (); |
633 | CloseHandle (fhs->wsock_mtx); | |
634 | return -1; | |
635 | } | |
636 | fhs->wsock_events = wsock_events; | |
637 | ||
619f7fa0 | 638 | fhs->addr_family = addr_family; |
12390bc4 | 639 | fhs->set_socket_type (get_socket_type ()); |
496337c9 CV |
640 | if (get_addr_family () == AF_LOCAL) |
641 | { | |
642 | fhs->set_sun_path (get_sun_path ()); | |
643 | if (get_socket_type () == SOCK_STREAM) | |
05726ddd | 644 | { |
496337c9 CV |
645 | fhs->sec_pid = sec_pid; |
646 | fhs->sec_uid = sec_uid; | |
647 | fhs->sec_gid = sec_gid; | |
648 | fhs->sec_peer_pid = sec_peer_pid; | |
649 | fhs->sec_peer_uid = sec_peer_uid; | |
650 | fhs->sec_peer_gid = sec_peer_gid; | |
496337c9 CV |
651 | } |
652 | } | |
56551a9b | 653 | fhs->connect_state (connect_state ()); |
9869e006 CV |
654 | int ret = fhandler_base::dup (child); |
655 | if (ret) | |
aa39b7f7 | 656 | { |
70e476d2 CV |
657 | CloseHandle (fhs->wsock_evt); |
658 | CloseHandle (fhs->wsock_mtx); | |
aa39b7f7 | 659 | } |
9869e006 | 660 | return ret; |
afd5033d CV |
661 | } |
662 | ||
0476bae5 | 663 | int __stdcall |
7ac61736 | 664 | fhandler_socket::fstat (struct __stat64 *buf) |
0476bae5 | 665 | { |
c2d0b9d8 CV |
666 | int res; |
667 | if (get_device () == FH_UNIX) | |
035bfbdd | 668 | { |
c2d0b9d8 CV |
669 | res = fhandler_base::fstat_fs (buf); |
670 | if (!res) | |
05726ddd | 671 | { |
c2d0b9d8 CV |
672 | buf->st_mode = (buf->st_mode & ~S_IFMT) | S_IFSOCK; |
673 | } | |
674 | } | |
675 | else | |
676 | { | |
677 | res = fhandler_base::fstat (buf); | |
678 | if (!res) | |
679 | { | |
680 | buf->st_dev = 0; | |
681 | buf->st_ino = (__ino64_t) ((DWORD) get_handle ()); | |
682 | buf->st_mode = S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO; | |
683 | } | |
035bfbdd | 684 | } |
9cde3cf3 | 685 | return res; |
0476bae5 CF |
686 | } |
687 | ||
3323df7e CV |
688 | int __stdcall |
689 | fhandler_socket::fstatvfs (struct statvfs *sfs) | |
690 | { | |
691 | if (get_device () == FH_UNIX) | |
692 | { | |
693 | fhandler_disk_file fh (pc); | |
694 | fh.get_device () = FH_FS; | |
695 | return fh.fstatvfs (sfs); | |
696 | } | |
697 | set_errno (EBADF); | |
698 | return -1; | |
699 | } | |
700 | ||
c2d0b9d8 CV |
701 | int |
702 | fhandler_socket::fchmod (mode_t mode) | |
703 | { | |
704 | if (get_device () == FH_UNIX) | |
705 | { | |
2b09be25 | 706 | fhandler_disk_file fh (pc); |
c2d0b9d8 | 707 | fh.get_device () = FH_FS; |
f4c96363 | 708 | int ret = fh.fchmod (S_IFSOCK | adjust_socket_file_mode (mode)); |
c2d0b9d8 CV |
709 | return ret; |
710 | } | |
3323df7e CV |
711 | set_errno (EBADF); |
712 | return -1; | |
c2d0b9d8 CV |
713 | } |
714 | ||
715 | int | |
716 | fhandler_socket::fchown (__uid32_t uid, __gid32_t gid) | |
717 | { | |
718 | if (get_device () == FH_UNIX) | |
719 | { | |
2b09be25 | 720 | fhandler_disk_file fh (pc); |
c2d0b9d8 CV |
721 | return fh.fchown (uid, gid); |
722 | } | |
3323df7e CV |
723 | set_errno (EBADF); |
724 | return -1; | |
c2d0b9d8 CV |
725 | } |
726 | ||
727 | int | |
728 | fhandler_socket::facl (int cmd, int nentries, __aclent32_t *aclbufp) | |
729 | { | |
730 | if (get_device () == FH_UNIX) | |
731 | { | |
2b09be25 | 732 | fhandler_disk_file fh (pc); |
c2d0b9d8 CV |
733 | return fh.facl (cmd, nentries, aclbufp); |
734 | } | |
3323df7e CV |
735 | set_errno (EBADF); |
736 | return -1; | |
c2d0b9d8 CV |
737 | } |
738 | ||
0d75ce96 CV |
739 | int |
740 | fhandler_socket::link (const char *newpath) | |
741 | { | |
742 | if (get_device () == FH_UNIX) | |
743 | { | |
2b09be25 | 744 | fhandler_disk_file fh (pc); |
0d75ce96 CV |
745 | return fh.link (newpath); |
746 | } | |
747 | return fhandler_base::link (newpath); | |
748 | } | |
749 | ||
0ee535cc CV |
750 | static inline bool |
751 | address_in_use (struct sockaddr_in *addr) | |
752 | { | |
753 | PMIB_TCPTABLE tab; | |
754 | PMIB_TCPROW entry; | |
755 | DWORD size = 0, i; | |
756 | ||
757 | if (GetTcpTable (NULL, &size, FALSE) == ERROR_INSUFFICIENT_BUFFER) | |
758 | { | |
759 | tab = (PMIB_TCPTABLE) alloca (size); | |
760 | if (!GetTcpTable (tab, &size, FALSE)) | |
34f5d087 | 761 | { |
0ee535cc CV |
762 | for (i = tab->dwNumEntries, entry = tab->table; i > 0; --i, ++entry) |
763 | if (entry->dwLocalAddr == addr->sin_addr.s_addr | |
34f5d087 | 764 | && entry->dwLocalPort == addr->sin_port |
0ee535cc CV |
765 | && entry->dwState >= MIB_TCP_STATE_LISTEN |
766 | && entry->dwState <= MIB_TCP_STATE_LAST_ACK) | |
767 | return true; | |
768 | } | |
769 | } | |
770 | return false; | |
771 | } | |
772 | ||
be5007aa CV |
773 | int |
774 | fhandler_socket::bind (const struct sockaddr *name, int namelen) | |
775 | { | |
776 | int res = -1; | |
777 | ||
778 | if (name->sa_family == AF_LOCAL) | |
779 | { | |
780 | #define un_addr ((struct sockaddr_un *) name) | |
781 | struct sockaddr_in sin; | |
5bf785a0 | 782 | int len = sizeof sin; |
be5007aa CV |
783 | |
784 | if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN) | |
785 | { | |
786 | set_errno (ENAMETOOLONG); | |
787 | goto out; | |
788 | } | |
789 | sin.sin_family = AF_INET; | |
790 | sin.sin_port = 0; | |
791 | sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
792 | if (::bind (get_socket (), (sockaddr *) &sin, len)) | |
793 | { | |
4997a508 | 794 | syscall_printf ("AF_LOCAL: bind failed"); |
be5007aa CV |
795 | set_winsock_errno (); |
796 | goto out; | |
797 | } | |
798 | if (::getsockname (get_socket (), (sockaddr *) &sin, &len)) | |
799 | { | |
4997a508 | 800 | syscall_printf ("AF_LOCAL: getsockname failed"); |
be5007aa CV |
801 | set_winsock_errno (); |
802 | goto out; | |
803 | } | |
804 | ||
805 | sin.sin_port = ntohs (sin.sin_port); | |
806 | debug_printf ("AF_LOCAL: socket bound to port %u", sin.sin_port); | |
807 | ||
5a082e9e CV |
808 | path_conv pc (un_addr->sun_path, PC_SYM_FOLLOW); |
809 | if (pc.error) | |
a113a3c5 CF |
810 | { |
811 | set_errno (pc.error); | |
be5007aa CV |
812 | goto out; |
813 | } | |
5a082e9e | 814 | if (pc.exists ()) |
a113a3c5 | 815 | { |
5a082e9e CV |
816 | set_errno (EADDRINUSE); |
817 | goto out; | |
818 | } | |
f9a963b8 CV |
819 | mode_t mode = adjust_socket_file_mode ((S_IRWXU | S_IRWXG | S_IRWXO) |
820 | & ~cygheap->umask); | |
d85bcb45 | 821 | DWORD fattr = FILE_ATTRIBUTE_SYSTEM; |
5a082e9e | 822 | if (!(mode & (S_IWUSR | S_IWGRP | S_IWOTH))) |
d85bcb45 CV |
823 | fattr |= FILE_ATTRIBUTE_READONLY; |
824 | SECURITY_ATTRIBUTES sa = sec_none_nih; | |
12069cf3 | 825 | security_descriptor sd; |
5a082e9e | 826 | if (allow_ntsec && pc.has_acls ()) |
12069cf3 | 827 | set_security_attribute (mode, &sa, sd); |
d85bcb45 CV |
828 | NTSTATUS status; |
829 | HANDLE fh; | |
830 | OBJECT_ATTRIBUTES attr; | |
831 | IO_STATUS_BLOCK io; | |
4797f5bc | 832 | status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE, |
d85bcb45 CV |
833 | pc.get_object_attr (attr, sa), &io, NULL, fattr, |
834 | FILE_SHARE_VALID_FLAGS, FILE_CREATE, | |
835 | FILE_NON_DIRECTORY_FILE | |
836 | | FILE_SYNCHRONOUS_IO_NONALERT | |
837 | | FILE_OPEN_FOR_BACKUP_INTENT, | |
838 | NULL, 0); | |
839 | if (!NT_SUCCESS (status)) | |
a113a3c5 | 840 | { |
d85bcb45 | 841 | if (io.Information == FILE_EXISTS) |
5a082e9e CV |
842 | set_errno (EADDRINUSE); |
843 | else | |
d85bcb45 | 844 | __seterrno_from_nt_status (status); |
5a082e9e | 845 | } |
be5007aa | 846 | else |
a113a3c5 | 847 | { |
4797f5bc CV |
848 | char buf[sizeof (SOCKET_COOKIE) + 80]; |
849 | __small_sprintf (buf, "%s%u %c ", SOCKET_COOKIE, sin.sin_port, | |
850 | get_socket_type () == SOCK_STREAM ? 's' | |
851 | : get_socket_type () == SOCK_DGRAM ? 'd' : '-'); | |
852 | af_local_set_secret (strchr (buf, '\0')); | |
853 | DWORD blen = strlen (buf) + 1; | |
854 | status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, blen, NULL, 0); | |
855 | if (!NT_SUCCESS (status)) | |
856 | { | |
857 | __seterrno_from_nt_status (status); | |
858 | FILE_DISPOSITION_INFORMATION fdi = { TRUE }; | |
859 | status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi, | |
860 | FileDispositionInformation); | |
861 | if (!NT_SUCCESS (status)) | |
862 | debug_printf ("Setting delete dispostion failed, status = %p", | |
863 | status); | |
864 | } | |
865 | else | |
866 | { | |
867 | set_sun_path (un_addr->sun_path); | |
868 | res = 0; | |
869 | } | |
870 | NtClose (fh); | |
be5007aa CV |
871 | } |
872 | #undef un_addr | |
873 | } | |
be5007aa | 874 | else |
5369605f CV |
875 | { |
876 | /* If the application didn't explicitely call setsockopt (SO_REUSEADDR), | |
34f5d087 | 877 | enforce exclusive local address use using the SO_EXCLUSIVEADDRUSE |
5369605f | 878 | socket option, to emulate POSIX socket behaviour more closely. |
34f5d087 | 879 | |
5369605f CV |
880 | KB 870562: Note that this option is only available since NT4 SP4. |
881 | Also note that a bug in Win2K SP1-3 and XP up to SP1 only enables | |
882 | this option for users in the local administrators group. */ | |
883 | if (wincap.has_exclusiveaddruse ()) | |
34f5d087 | 884 | { |
5369605f CV |
885 | if (!saw_reuseaddr ()) |
886 | { | |
887 | int on = 1; | |
888 | int ret = ::setsockopt (get_socket (), SOL_SOCKET, | |
889 | ~(SO_REUSEADDR), | |
890 | (const char *) &on, sizeof on); | |
891 | debug_printf ("%d = setsockopt (SO_EXCLUSIVEADDRUSE), %E", ret); | |
892 | } | |
893 | else | |
0ee535cc CV |
894 | { |
895 | debug_printf ("SO_REUSEADDR set"); | |
896 | /* There's a bug in SO_REUSEADDR handling in WinSock. | |
34f5d087 | 897 | Per standards, we must not be able to reuse a complete |
0ee535cc CV |
898 | duplicate of a local TCP address (same IP, same port), |
899 | even if SO_REUSEADDR has been set. That's unfortunately | |
900 | possible in WinSock. So we're testing here if the local | |
901 | address is already in use and don't bind, if so. This | |
902 | only works for OSes with IP Helper support. */ | |
903 | if (get_socket_type () == SOCK_STREAM | |
904 | && wincap.has_ip_helper_lib () | |
34f5d087 CF |
905 | && address_in_use ((struct sockaddr_in *) name)) |
906 | { | |
0ee535cc CV |
907 | debug_printf ("Local address in use, don't bind"); |
908 | set_errno (EADDRINUSE); | |
909 | goto out; | |
910 | } | |
911 | } | |
5369605f CV |
912 | } |
913 | if (::bind (get_socket (), name, namelen)) | |
914 | set_winsock_errno (); | |
915 | else | |
916 | res = 0; | |
917 | } | |
be5007aa CV |
918 | |
919 | out: | |
920 | return res; | |
921 | } | |
922 | ||
923 | int | |
924 | fhandler_socket::connect (const struct sockaddr *name, int namelen) | |
925 | { | |
926 | int res = -1; | |
2e008fb9 | 927 | bool in_progress = false; |
70e476d2 | 928 | struct sockaddr_storage sst; |
f496071c | 929 | DWORD err; |
a5bfc687 | 930 | int type; |
be5007aa | 931 | |
70e476d2 | 932 | if (!get_inet_addr (name, namelen, &sst, &namelen, &type, connect_secret)) |
be5007aa CV |
933 | return -1; |
934 | ||
a5bfc687 CV |
935 | if (get_addr_family () == AF_LOCAL && get_socket_type () != type) |
936 | { | |
937 | WSASetLastError (WSAEPROTOTYPE); | |
938 | set_winsock_errno (); | |
939 | return -1; | |
940 | } | |
941 | ||
70e476d2 CV |
942 | res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); |
943 | if (!is_nonblocking () | |
944 | && res == SOCKET_ERROR | |
945 | && WSAGetLastError () == WSAEWOULDBLOCK) | |
946 | res = wait_for_events (FD_CONNECT | FD_CLOSE); | |
5777b970 | 947 | |
b1d9a0bd CF |
948 | if (!res) |
949 | err = 0; | |
950 | else | |
be5007aa | 951 | { |
ef82f76c | 952 | err = WSAGetLastError (); |
be5007aa CV |
953 | /* Special handling for connect to return the correct error code |
954 | when called on a non-blocking socket. */ | |
04843bf4 | 955 | if (is_nonblocking ()) |
be5007aa | 956 | { |
be5007aa | 957 | if (err == WSAEWOULDBLOCK || err == WSAEALREADY) |
2e008fb9 | 958 | in_progress = true; |
f496071c TP |
959 | |
960 | if (err == WSAEWOULDBLOCK) | |
ef82f76c | 961 | WSASetLastError (err = WSAEINPROGRESS); |
be5007aa | 962 | } |
c2c020d1 CV |
963 | if (err == WSAEINVAL) |
964 | WSASetLastError (err = WSAEISCONN); | |
be5007aa CV |
965 | set_winsock_errno (); |
966 | } | |
2e7c4a2a CV |
967 | |
968 | if (get_addr_family () == AF_LOCAL && (!res || in_progress)) | |
969 | set_sun_path (name->sa_data); | |
970 | ||
be5007aa CV |
971 | if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM) |
972 | { | |
b832c4cf CV |
973 | af_local_set_cred (); /* Don't move into af_local_connect since |
974 | af_local_connect is called from select, | |
975 | possibly running under another identity. */ | |
976 | if (!res && af_local_connect ()) | |
977 | { | |
978 | set_winsock_errno (); | |
979 | return -1; | |
496337c9 | 980 | } |
be5007aa CV |
981 | } |
982 | ||
f496071c | 983 | if (err == WSAEINPROGRESS || err == WSAEALREADY) |
56551a9b | 984 | connect_state (connect_pending); |
04843bf4 CV |
985 | else if (err) |
986 | connect_state (connect_failed); | |
6bb769ef | 987 | else |
56551a9b | 988 | connect_state (connected); |
5777b970 | 989 | |
be5007aa CV |
990 | return res; |
991 | } | |
992 | ||
993 | int | |
994 | fhandler_socket::listen (int backlog) | |
995 | { | |
996 | int res = ::listen (get_socket (), backlog); | |
70e476d2 | 997 | if (res && WSAGetLastError () == WSAEINVAL) |
c2ab308c CV |
998 | { |
999 | /* It's perfectly valid to call listen on an unbound INET socket. | |
1000 | In this case the socket is automatically bound to an unused | |
1001 | port number, listening on all interfaces. On Winsock, listen | |
1002 | fails with WSAEINVAL when it's called on an unbound socket. | |
1003 | So we have to bind manually here to have POSIX semantics. */ | |
70e476d2 | 1004 | if (get_addr_family () == AF_INET) |
510a85cb | 1005 | { |
70e476d2 CV |
1006 | struct sockaddr_in sin; |
1007 | sin.sin_family = AF_INET; | |
1008 | sin.sin_port = 0; | |
1009 | sin.sin_addr.s_addr = INADDR_ANY; | |
1010 | if (!::bind (get_socket (), (struct sockaddr *) &sin, sizeof sin)) | |
1011 | res = ::listen (get_socket (), backlog); | |
1012 | } | |
1013 | else if (get_addr_family () == AF_INET6) | |
510a85cb CF |
1014 | { |
1015 | struct sockaddr_in6 sin6 = | |
70e476d2 CV |
1016 | { |
1017 | sin6_family: AF_INET6, | |
1018 | sin6_port: 0, | |
1019 | sin6_flowinfo: 0, | |
1020 | sin6_addr: IN6ADDR_ANY_INIT, | |
1021 | sin6_scope_id: 0 | |
1022 | }; | |
1023 | if (!::bind (get_socket (), (struct sockaddr *) &sin6, sizeof sin6)) | |
1024 | res = ::listen (get_socket (), backlog); | |
1025 | } | |
c2ab308c CV |
1026 | } |
1027 | if (!res) | |
c8b404bf CV |
1028 | { |
1029 | if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM) | |
b832c4cf | 1030 | af_local_set_cred (); |
c8b404bf | 1031 | connect_state (connected); |
70e476d2 | 1032 | listener (true); |
c8b404bf | 1033 | } |
c2ab308c CV |
1034 | else |
1035 | set_winsock_errno (); | |
be5007aa CV |
1036 | return res; |
1037 | } | |
1038 | ||
1039 | int | |
1040 | fhandler_socket::accept (struct sockaddr *peer, int *len) | |
1041 | { | |
be5007aa CV |
1042 | /* Allows NULL peer and len parameters. */ |
1043 | struct sockaddr_in peer_dummy; | |
1044 | int len_dummy; | |
1045 | if (!peer) | |
1046 | peer = (struct sockaddr *) &peer_dummy; | |
1047 | if (!len) | |
1048 | { | |
1049 | len_dummy = sizeof (struct sockaddr_in); | |
1050 | len = &len_dummy; | |
1051 | } | |
1052 | ||
1053 | /* accept on NT fails if len < sizeof (sockaddr_in) | |
1054 | * some programs set len to | |
1055 | * sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain | |
1056 | */ | |
1057 | if (len && ((unsigned) *len < sizeof (struct sockaddr_in))) | |
1058 | *len = sizeof (struct sockaddr_in); | |
1059 | ||
be5007aa | 1060 | |
70e476d2 CV |
1061 | int res = 0; |
1062 | while (!(res = wait_for_events (FD_ACCEPT | FD_CLOSE)) | |
1063 | && (res = ::accept (get_socket (), peer, len)) == SOCKET_ERROR | |
1064 | && WSAGetLastError () == WSAEWOULDBLOCK) | |
1065 | ; | |
b832c4cf | 1066 | if (res == (int) INVALID_SOCKET) |
01e3c897 CV |
1067 | set_winsock_errno (); |
1068 | else | |
1069 | { | |
518f5d49 | 1070 | cygheap_fdnew res_fd; |
7ac61736 | 1071 | if (res_fd >= 0 && fdsock (res_fd, &dev (), res)) |
e3778517 | 1072 | { |
ef82f76c CV |
1073 | fhandler_socket *sock = (fhandler_socket *) res_fd; |
1074 | sock->set_addr_family (get_addr_family ()); | |
1075 | sock->set_socket_type (get_socket_type ()); | |
1076 | sock->async_io (async_io ()); | |
1077 | sock->set_nonblocking (is_nonblocking ()); | |
c8b404bf CV |
1078 | if (get_addr_family () == AF_LOCAL) |
1079 | { | |
ef82f76c | 1080 | sock->set_sun_path (get_sun_path ()); |
c8b404bf | 1081 | if (get_socket_type () == SOCK_STREAM) |
05726ddd | 1082 | { |
ef82f76c CV |
1083 | /* Don't forget to copy credentials from accepting |
1084 | socket to accepted socket and start transaction | |
1085 | on accepted socket! */ | |
b832c4cf CV |
1086 | af_local_copy (sock); |
1087 | res = sock->af_local_accept (); | |
1088 | if (res == -1) | |
1089 | { | |
1090 | res_fd.release (); | |
1091 | set_winsock_errno (); | |
1092 | goto out; | |
1093 | } | |
05726ddd | 1094 | } |
c8b404bf | 1095 | } |
70e476d2 CV |
1096 | /* No locking necessary at this point. */ |
1097 | sock->wsock_events->events = wsock_events->events | FD_WRITE; | |
1098 | sock->wsock_events->owner = wsock_events->owner; | |
ef82f76c | 1099 | sock->connect_state (connected); |
518f5d49 CV |
1100 | res = res_fd; |
1101 | } | |
1102 | else | |
a113a3c5 | 1103 | { |
518f5d49 CV |
1104 | closesocket (res); |
1105 | res = -1; | |
1106 | } | |
01e3c897 | 1107 | } |
3c6bd991 | 1108 | |
b832c4cf | 1109 | out: |
7ac61736 | 1110 | debug_printf ("res %d", res); |
be5007aa CV |
1111 | return res; |
1112 | } | |
1113 | ||
1114 | int | |
1115 | fhandler_socket::getsockname (struct sockaddr *name, int *namelen) | |
1116 | { | |
1117 | int res = -1; | |
1118 | ||
be5007aa CV |
1119 | if (get_addr_family () == AF_LOCAL) |
1120 | { | |
1121 | struct sockaddr_un *sun = (struct sockaddr_un *) name; | |
1122 | memset (sun, 0, *namelen); | |
1123 | sun->sun_family = AF_LOCAL; | |
1124 | ||
1125 | if (!get_sun_path ()) | |
1126 | sun->sun_path[0] = '\0'; | |
1127 | else | |
1128 | /* According to SUSv2 "If the actual length of the address is | |
1129 | greater than the length of the supplied sockaddr structure, the | |
1130 | stored address will be truncated." We play it save here so | |
1131 | that the path always has a trailing 0 even if it's truncated. */ | |
1132 | strncpy (sun->sun_path, get_sun_path (), | |
1133 | *namelen - sizeof *sun + sizeof sun->sun_path - 1); | |
1134 | ||
1135 | *namelen = sizeof *sun - sizeof sun->sun_path | |
1136 | + strlen (sun->sun_path) + 1; | |
1137 | res = 0; | |
1138 | } | |
1139 | else | |
1140 | { | |
1141 | res = ::getsockname (get_socket (), name, namelen); | |
1142 | if (res) | |
510a85cb | 1143 | { |
70e476d2 CV |
1144 | if (WSAGetLastError () == WSAEINVAL) |
1145 | { | |
1146 | /* Winsock returns WSAEINVAL if the socket is locally | |
1147 | unbound. Per SUSv3 this is not an error condition. | |
1148 | We're faking a valid return value here by creating the | |
1149 | same content in the sockaddr structure as on Linux. */ | |
1150 | switch (get_addr_family ()) | |
510a85cb | 1151 | { |
70e476d2 CV |
1152 | case AF_INET: |
1153 | res = 0; | |
1154 | *namelen = sizeof (struct sockaddr_in); | |
1155 | break; | |
1156 | case AF_INET6: | |
1157 | res = 0; | |
1158 | *namelen = sizeof (struct sockaddr_in6); | |
1159 | break; | |
1160 | default: | |
1161 | WSASetLastError (WSAEOPNOTSUPP); | |
1162 | break; | |
1163 | } | |
1164 | if (!res) | |
510a85cb | 1165 | { |
70e476d2 CV |
1166 | memset (name, 0, *namelen); |
1167 | name->sa_family = get_addr_family (); | |
1168 | } | |
1169 | } | |
1170 | if (res) | |
1171 | set_winsock_errno (); | |
1172 | } | |
be5007aa CV |
1173 | } |
1174 | ||
1175 | return res; | |
1176 | } | |
1177 | ||
1178 | int | |
1179 | fhandler_socket::getpeername (struct sockaddr *name, int *namelen) | |
1180 | { | |
be5007aa CV |
1181 | int res = ::getpeername (get_socket (), name, namelen); |
1182 | if (res) | |
1183 | set_winsock_errno (); | |
1184 | ||
1185 | return res; | |
1186 | } | |
1187 | ||
4d147a03 CV |
1188 | int |
1189 | fhandler_socket::readv (const struct iovec *const iov, const int iovcnt, | |
1190 | ssize_t tot) | |
ff86860b | 1191 | { |
4d147a03 CV |
1192 | struct msghdr msg = |
1193 | { | |
ae799c99 CF |
1194 | msg_name: NULL, |
1195 | msg_namelen: 0, | |
1196 | msg_iov: (struct iovec *) iov, // const_cast | |
1197 | msg_iovlen: iovcnt, | |
8b00a766 CV |
1198 | msg_control: NULL, |
1199 | msg_controllen: 0, | |
1200 | msg_flags: 0 | |
4d147a03 CV |
1201 | }; |
1202 | ||
88386154 | 1203 | return recvmsg (&msg, 0); |
ff86860b | 1204 | } |
fae28904 | 1205 | |
70e476d2 CV |
1206 | inline ssize_t |
1207 | fhandler_socket::recv_internal (WSABUF *wsabuf, DWORD wsacnt, DWORD flags, | |
1208 | struct sockaddr *from, int *fromlen) | |
be5007aa | 1209 | { |
70e476d2 | 1210 | ssize_t res = 0; |
023a2fa7 | 1211 | DWORD ret = 0, wret; |
70e476d2 | 1212 | int evt_mask = FD_READ | ((flags & MSG_OOB) ? FD_OOB : 0); |
be5007aa | 1213 | |
023a2fa7 CV |
1214 | bool waitall = (flags & MSG_WAITALL); |
1215 | flags &= (MSG_OOB | MSG_PEEK | MSG_DONTROUTE); | |
1216 | if (waitall) | |
1217 | { | |
1218 | if (get_socket_type () != SOCK_STREAM) | |
70300fdb | 1219 | { |
023a2fa7 CV |
1220 | WSASetLastError (WSAEOPNOTSUPP); |
1221 | set_winsock_errno (); | |
1222 | return SOCKET_ERROR; | |
1223 | } | |
1224 | if (is_nonblocking () || (flags & (MSG_OOB | MSG_PEEK))) | |
70300fdb | 1225 | waitall = false; |
023a2fa7 CV |
1226 | } |
1227 | ||
1f7dbb01 CV |
1228 | /* Note: Don't call WSARecvFrom(MSG_PEEK) without actually having data |
1229 | waiting in the buffers, otherwise the event handling gets messed up | |
1230 | for some reason. */ | |
b23bc8c3 CV |
1231 | while (!(res = wait_for_events (evt_mask | FD_CLOSE)) |
1232 | || saw_shutdown_read ()) | |
ddd62ccb | 1233 | { |
023a2fa7 | 1234 | res = WSARecvFrom (get_socket (), wsabuf, wsacnt, &wret, |
2f98d8bd | 1235 | &flags, from, fromlen, NULL, NULL); |
023a2fa7 CV |
1236 | if (!res) |
1237 | { | |
1238 | ret += wret; | |
1239 | if (!waitall) | |
1240 | break; | |
1241 | while (wret && wsacnt) | |
1242 | { | |
1243 | if (wsabuf->len > wret) | |
1244 | { | |
1245 | wsabuf->len -= wret; | |
1246 | wsabuf->buf += wret; | |
1247 | wret = 0; | |
1248 | } | |
1249 | else | |
70300fdb | 1250 | { |
023a2fa7 CV |
1251 | wret -= wsabuf->len; |
1252 | ++wsabuf; | |
1253 | --wsacnt; | |
1254 | } | |
1255 | } | |
1256 | if (!wret) | |
1257 | break; | |
1258 | } | |
1259 | else if (WSAGetLastError () != WSAEWOULDBLOCK) | |
1f7dbb01 | 1260 | break; |
be5007aa CV |
1261 | } |
1262 | ||
023a2fa7 | 1263 | if (!ret && res == SOCKET_ERROR) |
4d147a03 | 1264 | { |
f0f3ea68 | 1265 | /* According to SUSv3, errno isn't set in that case and no error |
a113a3c5 | 1266 | condition is returned. */ |
f0f3ea68 | 1267 | if (WSAGetLastError () == WSAEMSGSIZE) |
70e476d2 | 1268 | return ret; |
f0f3ea68 | 1269 | |
6ba3f6bb | 1270 | /* ESHUTDOWN isn't defined for recv in SUSv3. Simply EOF is returned |
de935f6d | 1271 | in this case. */ |
6ba3f6bb | 1272 | if (WSAGetLastError () == WSAESHUTDOWN) |
de935f6d | 1273 | return 0; |
6ba3f6bb | 1274 | |
4d147a03 | 1275 | set_winsock_errno (); |
023a2fa7 | 1276 | return SOCKET_ERROR; |
4d147a03 | 1277 | } |
4d147a03 | 1278 | |
023a2fa7 | 1279 | return ret; |
be5007aa CV |
1280 | } |
1281 | ||
70e476d2 CV |
1282 | int |
1283 | fhandler_socket::recvfrom (void *ptr, size_t len, int flags, | |
1284 | struct sockaddr *from, int *fromlen) | |
1285 | { | |
1286 | WSABUF wsabuf = { len, (char *) ptr }; | |
1287 | return recv_internal (&wsabuf, 1, flags, from, fromlen); | |
1288 | } | |
1289 | ||
be5007aa | 1290 | int |
88386154 | 1291 | fhandler_socket::recvmsg (struct msghdr *msg, int flags) |
be5007aa | 1292 | { |
8b00a766 CV |
1293 | if (CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR) |
1294 | ((struct OLD_msghdr *) msg)->msg_accrightslen = 0; | |
1295 | else | |
1296 | { | |
1297 | msg->msg_controllen = 0; | |
1298 | msg->msg_flags = 0; | |
1299 | } | |
be5007aa CV |
1300 | if (get_addr_family () == AF_LOCAL) |
1301 | { | |
1302 | /* On AF_LOCAL sockets the (fixed-size) name of the shared memory | |
1303 | area used for descriptor passing is transmitted first. | |
1304 | If this string is empty, no descriptors are passed and we can | |
1305 | go ahead recv'ing the normal data blocks. Otherwise start | |
1306 | special handling for descriptor passing. */ | |
1307 | /*TODO*/ | |
1308 | } | |
4d147a03 | 1309 | |
70e476d2 CV |
1310 | WSABUF wsabuf[msg->msg_iovlen]; |
1311 | WSABUF *wsaptr = wsabuf + msg->msg_iovlen; | |
1312 | const struct iovec *iovptr = msg->msg_iov + msg->msg_iovlen; | |
1313 | while (--wsaptr >= wsabuf) | |
8b00a766 | 1314 | { |
70e476d2 | 1315 | wsaptr->len = (--iovptr)->iov_len; |
8b00a766 CV |
1316 | wsaptr->buf = (char *) iovptr->iov_base; |
1317 | } | |
f0f3ea68 | 1318 | |
70e476d2 CV |
1319 | struct sockaddr *from = (struct sockaddr *) msg->msg_name; |
1320 | int *fromlen = from ? &msg->msg_namelen : NULL; | |
4d147a03 | 1321 | |
70e476d2 | 1322 | return recv_internal (wsabuf, msg->msg_iovlen, flags, from, fromlen); |
be5007aa CV |
1323 | } |
1324 | ||
ff86860b | 1325 | int |
4d147a03 CV |
1326 | fhandler_socket::writev (const struct iovec *const iov, const int iovcnt, |
1327 | ssize_t tot) | |
ff86860b | 1328 | { |
4d147a03 CV |
1329 | struct msghdr msg = |
1330 | { | |
1331 | msg_name: NULL, | |
1332 | msg_namelen: 0, | |
1333 | msg_iov: (struct iovec *) iov, // const_cast | |
1334 | msg_iovlen: iovcnt, | |
8b00a766 CV |
1335 | msg_control: NULL, |
1336 | msg_controllen: 0, | |
1337 | msg_flags: 0 | |
4d147a03 CV |
1338 | }; |
1339 | ||
88386154 | 1340 | return sendmsg (&msg, 0); |
ff86860b CV |
1341 | } |
1342 | ||
70e476d2 CV |
1343 | inline ssize_t |
1344 | fhandler_socket::send_internal (struct _WSABUF *wsabuf, DWORD wsacnt, int flags, | |
1345 | const struct sockaddr *to, int tolen) | |
be5007aa | 1346 | { |
70e476d2 CV |
1347 | int res = 0; |
1348 | DWORD ret = 0, err = 0; | |
8b00a766 | 1349 | |
70e476d2 | 1350 | do |
be5007aa | 1351 | { |
70e476d2 | 1352 | if ((res = WSASendTo (get_socket (), wsabuf, wsacnt, &ret, |
023a2fa7 | 1353 | flags & (MSG_OOB | MSG_DONTROUTE), to, tolen, NULL, NULL)) |
70e476d2 | 1354 | && (err = WSAGetLastError ()) == WSAEWOULDBLOCK) |
510a85cb | 1355 | { |
1f7dbb01 CV |
1356 | LOCK_EVENTS; |
1357 | wsock_events->events &= ~FD_WRITE; | |
1358 | UNLOCK_EVENTS; | |
1359 | } | |
be5007aa | 1360 | } |
9869e006 CV |
1361 | while (res && err == WSAEWOULDBLOCK |
1362 | && !(res = wait_for_events (FD_WRITE | FD_CLOSE))); | |
be5007aa | 1363 | |
4d147a03 | 1364 | if (res == SOCKET_ERROR) |
4450172a | 1365 | set_winsock_errno (); |
4d147a03 CV |
1366 | else |
1367 | res = ret; | |
1368 | ||
fa85038b | 1369 | /* Special handling for EPIPE and SIGPIPE. |
df04ae29 | 1370 | |
fa85038b CV |
1371 | EPIPE is generated if the local end has been shut down on a connection |
1372 | oriented socket. In this case the process will also receive a SIGPIPE | |
1373 | unless MSG_NOSIGNAL is set. */ | |
4450172a | 1374 | if (res == SOCKET_ERROR && get_errno () == ESHUTDOWN |
fa85038b | 1375 | && get_socket_type () == SOCK_STREAM) |
281d8a32 CV |
1376 | { |
1377 | set_errno (EPIPE); | |
1378 | if (! (flags & MSG_NOSIGNAL)) | |
818089d9 | 1379 | raise (SIGPIPE); |
281d8a32 | 1380 | } |
4d147a03 | 1381 | |
be5007aa CV |
1382 | return res; |
1383 | } | |
1384 | ||
70e476d2 CV |
1385 | ssize_t |
1386 | fhandler_socket::sendto (const void *ptr, size_t len, int flags, | |
1387 | const struct sockaddr *to, int tolen) | |
1388 | { | |
1389 | struct sockaddr_storage sst; | |
1390 | ||
1391 | if (to && !get_inet_addr (to, tolen, &sst, &tolen)) | |
1392 | return SOCKET_ERROR; | |
1393 | ||
360b05b4 CV |
1394 | /* Never write more than 64K at once to workaround a problem with |
1395 | Winsock, which creates a temporary buffer with the total incoming | |
1396 | buffer size and copies the whole content over, regardless of | |
1397 | the size of the internal send buffer. A buffer full condition | |
1398 | is only recognized in subsequent calls and, if len is big enough, | |
1399 | the call even might fail with an out-of-memory condition. */ | |
1400 | WSABUF wsabuf = { len > 65536 ? 65536 : len, (char *) ptr }; | |
70e476d2 | 1401 | return send_internal (&wsabuf, 1, flags, |
510a85cb | 1402 | (to ? (const struct sockaddr *) &sst : NULL), tolen); |
70e476d2 CV |
1403 | } |
1404 | ||
be5007aa | 1405 | int |
88386154 | 1406 | fhandler_socket::sendmsg (const struct msghdr *msg, int flags) |
be5007aa | 1407 | { |
dcb091ca | 1408 | if (get_addr_family () == AF_LOCAL) |
4d147a03 | 1409 | { |
dcb091ca | 1410 | /* For AF_LOCAL/AF_UNIX sockets, if descriptors are given, start |
4d147a03 CV |
1411 | the special handling for descriptor passing. Otherwise just |
1412 | transmit an empty string to tell the receiver that no | |
1413 | descriptor passing is done. */ | |
dcb091ca | 1414 | /*TODO*/ |
4d147a03 CV |
1415 | } |
1416 | ||
70e476d2 | 1417 | WSABUF wsabuf[msg->msg_iovlen]; |
360b05b4 CV |
1418 | WSABUF *wsaptr = wsabuf; |
1419 | const struct iovec *iovptr = msg->msg_iov; | |
1420 | size_t total = 0; | |
1421 | for (int i = 0; i < msg->msg_iovlen && total < 65536; ++i) | |
8b00a766 | 1422 | { |
360b05b4 CV |
1423 | if (total + iovptr->iov_len > 65536) /* See above. */ |
1424 | wsaptr->len = 65536 - total; | |
1425 | else | |
1426 | wsaptr->len = iovptr->iov_len; | |
1427 | total += wsaptr->len; | |
1428 | (wsaptr++)->buf = (char *) (iovptr++)->iov_base; | |
8b00a766 | 1429 | } |
93ba1204 | 1430 | |
70e476d2 | 1431 | return send_internal (wsabuf, msg->msg_iovlen, flags, |
510a85cb | 1432 | (struct sockaddr *) msg->msg_name, msg->msg_namelen); |
be5007aa CV |
1433 | } |
1434 | ||
1435 | int | |
1436 | fhandler_socket::shutdown (int how) | |
1437 | { | |
1438 | int res = ::shutdown (get_socket (), how); | |
1439 | ||
1440 | if (res) | |
1441 | set_winsock_errno (); | |
1442 | else | |
1443 | switch (how) | |
1444 | { | |
1445 | case SHUT_RD: | |
56551a9b | 1446 | saw_shutdown_read (true); |
be5007aa CV |
1447 | break; |
1448 | case SHUT_WR: | |
56551a9b | 1449 | saw_shutdown_write (true); |
be5007aa CV |
1450 | break; |
1451 | case SHUT_RDWR: | |
56551a9b CV |
1452 | saw_shutdown_read (true); |
1453 | saw_shutdown_write (true); | |
be5007aa CV |
1454 | break; |
1455 | } | |
1456 | return res; | |
1457 | } | |
1458 | ||
afd5033d CV |
1459 | int |
1460 | fhandler_socket::close () | |
1461 | { | |
1462 | int res = 0; | |
be5007aa | 1463 | |
6a574f1a CV |
1464 | /* HACK to allow a graceful shutdown even if shutdown() hasn't been |
1465 | called by the application. Note that this isn't the ultimate | |
1466 | solution but it helps in many cases. */ | |
1467 | struct linger linger; | |
1468 | linger.l_onoff = 1; | |
a6df500f | 1469 | linger.l_linger = 240; /* secs. default 2MSL value according to MSDN. */ |
6a574f1a CV |
1470 | setsockopt (get_socket (), SOL_SOCKET, SO_LINGER, |
1471 | (const char *)&linger, sizeof linger); | |
1472 | ||
70e476d2 | 1473 | release_events (); |
eeac69d8 | 1474 | while ((res = closesocket (get_socket ())) != 0) |
05230a4a | 1475 | { |
eeac69d8 CF |
1476 | if (WSAGetLastError () != WSAEWOULDBLOCK) |
1477 | { | |
1478 | set_winsock_errno (); | |
1479 | res = -1; | |
1480 | break; | |
1481 | } | |
1482 | if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0) | |
1483 | { | |
1484 | set_errno (EINTR); | |
1485 | res = -1; | |
1486 | break; | |
1487 | } | |
1488 | WSASetLastError (0); | |
05230a4a | 1489 | } |
afd5033d | 1490 | |
6a574f1a | 1491 | debug_printf ("%d = fhandler_socket::close()", res); |
afd5033d CV |
1492 | return res; |
1493 | } | |
1494 | ||
bff43891 CV |
1495 | /* Definitions of old ifreq stuff used prior to Cygwin 1.7.0. */ |
1496 | #define OLD_SIOCGIFFLAGS _IOW('s', 101, struct __old_ifreq) | |
1497 | #define OLD_SIOCGIFADDR _IOW('s', 102, struct __old_ifreq) | |
1498 | #define OLD_SIOCGIFBRDADDR _IOW('s', 103, struct __old_ifreq) | |
1499 | #define OLD_SIOCGIFNETMASK _IOW('s', 104, struct __old_ifreq) | |
1500 | #define OLD_SIOCGIFHWADDR _IOW('s', 105, struct __old_ifreq) | |
1501 | #define OLD_SIOCGIFMETRIC _IOW('s', 106, struct __old_ifreq) | |
1502 | #define OLD_SIOCGIFMTU _IOW('s', 107, struct __old_ifreq) | |
1503 | #define OLD_SIOCGIFINDEX _IOW('s', 108, struct __old_ifreq) | |
1504 | ||
1505 | #define CONV_OLD_TO_NEW_SIO(old) (((old)&0xff00ffff)|(((long)sizeof(struct ifreq)&IOCPARM_MASK)<<16)) | |
1506 | ||
1507 | struct __old_ifreq { | |
1508 | #define __OLD_IFNAMSIZ 16 | |
1509 | union { | |
1510 | char ifrn_name[__OLD_IFNAMSIZ]; /* if name, e.g. "en0" */ | |
1511 | } ifr_ifrn; | |
1512 | ||
1513 | union { | |
1514 | struct sockaddr ifru_addr; | |
1515 | struct sockaddr ifru_broadaddr; | |
1516 | struct sockaddr ifru_netmask; | |
1517 | struct sockaddr ifru_hwaddr; | |
1518 | short ifru_flags; | |
1519 | int ifru_metric; | |
1520 | int ifru_mtu; | |
1521 | int ifru_ifindex; | |
1522 | } ifr_ifru; | |
1523 | }; | |
1524 | ||
afd5033d CV |
1525 | int |
1526 | fhandler_socket::ioctl (unsigned int cmd, void *p) | |
1527 | { | |
a71ecb55 | 1528 | extern int get_ifconf (struct ifconf *ifc, int what); /* net.cc */ |
afd5033d | 1529 | int res; |
9182099c | 1530 | struct ifconf ifc, *ifcp; |
bff43891 | 1531 | struct ifreq *ifrp; |
be5007aa | 1532 | |
afd5033d CV |
1533 | switch (cmd) |
1534 | { | |
1535 | case SIOCGIFCONF: | |
9182099c CV |
1536 | ifcp = (struct ifconf *) p; |
1537 | if (!ifcp) | |
afd5033d CV |
1538 | { |
1539 | set_errno (EINVAL); | |
1540 | return -1; | |
1541 | } | |
bff43891 CV |
1542 | if (CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ) |
1543 | { | |
1544 | ifc.ifc_len = ifcp->ifc_len / sizeof (struct __old_ifreq) | |
510a85cb | 1545 | * sizeof (struct ifreq); |
bff43891 CV |
1546 | ifc.ifc_buf = (caddr_t) alloca (ifc.ifc_len); |
1547 | } | |
1548 | else | |
510a85cb | 1549 | { |
bff43891 CV |
1550 | ifc.ifc_len = ifcp->ifc_len; |
1551 | ifc.ifc_buf = ifcp->ifc_buf; | |
1552 | } | |
a71ecb55 | 1553 | res = get_ifconf (&ifc, cmd); |
afd5033d | 1554 | if (res) |
f70389b5 | 1555 | debug_printf ("error in get_ifconf"); |
bff43891 | 1556 | if (CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ) |
510a85cb | 1557 | { |
bff43891 CV |
1558 | struct __old_ifreq *ifr = (struct __old_ifreq *) ifcp->ifc_buf; |
1559 | for (ifrp = ifc.ifc_req; | |
1560 | (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len; | |
1561 | ++ifrp, ++ifr) | |
1562 | { | |
1563 | memcpy (&ifr->ifr_ifrn, &ifrp->ifr_ifrn, sizeof ifr->ifr_ifrn); | |
1564 | ifr->ifr_name[__OLD_IFNAMSIZ - 1] = '\0'; | |
1565 | memcpy (&ifr->ifr_ifru, &ifrp->ifr_ifru, sizeof ifr->ifr_ifru); | |
1566 | } | |
1567 | ifcp->ifc_len = ifc.ifc_len / sizeof (struct ifreq) | |
1568 | * sizeof (struct __old_ifreq); | |
1569 | } | |
1570 | else | |
510a85cb | 1571 | ifcp->ifc_len = ifc.ifc_len; |
afd5033d | 1572 | break; |
bff43891 CV |
1573 | case OLD_SIOCGIFFLAGS: |
1574 | case OLD_SIOCGIFADDR: | |
1575 | case OLD_SIOCGIFBRDADDR: | |
1576 | case OLD_SIOCGIFNETMASK: | |
1577 | case OLD_SIOCGIFHWADDR: | |
1578 | case OLD_SIOCGIFMETRIC: | |
1579 | case OLD_SIOCGIFMTU: | |
1580 | case OLD_SIOCGIFINDEX: | |
1581 | cmd = CONV_OLD_TO_NEW_SIO (cmd); | |
1582 | /*FALLTHRU*/ | |
afd5033d | 1583 | case SIOCGIFFLAGS: |
afd5033d CV |
1584 | case SIOCGIFBRDADDR: |
1585 | case SIOCGIFNETMASK: | |
1586 | case SIOCGIFADDR: | |
9182099c CV |
1587 | case SIOCGIFHWADDR: |
1588 | case SIOCGIFMETRIC: | |
1589 | case SIOCGIFMTU: | |
835fc32a | 1590 | case SIOCGIFINDEX: |
bff43891 | 1591 | case SIOCGIFFRNDLYNAM: |
8e4a60b3 | 1592 | case SIOCGIFDSTADDR: |
afd5033d | 1593 | { |
bff43891 | 1594 | if (!p) |
afd5033d | 1595 | { |
f70389b5 | 1596 | debug_printf ("ifr == NULL"); |
afd5033d CV |
1597 | set_errno (EINVAL); |
1598 | return -1; | |
1599 | } | |
1600 | ||
bff43891 CV |
1601 | if (cmd > SIOCGIFINDEX && CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ) |
1602 | { | |
1603 | debug_printf ("cmd not supported on this platform"); | |
1604 | set_errno (EINVAL); | |
1605 | return -1; | |
1606 | } | |
1607 | ifc.ifc_len = 64 * sizeof (struct ifreq); | |
1608 | ifc.ifc_buf = (caddr_t) alloca (ifc.ifc_len); | |
1609 | if (cmd == SIOCGIFFRNDLYNAM) | |
1610 | { | |
1611 | struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *) | |
510a85cb | 1612 | alloca (64 * sizeof (struct ifreq_frndlyname)); |
bff43891 CV |
1613 | for (int i = 0; i < 64; ++i) |
1614 | ifc.ifc_req[i].ifr_frndlyname = &iff[i]; | |
1615 | } | |
1616 | ||
a71ecb55 | 1617 | res = get_ifconf (&ifc, cmd); |
afd5033d CV |
1618 | if (res) |
1619 | { | |
f70389b5 | 1620 | debug_printf ("error in get_ifconf"); |
afd5033d CV |
1621 | break; |
1622 | } | |
1623 | ||
bff43891 | 1624 | if (CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ) |
afd5033d | 1625 | { |
bff43891 CV |
1626 | struct __old_ifreq *ifr = (struct __old_ifreq *) p; |
1627 | debug_printf (" name: %s", ifr->ifr_name); | |
1628 | for (ifrp = ifc.ifc_req; | |
1629 | (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len; | |
1630 | ++ifrp) | |
afd5033d | 1631 | { |
bff43891 CV |
1632 | debug_printf ("testname: %s", ifrp->ifr_name); |
1633 | if (! strcmp (ifrp->ifr_name, ifr->ifr_name)) | |
afd5033d | 1634 | { |
bff43891 CV |
1635 | memcpy (&ifr->ifr_ifru, &ifrp->ifr_ifru, |
1636 | sizeof ifr->ifr_ifru); | |
9182099c | 1637 | break; |
bff43891 CV |
1638 | } |
1639 | } | |
1640 | } | |
1641 | else | |
1642 | { | |
1643 | struct ifreq *ifr = (struct ifreq *) p; | |
1644 | debug_printf (" name: %s", ifr->ifr_name); | |
1645 | for (ifrp = ifc.ifc_req; | |
1646 | (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len; | |
1647 | ++ifrp) | |
1648 | { | |
1649 | debug_printf ("testname: %s", ifrp->ifr_name); | |
1650 | if (! strcmp (ifrp->ifr_name, ifr->ifr_name)) | |
1651 | { | |
1652 | if (cmd == SIOCGIFFRNDLYNAM) | |
1653 | /* The application has to care for the space. */ | |
1654 | memcpy (ifr->ifr_frndlyname, ifrp->ifr_frndlyname, | |
1655 | sizeof (struct ifreq_frndlyname)); | |
1656 | else | |
1657 | memcpy (&ifr->ifr_ifru, &ifrp->ifr_ifru, | |
1658 | sizeof ifr->ifr_ifru); | |
835fc32a | 1659 | break; |
afd5033d | 1660 | } |
afd5033d CV |
1661 | } |
1662 | } | |
1663 | if ((caddr_t) ifrp >= ifc.ifc_buf + ifc.ifc_len) | |
1664 | { | |
1665 | set_errno (EINVAL); | |
1666 | return -1; | |
1667 | } | |
1668 | break; | |
1669 | } | |
1670 | case FIOASYNC: | |
0c565ab3 | 1671 | res = WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, |
afd5033d CV |
1672 | *(int *) p ? ASYNC_MASK : 0); |
1673 | syscall_printf ("Async I/O on socket %s", | |
1674 | *(int *) p ? "started" : "cancelled"); | |
56551a9b | 1675 | async_io (*(int *) p != 0); |
70e476d2 CV |
1676 | /* If async_io is switched off, revert the event handling. */ |
1677 | if (*(int *) p == 0) | |
510a85cb | 1678 | WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK); |
afd5033d | 1679 | break; |
9ec70d20 CV |
1680 | case FIONREAD: |
1681 | res = ioctlsocket (get_socket (), FIONREAD, (unsigned long *) p); | |
1682 | if (res == SOCKET_ERROR) | |
e3778517 | 1683 | set_winsock_errno (); |
9ec70d20 | 1684 | break; |
afd5033d | 1685 | default: |
70e476d2 | 1686 | /* Sockets are always non-blocking internally. So we just note the |
510a85cb | 1687 | state here. */ |
afd5033d CV |
1688 | if (cmd == FIONBIO) |
1689 | { | |
70e476d2 CV |
1690 | syscall_printf ("socket is now %sblocking", |
1691 | *(int *) p ? "non" : ""); | |
1692 | set_nonblocking (*(int *) p); | |
1693 | res = 0; | |
510a85cb | 1694 | } |
70e476d2 CV |
1695 | else |
1696 | res = ioctlsocket (get_socket (), cmd, (unsigned long *) p); | |
afd5033d CV |
1697 | break; |
1698 | } | |
1699 | syscall_printf ("%d = ioctl_socket (%x, %x)", res, cmd, p); | |
1700 | return res; | |
1701 | } | |
1702 | ||
1703 | int | |
1704 | fhandler_socket::fcntl (int cmd, void *arg) | |
1705 | { | |
1706 | int res = 0; | |
1707 | int request, current; | |
1708 | ||
1709 | switch (cmd) | |
1710 | { | |
75b5f30f CV |
1711 | case F_SETOWN: |
1712 | { | |
75b5f30f | 1713 | pid_t pid = (pid_t) arg; |
70e476d2 CV |
1714 | LOCK_EVENTS; |
1715 | wsock_events->owner = pid; | |
1716 | UNLOCK_EVENTS; | |
1717 | debug_printf ("owner set to %d", pid); | |
75b5f30f CV |
1718 | } |
1719 | break; | |
70e476d2 CV |
1720 | case F_GETOWN: |
1721 | res = wsock_events->owner; | |
1722 | break; | |
afd5033d CV |
1723 | case F_SETFL: |
1724 | { | |
1ff9f4b9 | 1725 | /* Carefully test for the O_NONBLOCK or deprecated OLD_O_NDELAY flag. |
96a3f4ae CF |
1726 | Set only the flag that has been passed in. If both are set, just |
1727 | record O_NONBLOCK. */ | |
6a574f1a | 1728 | int new_flags = (int) arg & O_NONBLOCK_MASK; |
96a3f4ae CF |
1729 | if ((new_flags & OLD_O_NDELAY) && (new_flags & O_NONBLOCK)) |
1730 | new_flags = O_NONBLOCK; | |
1ff9f4b9 | 1731 | current = get_flags () & O_NONBLOCK_MASK; |
6a574f1a | 1732 | request = new_flags ? 1 : 0; |
1ff9f4b9 CF |
1733 | if (!!current != !!new_flags && (res = ioctl (FIONBIO, &request))) |
1734 | break; | |
6a574f1a | 1735 | set_flags ((get_flags () & ~O_NONBLOCK_MASK) | new_flags); |
1ff9f4b9 | 1736 | break; |
afd5033d CV |
1737 | } |
1738 | default: | |
1739 | res = fhandler_base::fcntl (cmd, arg); | |
1740 | break; | |
1741 | } | |
1742 | return res; | |
1743 | } | |
1744 | ||
50b12648 | 1745 | void |
56551a9b | 1746 | fhandler_socket::set_close_on_exec (bool val) |
50b12648 | 1747 | { |
70e476d2 CV |
1748 | set_no_inheritance (wsock_mtx, val); |
1749 | set_no_inheritance (wsock_evt, val); | |
9869e006 | 1750 | fhandler_base::set_close_on_exec (val); |
50b12648 CV |
1751 | debug_printf ("set close_on_exec for %s to %d", get_name (), val); |
1752 | } | |
2fe27909 CV |
1753 | |
1754 | void | |
1755 | fhandler_socket::set_sun_path (const char *path) | |
1756 | { | |
5cff62d6 | 1757 | sun_path = path ? cstrdup (path) : NULL; |
2fe27909 | 1758 | } |
c8b404bf CV |
1759 | |
1760 | int | |
1761 | fhandler_socket::getpeereid (pid_t *pid, __uid32_t *euid, __gid32_t *egid) | |
1762 | { | |
ef82f76c CV |
1763 | if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM) |
1764 | { | |
1765 | set_errno (EINVAL); | |
1766 | return -1; | |
1767 | } | |
1768 | if (connect_state () != connected) | |
c8b404bf | 1769 | { |
c8b404bf | 1770 | set_errno (ENOTCONN); |
ef82f76c | 1771 | return -1; |
c8b404bf | 1772 | } |
ef82f76c CV |
1773 | if (sec_peer_pid == (pid_t) 0) |
1774 | { | |
1775 | set_errno (ENOTCONN); /* Usually when calling getpeereid on | |
05726ddd | 1776 | accepting (instead of accepted) socket. */ |
ef82f76c CV |
1777 | return -1; |
1778 | } | |
1779 | ||
893ac8e0 CF |
1780 | myfault efault; |
1781 | if (efault.faulted (EFAULT)) | |
1782 | return -1; | |
1783 | if (pid) | |
ef82f76c | 1784 | *pid = sec_peer_pid; |
893ac8e0 | 1785 | if (euid) |
ef82f76c | 1786 | *euid = sec_peer_uid; |
893ac8e0 | 1787 | if (egid) |
ef82f76c CV |
1788 | *egid = sec_peer_gid; |
1789 | return 0; | |
c8b404bf | 1790 | } |