xref: /libev/ev_win32.c (revision 93823e6c)
1e3a38431SPaul Bohm /*
2e3a38431SPaul Bohm  * libev win32 compatibility cruft (_not_ a backend)
3e3a38431SPaul Bohm  *
4e3a38431SPaul Bohm  * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <[email protected]>
5e3a38431SPaul Bohm  * All rights reserved.
6e3a38431SPaul Bohm  *
7e3a38431SPaul Bohm  * Redistribution and use in source and binary forms, with or without modifica-
8e3a38431SPaul Bohm  * tion, are permitted provided that the following conditions are met:
9e3a38431SPaul Bohm  *
10e3a38431SPaul Bohm  *   1.  Redistributions of source code must retain the above copyright notice,
11e3a38431SPaul Bohm  *       this list of conditions and the following disclaimer.
12e3a38431SPaul Bohm  *
13e3a38431SPaul Bohm  *   2.  Redistributions in binary form must reproduce the above copyright
14e3a38431SPaul Bohm  *       notice, this list of conditions and the following disclaimer in the
15e3a38431SPaul Bohm  *       documentation and/or other materials provided with the distribution.
16e3a38431SPaul Bohm  *
17e3a38431SPaul Bohm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18e3a38431SPaul Bohm  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19e3a38431SPaul Bohm  * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
20e3a38431SPaul Bohm  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21e3a38431SPaul Bohm  * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22e3a38431SPaul Bohm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23e3a38431SPaul Bohm  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24e3a38431SPaul Bohm  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25e3a38431SPaul Bohm  * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26e3a38431SPaul Bohm  * OF THE POSSIBILITY OF SUCH DAMAGE.
27e3a38431SPaul Bohm  *
28e3a38431SPaul Bohm  * Alternatively, the contents of this file may be used under the terms of
29e3a38431SPaul Bohm  * the GNU General Public License ("GPL") version 2 or any later version,
30e3a38431SPaul Bohm  * in which case the provisions of the GPL are applicable instead of
31e3a38431SPaul Bohm  * the above. If you wish to allow the use of your version of this file
32e3a38431SPaul Bohm  * only under the terms of the GPL and not to allow others to use your
33e3a38431SPaul Bohm  * version of this file under the BSD license, indicate your decision
34e3a38431SPaul Bohm  * by deleting the provisions above and replace them with the notice
35e3a38431SPaul Bohm  * and other provisions required by the GPL. If you do not delete the
36e3a38431SPaul Bohm  * provisions above, a recipient may use your version of this file under
37e3a38431SPaul Bohm  * either the BSD or the GPL.
38e3a38431SPaul Bohm  */
39e3a38431SPaul Bohm 
40e3a38431SPaul Bohm #ifdef _WIN32
41e3a38431SPaul Bohm 
42e3a38431SPaul Bohm /* note: the comment below could not be substantiated, but what would I care */
43e3a38431SPaul Bohm /* MSDN says this is required to handle SIGFPE */
44e3a38431SPaul Bohm /* my wild guess would be that using something floating-pointy is required */
45e3a38431SPaul Bohm /* for the crt to do something about it */
46e3a38431SPaul Bohm volatile double SIGFPE_REQ = 0.0f;
47e3a38431SPaul Bohm 
48*93823e6cSPaul Bohm static SOCKET
ev_tcp_socket(void)49*93823e6cSPaul Bohm ev_tcp_socket (void)
50*93823e6cSPaul Bohm {
51*93823e6cSPaul Bohm #if EV_USE_WSASOCKET
52*93823e6cSPaul Bohm   return WSASocket (AF_INET, SOCK_STREAM, 0, 0, 0, 0);
53*93823e6cSPaul Bohm #else
54*93823e6cSPaul Bohm   return socket (AF_INET, SOCK_STREAM, 0);
55*93823e6cSPaul Bohm #endif
56*93823e6cSPaul Bohm }
57*93823e6cSPaul Bohm 
58e3a38431SPaul Bohm /* oh, the humanity! */
59e3a38431SPaul Bohm static int
ev_pipe(int filedes[2])60e3a38431SPaul Bohm ev_pipe (int filedes [2])
61e3a38431SPaul Bohm {
62e3a38431SPaul Bohm   struct sockaddr_in addr = { 0 };
63e3a38431SPaul Bohm   int addr_size = sizeof (addr);
64e3a38431SPaul Bohm   struct sockaddr_in adr2;
65e3a38431SPaul Bohm   int adr2_size = sizeof (adr2);
66e3a38431SPaul Bohm   SOCKET listener;
67e3a38431SPaul Bohm   SOCKET sock [2] = { -1, -1 };
68e3a38431SPaul Bohm 
69*93823e6cSPaul Bohm   if ((listener = ev_tcp_socket ()) == INVALID_SOCKET)
70e3a38431SPaul Bohm     return -1;
71e3a38431SPaul Bohm 
72e3a38431SPaul Bohm   addr.sin_family = AF_INET;
73e3a38431SPaul Bohm   addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
74e3a38431SPaul Bohm   addr.sin_port = 0;
75e3a38431SPaul Bohm 
76e3a38431SPaul Bohm   if (bind (listener, (struct sockaddr *)&addr, addr_size))
77e3a38431SPaul Bohm     goto fail;
78e3a38431SPaul Bohm 
79e3a38431SPaul Bohm   if (getsockname (listener, (struct sockaddr *)&addr, &addr_size))
80e3a38431SPaul Bohm     goto fail;
81e3a38431SPaul Bohm 
82e3a38431SPaul Bohm   if (listen (listener, 1))
83e3a38431SPaul Bohm     goto fail;
84e3a38431SPaul Bohm 
85*93823e6cSPaul Bohm   if ((sock [0] = ev_tcp_socket ()) == INVALID_SOCKET)
86e3a38431SPaul Bohm     goto fail;
87e3a38431SPaul Bohm 
88e3a38431SPaul Bohm   if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
89e3a38431SPaul Bohm     goto fail;
90e3a38431SPaul Bohm 
91*93823e6cSPaul Bohm   /* TODO: returns INVALID_SOCKET on winsock accept, not < 0. fix it */
92*93823e6cSPaul Bohm   /* when convenient, probably by just removing error checking altogether? */
93e3a38431SPaul Bohm   if ((sock [1] = accept (listener, 0, 0)) < 0)
94e3a38431SPaul Bohm     goto fail;
95e3a38431SPaul Bohm 
96e3a38431SPaul Bohm   /* windows vista returns fantasy port numbers for sockets:
97e3a38431SPaul Bohm    * example for two interconnected tcp sockets:
98e3a38431SPaul Bohm    *
99e3a38431SPaul Bohm    * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364
100e3a38431SPaul Bohm    * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363
101e3a38431SPaul Bohm    * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363
102e3a38431SPaul Bohm    * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365
103e3a38431SPaul Bohm    *
104e3a38431SPaul Bohm    * wow! tridirectional sockets!
105e3a38431SPaul Bohm    *
106e3a38431SPaul Bohm    * this way of checking ports seems to work:
107e3a38431SPaul Bohm    */
108e3a38431SPaul Bohm   if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size))
109e3a38431SPaul Bohm     goto fail;
110e3a38431SPaul Bohm 
111e3a38431SPaul Bohm   if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size))
112e3a38431SPaul Bohm     goto fail;
113e3a38431SPaul Bohm 
114e3a38431SPaul Bohm   errno = WSAEINVAL;
115e3a38431SPaul Bohm   if (addr_size != adr2_size
116e3a38431SPaul Bohm       || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */
117e3a38431SPaul Bohm       || addr.sin_port        != adr2.sin_port)
118e3a38431SPaul Bohm     goto fail;
119e3a38431SPaul Bohm 
120e3a38431SPaul Bohm   closesocket (listener);
121e3a38431SPaul Bohm 
122e3a38431SPaul Bohm #if EV_SELECT_IS_WINSOCKET
123e3a38431SPaul Bohm   filedes [0] = EV_WIN32_HANDLE_TO_FD (sock [0]);
124e3a38431SPaul Bohm   filedes [1] = EV_WIN32_HANDLE_TO_FD (sock [1]);
125e3a38431SPaul Bohm #else
126e3a38431SPaul Bohm   /* when select isn't winsocket, we also expect socket, connect, accept etc.
127e3a38431SPaul Bohm    * to work on fds */
128e3a38431SPaul Bohm   filedes [0] = sock [0];
129e3a38431SPaul Bohm   filedes [1] = sock [1];
130e3a38431SPaul Bohm #endif
131e3a38431SPaul Bohm 
132e3a38431SPaul Bohm   return 0;
133e3a38431SPaul Bohm 
134e3a38431SPaul Bohm fail:
135e3a38431SPaul Bohm   closesocket (listener);
136e3a38431SPaul Bohm 
137e3a38431SPaul Bohm   if (sock [0] != INVALID_SOCKET) closesocket (sock [0]);
138e3a38431SPaul Bohm   if (sock [1] != INVALID_SOCKET) closesocket (sock [1]);
139e3a38431SPaul Bohm 
140e3a38431SPaul Bohm   return -1;
141e3a38431SPaul Bohm }
142e3a38431SPaul Bohm 
143e3a38431SPaul Bohm #undef pipe
144e3a38431SPaul Bohm #define pipe(filedes) ev_pipe (filedes)
145e3a38431SPaul Bohm 
146e3a38431SPaul Bohm #define EV_HAVE_EV_TIME 1
147e3a38431SPaul Bohm ev_tstamp
ev_time(void)148e3a38431SPaul Bohm ev_time (void)
149e3a38431SPaul Bohm {
150e3a38431SPaul Bohm   FILETIME ft;
151e3a38431SPaul Bohm   ULARGE_INTEGER ui;
152e3a38431SPaul Bohm 
153e3a38431SPaul Bohm   GetSystemTimeAsFileTime (&ft);
154e3a38431SPaul Bohm   ui.u.LowPart  = ft.dwLowDateTime;
155e3a38431SPaul Bohm   ui.u.HighPart = ft.dwHighDateTime;
156e3a38431SPaul Bohm 
157e3a38431SPaul Bohm   /* msvc cannot convert ulonglong to double... yes, it is that sucky */
158e3a38431SPaul Bohm   return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7;
159e3a38431SPaul Bohm }
160e3a38431SPaul Bohm 
161e3a38431SPaul Bohm #endif
162e3a38431SPaul Bohm 
163