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