]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/fhandler_socket.cc
Remove unneeded header files from source files throughout.
[newlib-cygwin.git] / winsup / cygwin / fhandler_socket.cc
CommitLineData
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 43extern bool fdsock (cygheap_fdmanip& fd, const device *, SOCKET soc);
be5007aa
CV
44extern "C" {
45int sscanf (const char *, const char *, ...);
46} /* End of "C" section */
47
08b78edf 48fhandler_dev_random* entropy_source;
619f7fa0 49
f9a963b8
CV
50static inline mode_t
51adjust_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 */
63static int
64get_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
148fhandler_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
159fhandler_socket::~fhandler_socket ()
160{
2fe27909
CV
161 if (sun_path)
162 cfree (sun_path);
afd5033d
CV
163}
164
b832c4cf
CV
165char *
166fhandler_socket::get_proc_fd_name (char *buf)
167{
168 __small_sprintf (buf, "socket:[%d]", get_socket ());
169 return buf;
170}
171
172int
173fhandler_socket::open (int flags, mode_t mode)
174{
175 set_errno (ENXIO);
176 return 0;
177}
178
ef82f76c 179void
2f9ae2ed 180fhandler_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
187void
b832c4cf 188fhandler_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
201void
b832c4cf 202fhandler_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
213bool
2f9ae2ed 214fhandler_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
243bool
2f9ae2ed 244fhandler_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
261bool
2f9ae2ed 262fhandler_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
288bool
2f9ae2ed 289fhandler_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 *) &in;
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 309int
2f9ae2ed 310fhandler_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 331int
2f9ae2ed 332fhandler_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 350void
2f9ae2ed 351fhandler_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
361void
362fhandler_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 376void
b832c4cf 377fhandler_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
411static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared)) = { 0 };
412
413static LONG socket_serial_number __attribute__((section (".cygwin_dll_common"), shared)) = 0;
414
415static HANDLE wsa_slot_mtx;
416
417static wsa_event *
418search_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
463bool
464fhandler_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
512int
513fhandler_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
560int
561fhandler_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
602void
603fhandler_socket::release_events ()
604{
605 CloseHandle (wsock_evt);
606 CloseHandle (wsock_mtx);
607}
608
afd5033d 609void
3d78e129 610fhandler_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 617int
dcb091ca 618fhandler_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 663int __stdcall
7ac61736 664fhandler_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
688int __stdcall
689fhandler_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
701int
702fhandler_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
715int
716fhandler_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
727int
728fhandler_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
739int
740fhandler_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
750static inline bool
751address_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
773int
774fhandler_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
919out:
920 return res;
921}
922
923int
924fhandler_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
993int
994fhandler_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
1039int
1040fhandler_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 1109out:
7ac61736 1110 debug_printf ("res %d", res);
be5007aa
CV
1111 return res;
1112}
1113
1114int
1115fhandler_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
1178int
1179fhandler_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
1188int
1189fhandler_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
1206inline ssize_t
1207fhandler_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
1282int
1283fhandler_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 1290int
88386154 1291fhandler_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 1325int
4d147a03
CV
1326fhandler_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
1343inline ssize_t
1344fhandler_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
1385ssize_t
1386fhandler_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 1405int
88386154 1406fhandler_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
1435int
1436fhandler_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
1459int
1460fhandler_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
1507struct __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
1525int
1526fhandler_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
1703int
1704fhandler_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 1745void
56551a9b 1746fhandler_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
1754void
1755fhandler_socket::set_sun_path (const char *path)
1756{
5cff62d6 1757 sun_path = path ? cstrdup (path) : NULL;
2fe27909 1758}
c8b404bf
CV
1759
1760int
1761fhandler_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}
This page took 0.50185 seconds and 5 git commands to generate.