1 // Module:  Log4CPLUS
2 // File:    socket-win32.cxx
3 // Created: 4/2003
4 // Author:  Tad E. Smith
5 //
6 //
7 // Copyright 2003-2013 Tad E. Smith
8 //
9 // Licensed under the Apache License, Version 2.0 (the "License");
10 // you may not use this file except in compliance with the License.
11 // You may obtain a copy of the License at
12 //
13 //     http://www.apache.org/licenses/LICENSE-2.0
14 //
15 // Unless required by applicable law or agreed to in writing, software
16 // distributed under the License is distributed on an "AS IS" BASIS,
17 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 // See the License for the specific language governing permissions and
19 // limitations under the License.
20 
21 #include <log4cplus/config.hxx>
22 #if defined (LOG4CPLUS_USE_WINSOCK)
23 
24 #include <cassert>
25 #include <cerrno>
26 #include <vector>
27 #include <cstring>
28 #include <log4cplus/internal/socket.h>
29 #include <log4cplus/helpers/loglog.h>
30 #include <log4cplus/thread/threads.h>
31 #include <log4cplus/helpers/stringhelper.h>
32 
33 
34 /////////////////////////////////////////////////////////////////////////////
35 // file LOCAL Classes
36 /////////////////////////////////////////////////////////////////////////////
37 
38 namespace
39 {
40 
41 enum WSInitStates
42 {
43     WS_UNINITIALIZED,
44     WS_INITIALIZING,
45     WS_INITIALIZED
46 };
47 
48 
49 static WSADATA wsa;
50 static LONG volatile winsock_state = WS_UNINITIALIZED;
51 
52 
53 static
54 void
init_winsock_worker()55 init_winsock_worker ()
56 {
57     log4cplus::helpers::LogLog * loglog
58         = log4cplus::helpers::LogLog::getLogLog ();
59 
60     // Try to change the state to WS_INITIALIZING.
61     LONG val = ::InterlockedCompareExchange (
62         const_cast<LPLONG>(&winsock_state), WS_INITIALIZING, WS_UNINITIALIZED);
63     switch (val)
64     {
65     case WS_UNINITIALIZED:
66     {
67         int ret = WSAStartup (MAKEWORD (2, 2), &wsa);
68         if (ret != 0)
69         {
70             // Revert the state back to WS_UNINITIALIZED to unblock other
71             // threads and let them throw exception.
72             val = ::InterlockedCompareExchange (
73                 const_cast<LPLONG>(&winsock_state), WS_UNINITIALIZED,
74                 WS_INITIALIZING);
75             assert (val == WS_INITIALIZING);
76             loglog->error (LOG4CPLUS_TEXT ("Could not initialize WinSock."),
77                 true);
78         }
79 
80         // WinSock is initialized, change the state to WS_INITIALIZED.
81         val = ::InterlockedCompareExchange (
82             const_cast<LPLONG>(&winsock_state), WS_INITIALIZED,
83             WS_INITIALIZING);
84         assert (val == WS_INITIALIZING);
85         return;
86     }
87 
88     case WS_INITIALIZING:
89         // Wait for state change.
90         while (true)
91         {
92             switch (winsock_state)
93             {
94             case WS_INITIALIZED:
95                 return;
96 
97             case WS_INITIALIZING:
98                 log4cplus::thread::yield ();
99                 continue;
100 
101             default:
102                 assert (0);
103                 loglog->error (LOG4CPLUS_TEXT ("Unknown WinSock state."), true);
104             }
105         }
106 
107     case WS_INITIALIZED:
108         // WinSock is already initialized.
109         return;
110 
111     default:
112         assert (0);
113         loglog->error (LOG4CPLUS_TEXT ("Unknown WinSock state."), true);
114     }
115 }
116 
117 
118 static
119 void
init_winsock()120 init_winsock ()
121 {
122     // Quick check first to avoid the expensive interlocked compare
123     // and exchange.
124     if (winsock_state == WS_INITIALIZED)
125         return;
126     else
127         init_winsock_worker ();
128 }
129 
130 
131 struct WinSockInitializer
132 {
~WinSockInitializer__anonfa8ca85f0111::WinSockInitializer133     ~WinSockInitializer ()
134     {
135         if (winsock_state == WS_INITIALIZED)
136             WSACleanup ();
137     }
138 
139     static WinSockInitializer winSockInitializer;
140 };
141 
142 
143 WinSockInitializer WinSockInitializer::winSockInitializer;
144 
145 
146 } // namespace
147 
148 
149 namespace log4cplus { namespace helpers {
150 
151 
152 /////////////////////////////////////////////////////////////////////////////
153 // Global Methods
154 /////////////////////////////////////////////////////////////////////////////
155 
156 SOCKET_TYPE
openSocket(unsigned short port,SocketState & state)157 openSocket(unsigned short port, SocketState& state)
158 {
159     struct sockaddr_in server;
160 
161     init_winsock ();
162 
163     SOCKET sock = WSASocket (AF_INET, SOCK_STREAM, AF_UNSPEC, 0, 0
164 #if defined (WSA_FLAG_NO_HANDLE_INHERIT)
165         , WSA_FLAG_NO_HANDLE_INHERIT
166 #else
167         , 0
168 #endif
169         );
170 
171     if (sock == INVALID_OS_SOCKET_VALUE)
172         goto error;
173 
174     server.sin_family = AF_INET;
175     server.sin_addr.s_addr = htonl(INADDR_ANY);
176     server.sin_port = htons(port);
177 
178     if (bind(sock, reinterpret_cast<struct sockaddr*>(&server), sizeof(server))
179         != 0)
180         goto error;
181 
182     if (::listen(sock, 10) != 0)
183         goto error;
184 
185     state = ok;
186     return to_log4cplus_socket (sock);
187 
188 error:
189     int eno = WSAGetLastError ();
190 
191     if (sock != INVALID_OS_SOCKET_VALUE)
192         ::closesocket (sock);
193 
194     set_last_socket_error (eno);
195     return INVALID_SOCKET_VALUE;
196 }
197 
198 
199 SOCKET_TYPE
connectSocket(const tstring & hostn,unsigned short port,bool udp,SocketState & state)200 connectSocket(const tstring& hostn, unsigned short port, bool udp, SocketState& state)
201 {
202     struct hostent * hp;
203     struct sockaddr_in insock;
204     int retval;
205 
206     init_winsock ();
207 
208     SOCKET sock = WSASocket (AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM),
209         AF_UNSPEC, 0, 0
210 #if defined (WSA_FLAG_NO_HANDLE_INHERIT)
211         , WSA_FLAG_NO_HANDLE_INHERIT
212 #else
213         , 0
214 #endif
215         );
216     if (sock == INVALID_OS_SOCKET_VALUE)
217         goto error;
218 
219     hp = ::gethostbyname( LOG4CPLUS_TSTRING_TO_STRING(hostn).c_str() );
220     if (hp == 0 || hp->h_addrtype != AF_INET)
221     {
222         insock.sin_family = AF_INET;
223         INT insock_size = sizeof (insock);
224         INT ret = WSAStringToAddress (const_cast<LPTSTR>(hostn.c_str ()),
225             AF_INET, 0, reinterpret_cast<struct sockaddr *>(&insock),
226             &insock_size);
227         if (ret == SOCKET_ERROR || insock_size != static_cast<INT>(sizeof (insock)))
228         {
229             state = bad_address;
230             goto error;
231         }
232     }
233     else
234         std::memcpy (&insock.sin_addr, hp->h_addr_list[0],
235             sizeof (insock.sin_addr));
236 
237     insock.sin_port = htons(port);
238     insock.sin_family = AF_INET;
239 
240     while(   (retval = ::connect(sock, (struct sockaddr*)&insock, sizeof(insock))) == -1
241           && (WSAGetLastError() == WSAEINTR))
242         ;
243     if (retval == SOCKET_ERROR)
244         goto error;
245 
246     state = ok;
247     return to_log4cplus_socket (sock);
248 
249 error:
250     int eno = WSAGetLastError ();
251 
252     if (sock != INVALID_OS_SOCKET_VALUE)
253         ::closesocket (sock);
254 
255     set_last_socket_error (eno);
256     return INVALID_SOCKET_VALUE;
257 }
258 
259 
260 SOCKET_TYPE
acceptSocket(SOCKET_TYPE sock,SocketState & state)261 acceptSocket(SOCKET_TYPE sock, SocketState & state)
262 {
263     init_winsock ();
264 
265     SOCKET connected_socket = ::accept (to_os_socket (sock), NULL, NULL);
266 
267     if (connected_socket != INVALID_OS_SOCKET_VALUE)
268         state = ok;
269     else
270         set_last_socket_error (WSAGetLastError ());
271 
272     return to_log4cplus_socket (connected_socket);
273 }
274 
275 
276 
277 int
closeSocket(SOCKET_TYPE sock)278 closeSocket(SOCKET_TYPE sock)
279 {
280     return ::closesocket (to_os_socket (sock));
281 }
282 
283 
284 int
shutdownSocket(SOCKET_TYPE sock)285 shutdownSocket(SOCKET_TYPE sock)
286 {
287     return ::shutdown (to_os_socket (sock), SD_BOTH);
288 }
289 
290 
291 long
read(SOCKET_TYPE sock,SocketBuffer & buffer)292 read(SOCKET_TYPE sock, SocketBuffer& buffer)
293 {
294     long res, read = 0;
295     os_socket_type const osSocket = to_os_socket (sock);
296 
297     do
298     {
299         res = ::recv(osSocket,
300                      buffer.getBuffer() + read,
301                      static_cast<int>(buffer.getMaxSize() - read),
302                      0);
303         if (res == SOCKET_ERROR)
304         {
305             set_last_socket_error (WSAGetLastError ());
306             return res;
307         }
308 
309         // A return of 0 indicates the socket is closed,
310         // return to prevent an infinite loop.
311         if (res == 0)
312             return read;
313 
314         read += res;
315     }
316     while (read < static_cast<long>(buffer.getMaxSize()));
317 
318     return read;
319 }
320 
321 
322 
323 long
write(SOCKET_TYPE sock,const SocketBuffer & buffer)324 write(SOCKET_TYPE sock, const SocketBuffer& buffer)
325 {
326     long ret = ::send (to_os_socket (sock), buffer.getBuffer(),
327         static_cast<int>(buffer.getSize()), 0);
328     if (ret == SOCKET_ERROR)
329         set_last_socket_error (WSAGetLastError ());
330     return ret;
331 }
332 
333 
334 long
write(SOCKET_TYPE sock,const std::string & buffer)335 write(SOCKET_TYPE sock, const std::string & buffer)
336 {
337     long ret = ::send (to_os_socket (sock), buffer.c_str (),
338         static_cast<int>(buffer.size ()), 0);
339     if (ret == SOCKET_ERROR)
340         set_last_socket_error (WSAGetLastError ());
341     return ret;
342 }
343 
344 
345 tstring
getHostname(bool fqdn)346 getHostname (bool fqdn)
347 {
348     init_winsock ();
349 
350     char const * hostname = "unknown";
351     int ret;
352     std::vector<char> hn (1024, 0);
353 
354     while (true)
355     {
356         ret = ::gethostname (&hn[0], static_cast<int>(hn.size ()) - 1);
357         if (ret == 0)
358         {
359             hostname = &hn[0];
360             break;
361         }
362         else if (ret != 0 && WSAGetLastError () == WSAEFAULT)
363             // Out buffer was too short. Retry with buffer twice the size.
364             hn.resize (hn.size () * 2, 0);
365         else
366             break;
367     }
368 
369     if (ret != 0 || (ret == 0 && ! fqdn))
370         return LOG4CPLUS_STRING_TO_TSTRING (hostname);
371 
372     struct ::hostent * hp = ::gethostbyname (hostname);
373     if (hp)
374         hostname = hp->h_name;
375 
376     return LOG4CPLUS_STRING_TO_TSTRING (hostname);
377 }
378 
379 
380 int
setTCPNoDelay(SOCKET_TYPE sock,bool val)381 setTCPNoDelay (SOCKET_TYPE sock, bool val)
382 {
383     int result;
384     int enabled = static_cast<int>(val);
385     if ((result = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
386             reinterpret_cast<char*>(&enabled),sizeof(enabled))) != 0)
387     {
388         int eno = WSAGetLastError ();
389         set_last_socket_error (eno);
390     }
391 
392     return result;
393 }
394 
395 
396 //
397 // ServerSocket OS dependent stuff
398 //
399 
400 namespace
401 {
402 
403 static
404 bool
setSocketBlocking(SOCKET_TYPE s)405 setSocketBlocking (SOCKET_TYPE s)
406 {
407     u_long val = 0;
408     int ret = ioctlsocket (to_os_socket (s), FIONBIO, &val);
409     if (ret == SOCKET_ERROR)
410     {
411         set_last_socket_error (WSAGetLastError ());
412         return false;
413     }
414     else
415         return true;
416 }
417 
418 static
419 bool
removeSocketEvents(SOCKET_TYPE s,HANDLE ev)420 removeSocketEvents (SOCKET_TYPE s, HANDLE ev)
421 {
422     // Clean up socket events handling.
423 
424     int ret = WSAEventSelect (to_os_socket (s), ev, 0);
425     if (ret == SOCKET_ERROR)
426     {
427         set_last_socket_error (WSAGetLastError ());
428         return false;
429     }
430     else
431         return true;
432 }
433 
434 
435 static
436 bool
socketEventHandlingCleanup(SOCKET_TYPE s,HANDLE ev)437 socketEventHandlingCleanup (SOCKET_TYPE s, HANDLE ev)
438 {
439     bool ret = removeSocketEvents (s, ev);
440     ret = setSocketBlocking (s) && ret;
441     ret = WSACloseEvent (ev) && ret;
442     return ret;
443 }
444 
445 
446 } // namespace
447 
448 
ServerSocket(unsigned short port)449 ServerSocket::ServerSocket(unsigned short port)
450 {
451     sock = openSocket (port, state);
452     if (sock == INVALID_SOCKET_VALUE)
453     {
454         err = get_last_socket_error ();
455         return;
456     }
457 
458     HANDLE ev = WSACreateEvent ();
459     if (ev == WSA_INVALID_EVENT)
460     {
461         err = WSAGetLastError ();
462         closeSocket (sock);
463         sock = INVALID_SOCKET_VALUE;
464     }
465     else
466     {
467         assert (sizeof (std::ptrdiff_t) >= sizeof (HANDLE));
468         interruptHandles[0] = reinterpret_cast<std::ptrdiff_t>(ev);
469     }
470 }
471 
472 Socket
accept()473 ServerSocket::accept ()
474 {
475     int const N_EVENTS = 2;
476     HANDLE events[N_EVENTS] = {
477         reinterpret_cast<HANDLE>(interruptHandles[0]) };
478     HANDLE & accept_ev = events[1];
479     int ret;
480 
481     // Create event and prime socket to set the event on FD_ACCEPT.
482 
483     accept_ev = WSACreateEvent ();
484     if (accept_ev == WSA_INVALID_EVENT)
485     {
486         set_last_socket_error (WSAGetLastError ());
487         goto error;
488     }
489 
490     ret = WSAEventSelect (to_os_socket (sock), accept_ev, FD_ACCEPT);
491     if (ret == SOCKET_ERROR)
492     {
493         set_last_socket_error (WSAGetLastError ());
494         goto error;
495     }
496 
497     do
498     {
499         // Wait either for interrupt event or actual connection coming in.
500 
501         DWORD wsawfme = WSAWaitForMultipleEvents (N_EVENTS, events, FALSE,
502             WSA_INFINITE, TRUE);
503         switch (wsawfme)
504         {
505         case WSA_WAIT_TIMEOUT:
506         case WSA_WAIT_IO_COMPLETION:
507             // Retry after timeout or APC.
508             continue;
509 
510         // This is interrupt signal/event.
511         case WSA_WAIT_EVENT_0:
512         {
513             // Reset the interrupt event back to non-signalled state.
514 
515             ret = WSAResetEvent (reinterpret_cast<HANDLE>(interruptHandles[0]));
516 
517             // Clean up socket events handling.
518 
519             ret = socketEventHandlingCleanup (sock, accept_ev);
520 
521             // Return Socket with state set to accept_interrupted.
522 
523             return Socket (INVALID_SOCKET_VALUE, accept_interrupted, 0);
524         }
525 
526         // This is accept_ev.
527         case WSA_WAIT_EVENT_0 + 1:
528         {
529             // Clean up socket events handling.
530 
531             ret = socketEventHandlingCleanup (sock, accept_ev);
532 
533             // Finally, call accept().
534 
535             SocketState st = not_opened;
536             SOCKET_TYPE clientSock = acceptSocket (sock, st);
537             int eno = 0;
538             if (clientSock == INVALID_SOCKET_VALUE)
539                 eno = get_last_socket_error ();
540 
541             return Socket (clientSock, st, eno);
542         }
543 
544         case WSA_WAIT_FAILED:
545         default:
546             set_last_socket_error (WSAGetLastError ());
547             goto error;
548         }
549     }
550     while (true);
551 
552 
553 error:;
554     DWORD eno = get_last_socket_error ();
555 
556     // Clean up socket events handling.
557 
558     if (sock != INVALID_SOCKET_VALUE)
559     {
560         (void) removeSocketEvents (sock, accept_ev);
561         (void) setSocketBlocking (sock);
562     }
563 
564     if (accept_ev != WSA_INVALID_EVENT)
565         WSACloseEvent (accept_ev);
566 
567     set_last_socket_error (eno);
568     return Socket (INVALID_SOCKET_VALUE, not_opened, eno);
569 }
570 
571 
572 void
interruptAccept()573 ServerSocket::interruptAccept ()
574 {
575     (void) WSASetEvent (reinterpret_cast<HANDLE>(interruptHandles[0]));
576 }
577 
578 
~ServerSocket()579 ServerSocket::~ServerSocket()
580 {
581     (void) WSACloseEvent (reinterpret_cast<HANDLE>(interruptHandles[0]));
582 }
583 
584 
585 
586 } } // namespace log4cplus { namespace helpers {
587 
588 #endif // LOG4CPLUS_USE_WINSOCK
589