]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/fhandler_socket.cc
* fhandler.cc (fhandler_base::fcntl): Use new O_NONBLOCK_MASK define.
[newlib-cygwin.git] / winsup / cygwin / fhandler_socket.cc
1 /* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes.
2
3 Copyright 2000, 2001 Red Hat, Inc.
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
15 #include "winsup.h"
16 #include <errno.h>
17 #include <sys/socket.h>
18 #include <asm/byteorder.h>
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #define USE_SYS_TYPES_FD_SET
24 #include <winsock2.h>
25 #include "cygerrno.h"
26 #include "security.h"
27 #include "cygwin/version.h"
28 #include "perprocess.h"
29 #include "fhandler.h"
30 #include "dtable.h"
31 #include "cygheap.h"
32 #include "sigproc.h"
33
34 #define SECRET_EVENT_NAME "cygwin.local_socket.secret.%d.%08x-%08x-%08x-%08x"
35 #define ENTROPY_SOURCE_NAME "/dev/urandom"
36 #define ENTROPY_SOURCE_DEV_UNIT 9
37
38 fhandler_dev_random* entropy_source = NULL;
39
40 /**********************************************************************/
41 /* fhandler_socket */
42
43 fhandler_socket::fhandler_socket (const char *name) :
44 fhandler_base (FH_SOCKET, name)
45 {
46 set_cb (sizeof *this);
47 set_need_fork_fixup ();
48 prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF,
49 sizeof (WSAPROTOCOL_INFOA));
50 }
51
52 fhandler_socket::~fhandler_socket ()
53 {
54 if (prot_info_ptr)
55 cfree (prot_info_ptr);
56 }
57
58 void
59 fhandler_socket::set_connect_secret ()
60 {
61 if (!entropy_source)
62 {
63 void *buf = malloc (sizeof (fhandler_dev_random));
64 entropy_source = new (buf) fhandler_dev_random (ENTROPY_SOURCE_NAME,
65 ENTROPY_SOURCE_DEV_UNIT);
66 }
67 if (entropy_source &&
68 !entropy_source->open (ENTROPY_SOURCE_NAME, O_RDONLY))
69 {
70 delete entropy_source;
71 entropy_source = NULL;
72 }
73 if (!entropy_source ||
74 (entropy_source->read (connect_secret, sizeof (connect_secret)) !=
75 sizeof (connect_secret)))
76 bzero ((char*) connect_secret, sizeof (connect_secret));
77 }
78
79 void
80 fhandler_socket::get_connect_secret (char* buf)
81 {
82 __small_sprintf (buf, "%08x-%08x-%08x-%08x",
83 connect_secret [0], connect_secret [1],
84 connect_secret [2], connect_secret [3]);
85 }
86
87 HANDLE
88 fhandler_socket::create_secret_event (int* secret)
89 {
90 char buf [128];
91 int* secret_ptr = (secret ? : connect_secret);
92 struct sockaddr_in sin;
93 int sin_len = sizeof (sin);
94
95 if (getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))
96 {
97 debug_printf ("error getting local socket name (%d)", WSAGetLastError ());
98 return NULL;
99 }
100
101 __small_sprintf (buf, SECRET_EVENT_NAME, sin.sin_port,
102 secret_ptr [0], secret_ptr [1],
103 secret_ptr [2], secret_ptr [3]);
104 secret_event = CreateEvent (get_inheritance (), FALSE, FALSE, buf);
105 if (!secret_event && GetLastError () == ERROR_ALREADY_EXISTS)
106 secret_event = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
107
108 if (secret_event)
109 ProtectHandle (secret_event);
110
111 return secret_event;
112 }
113
114 void
115 fhandler_socket::signal_secret_event ()
116 {
117 if (secret_event)
118 SetEvent (secret_event);
119 }
120
121 void
122 fhandler_socket::close_secret_event ()
123 {
124 if (secret_event)
125 ForceCloseHandle (secret_event);
126 secret_event = NULL;
127 }
128
129 int
130 fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
131 {
132 char buf [128];
133 HANDLE ev;
134 int* secret_ptr = (secret ? : connect_secret);
135
136 __small_sprintf (buf, SECRET_EVENT_NAME, peer->sin_port,
137 secret_ptr [0], secret_ptr [1],
138 secret_ptr [2], secret_ptr [3]);
139 ev = CreateEvent (&sec_none_nih, FALSE, FALSE, buf);
140 if (!ev && GetLastError () == ERROR_ALREADY_EXISTS)
141 {
142 debug_printf ("%s event already exist");
143 ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
144 }
145
146 signal_secret_event ();
147
148 if (ev)
149 {
150 DWORD rc = WaitForSingleObject (ev, 10000);
151 debug_printf ("WFSO rc=%d", rc);
152 CloseHandle (ev);
153 return (rc == WAIT_OBJECT_0 ? 1 : 0 );
154 }
155 else
156 return 0;
157 }
158
159 void
160 fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
161 {
162 int ret = 1;
163
164 if (prot_info_ptr &&
165 (ret = WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr)))
166 {
167 debug_printf ("WSADuplicateSocket error");
168 set_winsock_errno ();
169 }
170 if (!ret && ws2_32_handle)
171 {
172 debug_printf ("WSADuplicateSocket went fine, dwServiceFlags1=%d",
173 prot_info_ptr->dwServiceFlags1);
174 }
175 else
176 {
177 fhandler_base::fixup_before_fork_exec (win_proc_id);
178 debug_printf ("Without Winsock 2.0");
179 }
180 }
181
182 void
183 fhandler_socket::fixup_after_fork (HANDLE parent)
184 {
185 SOCKET new_sock = INVALID_SOCKET;
186
187 debug_printf ("WSASocket begin, dwServiceFlags1=%d",
188 prot_info_ptr->dwServiceFlags1);
189 if (prot_info_ptr &&
190 (new_sock = WSASocketA (FROM_PROTOCOL_INFO,
191 FROM_PROTOCOL_INFO,
192 FROM_PROTOCOL_INFO,
193 prot_info_ptr, 0, 0)) == INVALID_SOCKET)
194 {
195 debug_printf ("WSASocket error");
196 set_winsock_errno ();
197 }
198 if (new_sock != INVALID_SOCKET && ws2_32_handle)
199 {
200 debug_printf ("WSASocket went fine");
201 set_io_handle ((HANDLE) new_sock);
202 }
203 else
204 {
205 fhandler_base::fixup_after_fork (parent);
206 debug_printf ("Without Winsock 2.0");
207 }
208 if (secret_event)
209 fork_fixup (parent, secret_event, "secret_event");
210 }
211
212 int
213 fhandler_socket::dup (fhandler_base *child)
214 {
215 fhandler_socket *fhs = (fhandler_socket *) child;
216 fhs->addr_family = addr_family;
217 fhs->set_io_handle (get_io_handle ());
218 fhs->fixup_before_fork_exec (GetCurrentProcessId ());
219 if (ws2_32_handle)
220 {
221 fhs->fixup_after_fork (hMainProc);
222 return 0;
223 }
224 return fhandler_base::dup (child);
225 }
226
227 int
228 fhandler_socket::read (void *ptr, size_t len)
229 {
230 sigframe thisframe (mainthread);
231 int res = recv (get_socket (), (char *) ptr, len, 0);
232 if (res == SOCKET_ERROR)
233 {
234 set_winsock_errno ();
235 }
236 return res;
237 }
238
239 int
240 fhandler_socket::write (const void *ptr, size_t len)
241 {
242 sigframe thisframe (mainthread);
243 int res = send (get_socket (), (const char *) ptr, len, 0);
244 if (res == SOCKET_ERROR)
245 {
246 set_winsock_errno ();
247 if (get_errno () == ECONNABORTED || get_errno () == ECONNRESET)
248 _raise (SIGPIPE);
249 }
250 return res;
251 }
252
253 /* Cygwin internal */
254 int
255 fhandler_socket::close ()
256 {
257 int res = 0;
258 sigframe thisframe (mainthread);
259
260 /* HACK to allow a graceful shutdown even if shutdown() hasn't been
261 called by the application. Note that this isn't the ultimate
262 solution but it helps in many cases. */
263 struct linger linger;
264 linger.l_onoff = 1;
265 linger.l_linger = 60; /* seconds. 2MSL according to BSD implementation. */
266 setsockopt (get_socket (), SOL_SOCKET, SO_LINGER,
267 (const char *)&linger, sizeof linger);
268
269 if (closesocket (get_socket ()))
270 {
271 set_winsock_errno ();
272 res = -1;
273 }
274
275 close_secret_event ();
276
277 debug_printf ("%d = fhandler_socket::close()", res);
278 return res;
279 }
280
281 #define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
282
283 /* Cygwin internal */
284 int
285 fhandler_socket::ioctl (unsigned int cmd, void *p)
286 {
287 extern int get_ifconf (struct ifconf *ifc, int what); /* net.cc */
288 int res;
289 struct ifconf ifc, *ifcp;
290 struct ifreq *ifr, *ifrp;
291 sigframe thisframe (mainthread);
292
293 switch (cmd)
294 {
295 case SIOCGIFCONF:
296 ifcp = (struct ifconf *) p;
297 if (!ifcp)
298 {
299 set_errno (EINVAL);
300 return -1;
301 }
302 res = get_ifconf (ifcp, cmd);
303 if (res)
304 debug_printf ("error in get_ifconf\n");
305 break;
306 case SIOCGIFFLAGS:
307 ifr = (struct ifreq *) p;
308 if (ifr == 0)
309 {
310 set_errno (EINVAL);
311 return -1;
312 }
313 ifr->ifr_flags = IFF_NOTRAILERS | IFF_UP | IFF_RUNNING;
314 if (ntohl (((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr)
315 == INADDR_LOOPBACK)
316 ifr->ifr_flags |= IFF_LOOPBACK;
317 else
318 ifr->ifr_flags |= IFF_BROADCAST;
319 res = 0;
320 break;
321 case SIOCGIFBRDADDR:
322 case SIOCGIFNETMASK:
323 case SIOCGIFADDR:
324 case SIOCGIFHWADDR:
325 case SIOCGIFMETRIC:
326 case SIOCGIFMTU:
327 {
328 ifc.ifc_len = 2048;
329 ifc.ifc_buf = (char *) alloca (2048);
330
331 ifr = (struct ifreq *) p;
332 if (ifr == 0)
333 {
334 debug_printf ("ifr == NULL\n");
335 set_errno (EINVAL);
336 return -1;
337 }
338
339 res = get_ifconf (&ifc, cmd);
340 if (res)
341 {
342 debug_printf ("error in get_ifconf\n");
343 break;
344 }
345
346 debug_printf (" name: %s\n", ifr->ifr_name);
347 for (ifrp = ifc.ifc_req;
348 (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len;
349 ++ifrp)
350 {
351 debug_printf ("testname: %s\n", ifrp->ifr_name);
352 if (! strcmp (ifrp->ifr_name, ifr->ifr_name))
353 {
354 switch (cmd)
355 {
356 case SIOCGIFADDR:
357 ifr->ifr_addr = ifrp->ifr_addr;
358 break;
359 case SIOCGIFBRDADDR:
360 ifr->ifr_broadaddr = ifrp->ifr_broadaddr;
361 break;
362 case SIOCGIFNETMASK:
363 ifr->ifr_netmask = ifrp->ifr_netmask;
364 break;
365 case SIOCGIFHWADDR:
366 ifr->ifr_hwaddr = ifrp->ifr_hwaddr;
367 break;
368 case SIOCGIFMETRIC:
369 ifr->ifr_metric = ifrp->ifr_metric;
370 break;
371 case SIOCGIFMTU:
372 ifr->ifr_mtu = ifrp->ifr_mtu;
373 break;
374 }
375 break;
376 }
377 }
378 if ((caddr_t) ifrp >= ifc.ifc_buf + ifc.ifc_len)
379 {
380 set_errno (EINVAL);
381 return -1;
382 }
383 break;
384 }
385 case FIOASYNC:
386 res = WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO,
387 *(int *) p ? ASYNC_MASK : 0);
388 syscall_printf ("Async I/O on socket %s",
389 *(int *) p ? "started" : "cancelled");
390 set_async (*(int *) p);
391 break;
392 default:
393 /* We must cancel WSAAsyncSelect (if any) before setting socket to
394 * blocking mode
395 */
396 if (cmd == FIONBIO && *(int *) p == 0)
397 WSAAsyncSelect (get_socket (), gethwnd (), 0, 0);
398 res = ioctlsocket (get_socket (), cmd, (unsigned long *) p);
399 if (res == SOCKET_ERROR)
400 set_winsock_errno ();
401 if (cmd == FIONBIO)
402 {
403 syscall_printf ("socket is now %sblocking",
404 *(int *) p ? "un" : "");
405 /* Start AsyncSelect if async socket unblocked */
406 if (*(int *) p && get_async ())
407 WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO, ASYNC_MASK);
408
409 int current = get_flags () & O_NONBLOCK_MASK;
410 int new_flags = *(int *) p ? (!current ? O_NONBLOCK : current) : 0;
411 set_flags ((get_flags () & ~O_NONBLOCK_MASK) | new_flags);
412 }
413 break;
414 }
415 syscall_printf ("%d = ioctl_socket (%x, %x)", res, cmd, p);
416 return res;
417 }
418
419 int
420 fhandler_socket::fcntl (int cmd, void *arg)
421 {
422 int res = 0;
423 int request, current;
424
425 switch (cmd)
426 {
427 case F_SETFL:
428 {
429 /* Carefully test for the O_NONBLOCK or deprecated OLD_O_NDELAY flag.
430 Set only the flag that has been passed in. If both are set, just
431 record O_NONBLOCK. */
432 int new_flags = (int) arg & O_NONBLOCK_MASK;
433 if ((new_flags & OLD_O_NDELAY) && (new_flags & O_NONBLOCK))
434 new_flags = O_NONBLOCK;
435 current = get_flags () & O_NONBLOCK_MASK;
436 request = new_flags ? 1 : 0;
437 if (!!current != !!new_flags && (res = ioctl (FIONBIO, &request)))
438 break;
439 set_flags ((get_flags () & ~O_NONBLOCK_MASK) | new_flags);
440 break;
441 }
442 default:
443 res = fhandler_base::fcntl (cmd, arg);
444 break;
445 }
446 return res;
447 }
448
449 void
450 fhandler_socket::set_close_on_exec (int val)
451 {
452 extern WSADATA wsadata;
453 if (wsadata.wVersion < 512) /* < Winsock 2.0 */
454 set_inheritance (get_handle (), val);
455 set_close_on_exec_flag (val);
456 debug_printf ("set close_on_exec for %s to %d", get_name (), val);
457 }
This page took 0.055385 seconds and 5 git commands to generate.