1 /*****************************************************************
3 | Neptune - Sockets :: WinRT Implementation
5 | (c) 2001-2012 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
8 ****************************************************************/
10 /*----------------------------------------------------------------------
12 +---------------------------------------------------------------------*/
13 #include "NptWinRtPch.h"
15 using namespace Platform
;
16 using namespace Windows::Foundation
;
17 using namespace Windows::Foundation::Collections
;
18 using namespace Windows::Networking
;
19 using namespace Windows::Networking::Sockets
;
20 using namespace Windows::Storage::Streams
;
21 using namespace Concurrency
;
23 /*----------------------------------------------------------------------
25 +---------------------------------------------------------------------*/
26 NPT_SET_LOCAL_LOGGER("neptune.sockets.winrt")
28 /*----------------------------------------------------------------------
30 +---------------------------------------------------------------------*/
31 const DWORD NPT_WINRT_SOCKET_DEFAULT_READ_TIMEOUT
= 30000;
32 const DWORD NPT_WINRT_SOCKET_DEFAULT_WRITE_TIMEOUT
= 30000;
34 /*----------------------------------------------------------------------
35 | NPT_WinRtTcpClientSocket
36 +---------------------------------------------------------------------*/
37 class NPT_WinRtTcpClientSocket
: public NPT_SocketInterface
40 // constructors and destructor
41 NPT_WinRtTcpClientSocket();
42 virtual ~NPT_WinRtTcpClientSocket();
44 // NPT_SocketInterface methods
45 NPT_Result
Bind(const NPT_SocketAddress
& address
, bool reuse_address
= true);
46 NPT_Result
Connect(const NPT_SocketAddress
& address
, NPT_Timeout timeout
);
47 NPT_Result
GetInputStream(NPT_InputStreamReference
& stream
);
48 NPT_Result
GetOutputStream(NPT_OutputStreamReference
& stream
);
49 NPT_Result
GetInfo(NPT_SocketInfo
& info
);
50 NPT_Result
SetReadTimeout(NPT_Timeout timeout
);
51 NPT_Result
SetWriteTimeout(NPT_Timeout timeout
);
52 NPT_Result
Cancel(bool shutdown
);
55 StreamSocket
^ m_Socket
;
56 HostName
^ m_RemoteHostName
;
58 NPT_Timeout m_ReadTimeout
;
59 NPT_Timeout m_WriteTimeout
;
62 /*----------------------------------------------------------------------
63 | NPT_WinRtSocketInputStream
64 +---------------------------------------------------------------------*/
65 class NPT_WinRtSocketInputStream
: public NPT_InputStream
68 // constructors and destructor
69 NPT_WinRtSocketInputStream(StreamSocket
^ socket
, NPT_Timeout timeout
);
70 virtual ~NPT_WinRtSocketInputStream();
72 // NPT_InputStream methods
73 NPT_Result
Read(void* buffer
,
74 NPT_Size bytes_to_read
,
75 NPT_Size
* bytes_read
);
76 NPT_Result
Seek(NPT_Position offset
);
77 NPT_Result
Tell(NPT_Position
& where
);
78 NPT_Result
GetSize(NPT_LargeSize
& size
);
79 NPT_Result
GetAvailable(NPT_LargeSize
& available
);
82 StreamSocket
^ m_Socket
;
83 IInputStream
^ m_InputStream
;
86 NPT_Timeout m_Timeout
;
89 /*----------------------------------------------------------------------
90 | NPT_WinRtSocketOutputStream
91 +---------------------------------------------------------------------*/
92 class NPT_WinRtSocketOutputStream
: public NPT_OutputStream
95 // constructors and destructor
96 NPT_WinRtSocketOutputStream(StreamSocket
^ socket
, NPT_Timeout timeout
);
97 virtual ~NPT_WinRtSocketOutputStream();
99 // NPT_OutputStream methods
100 NPT_Result
Write(const void* buffer
,
101 NPT_Size bytes_to_write
,
102 NPT_Size
* bytes_written
);
103 NPT_Result
Seek(NPT_Position offset
);
104 NPT_Result
Tell(NPT_Position
& where
);
108 StreamSocket
^ m_Socket
;
109 IOutputStream
^ m_OutputStream
;
110 DataWriter
^ m_Writer
;
112 NPT_Timeout m_Timeout
;
115 /*----------------------------------------------------------------------
117 +---------------------------------------------------------------------*/
119 StringFromUTF8(const char* utf
)
121 unsigned int utf_len
= NPT_StringLength(utf
);
122 unsigned int wide_len
= utf_len
;
123 wchar_t* wide
= new wchar_t[wide_len
+1];
124 int result
= MultiByteToWideChar(CP_UTF8
,
132 str
= ref
new String(wide
);
134 str
= ref
new String();
140 /*----------------------------------------------------------------------
142 +---------------------------------------------------------------------*/
144 TranslateHResult(HResult result
)
146 switch (HRESULT_FACILITY(result
.Value
)) {
148 switch (HRESULT_CODE(result
.Value
)) {
149 case WSAHOST_NOT_FOUND
:
150 return NPT_ERROR_HOST_UNKNOWN
;
153 return NPT_ERROR_TIMEOUT
;
155 case WSAECONNREFUSED
:
156 return NPT_ERROR_CONNECTION_REFUSED
;
159 return NPT_ERROR_WOULD_BLOCK
;
161 case WSAECONNABORTED
:
162 return NPT_ERROR_CONNECTION_ABORTED
;
166 return NPT_ERROR_CONNECTION_RESET
;
169 return NPT_ERROR_ADDRESS_IN_USE
;
172 return NPT_ERROR_NETWORK_DOWN
;
175 return NPT_ERROR_NETWORK_UNREACHABLE
;
178 return NPT_ERROR_INTERRUPTED
;
181 return NPT_ERROR_NOT_CONNECTED
;
188 /* TODO: map error codes */
194 /*----------------------------------------------------------------------
196 +---------------------------------------------------------------------*/
198 WaitForAsyncAction(IAsyncAction
^ action
,
200 DWORD timeout
= INFINITE
)
202 NPT_Result result
= NPT_ERROR_INTERNAL
;
204 NPT_LOG_FINEST("waiting for async action...");
205 ResetEvent(wait_event
);
207 action
->Completed
= ref
new AsyncActionCompletedHandler
208 ([&](IAsyncAction
^ action_
, AsyncStatus status
) {
210 case AsyncStatus::Canceled
:
211 result
= NPT_ERROR_TIMEOUT
;
214 case AsyncStatus::Completed
:
215 result
= NPT_SUCCESS
;
218 case AsyncStatus::Error
:
219 NPT_LOG_FINE_1("AsyncAction error %x", action_
->ErrorCode
.Value
);
220 result
= TranslateHResult(action_
->ErrorCode
);
224 result
= NPT_ERROR_INTERNAL
;
227 SetEvent(wait_event
);
230 DWORD wait_result
= WaitForSingleObjectEx(wait_event
, timeout
, FALSE
);
231 if (wait_result
!= WAIT_OBJECT_0
) {
232 NPT_LOG_FINE("action timed out, canceling...");
234 WaitForSingleObjectEx(wait_event
, INFINITE
, FALSE
);
236 NPT_LOG_FINEST("done waiting for async action");
241 /*----------------------------------------------------------------------
242 | WaitForAsyncOperation
243 +---------------------------------------------------------------------*/
245 WaitForAsyncOperation(IAsyncOperation
<unsigned int>^ operation
,
247 unsigned int& return_value
,
248 DWORD timeout
= INFINITE
)
250 NPT_Result result
= NPT_ERROR_INTERNAL
;
252 NPT_LOG_FINEST("waiting for async operation...");
254 ResetEvent(wait_event
);
256 operation
->Completed
= ref
new AsyncOperationCompletedHandler
<unsigned int>
257 ([&](IAsyncOperation
<unsigned int>^ operation_
, AsyncStatus status
) {
259 case AsyncStatus::Canceled
:
260 result
= NPT_ERROR_TIMEOUT
;
263 case AsyncStatus::Completed
:
264 return_value
= operation_
->GetResults();
265 result
= NPT_SUCCESS
;
268 case AsyncStatus::Error
:
269 NPT_LOG_FINE_1("AsyncOperation error %x", operation_
->ErrorCode
.Value
);
270 result
= TranslateHResult(operation_
->ErrorCode
);
274 result
= NPT_ERROR_INTERNAL
;
278 SetEvent(wait_event
);
281 DWORD wait_result
= WaitForSingleObjectEx(wait_event
, timeout
, FALSE
);
282 if (wait_result
!= WAIT_OBJECT_0
) {
283 NPT_LOG_FINE("operation timed out, canceling...");
285 WaitForSingleObjectEx(wait_event
, INFINITE
, FALSE
);
287 NPT_LOG_FINEST("done waiting for async operation");
292 /*----------------------------------------------------------------------
293 | NPT_WinRtSocketInputStream::NPT_WinRtSocketInputStream
294 +---------------------------------------------------------------------*/
295 NPT_WinRtSocketInputStream::NPT_WinRtSocketInputStream(StreamSocket
^ socket
,
296 NPT_Timeout timeout
) :
300 m_InputStream
= socket
->InputStream
;
301 m_Reader
= ref
new DataReader(m_InputStream
);
302 m_Reader
->InputStreamOptions
= InputStreamOptions::Partial
;
303 m_WaitEvent
= CreateEventExW(NULL
, L
"", 0, EVENT_ALL_ACCESS
);
306 /*----------------------------------------------------------------------
307 | NPT_WinRtSocketInputStream::~NPT_WinRtSocketInputStream
308 +---------------------------------------------------------------------*/
309 NPT_WinRtSocketInputStream::~NPT_WinRtSocketInputStream()
311 m_Reader
->DetachStream();
312 CloseHandle(m_WaitEvent
);
315 /*----------------------------------------------------------------------
316 | NPT_WinRtSocketInputStream::Read
317 +---------------------------------------------------------------------*/
319 NPT_WinRtSocketInputStream::Read(void* buffer
,
320 NPT_Size bytes_to_read
,
321 NPT_Size
* bytes_read
)
324 if (bytes_read
) *bytes_read
= 0;
325 if (bytes_to_read
== 0) return NPT_SUCCESS
;
327 NPT_LOG_FINER_1("reading %d bytes", bytes_to_read
);
328 auto operation
= m_Reader
->LoadAsync(bytes_to_read
);
330 unsigned int return_value
= 0;
331 NPT_Result result
= WaitForAsyncOperation(operation
, m_WaitEvent
, return_value
, m_Timeout
);
333 if (NPT_SUCCEEDED(result
)) {
335 unsigned int bytes_available
= m_Reader
->UnconsumedBufferLength
;
336 Array
<unsigned char>^ bytes
= ref
new Array
<unsigned char>(bytes_available
);
337 m_Reader
->ReadBytes(bytes
);
338 NPT_CopyMemory(buffer
, bytes
->Data
, bytes_available
);
339 if (bytes_read
) *bytes_read
= bytes_available
;
342 return NPT_ERROR_EOS
;
349 /*----------------------------------------------------------------------
350 | NPT_WinRtSocketInputStream::Seek
351 +---------------------------------------------------------------------*/
353 NPT_WinRtSocketInputStream::Seek(NPT_Position offset
)
355 return NPT_ERROR_NOT_SUPPORTED
;
358 /*----------------------------------------------------------------------
359 | NPT_WinRtSocketInputStream::Tell
360 +---------------------------------------------------------------------*/
362 NPT_WinRtSocketInputStream::Tell(NPT_Position
& where
)
365 return NPT_ERROR_NOT_SUPPORTED
;
368 /*----------------------------------------------------------------------
369 | NPT_WinRtSocketInputStream::GetSize
370 +---------------------------------------------------------------------*/
372 NPT_WinRtSocketInputStream::GetSize(NPT_LargeSize
& size
)
375 return NPT_ERROR_NOT_SUPPORTED
;
378 /*----------------------------------------------------------------------
379 | NPT_WinRtSocketInputStream::GetAvailable
380 +---------------------------------------------------------------------*/
382 NPT_WinRtSocketInputStream::GetAvailable(NPT_LargeSize
& available
)
388 /*----------------------------------------------------------------------
389 | NPT_WinRtSocketOutputStream::NPT_WinRtSocketOutputStream
390 +---------------------------------------------------------------------*/
391 NPT_WinRtSocketOutputStream::NPT_WinRtSocketOutputStream(StreamSocket
^ socket
,
392 NPT_Timeout timeout
) :
396 m_OutputStream
= socket
->OutputStream
;
397 m_Writer
= ref
new DataWriter(m_OutputStream
);
398 m_WaitEvent
= CreateEventExW(NULL
, L
"", 0, EVENT_ALL_ACCESS
);
401 /*----------------------------------------------------------------------
402 | NPT_WinRtSocketOutputStream::~NPT_WinRtSocketOutputStream
403 +---------------------------------------------------------------------*/
404 NPT_WinRtSocketOutputStream::~NPT_WinRtSocketOutputStream()
406 m_Writer
->DetachStream();
407 CloseHandle(m_WaitEvent
);
410 /*----------------------------------------------------------------------
411 | NPT_WinRtSocketOutputStream::Write
412 +---------------------------------------------------------------------*/
414 NPT_WinRtSocketOutputStream::Write(const void* buffer
,
415 NPT_Size bytes_to_write
,
416 NPT_Size
* bytes_written
)
418 NPT_LOG_FINER_1("writing %d bytes", bytes_to_write
);
420 Array
<unsigned char>^ bytes
= ref
new Array
<unsigned char>(bytes_to_write
);
421 NPT_CopyMemory(bytes
->Data
, buffer
, bytes_to_write
);
422 m_Writer
->WriteBytes(bytes
);
423 auto operation
= m_Writer
->StoreAsync();
424 unsigned int return_value
= 0;
426 NPT_Result result
= WaitForAsyncOperation(operation
, m_WaitEvent
, return_value
, m_Timeout
);
427 if (bytes_written
) *bytes_written
= return_value
;
432 /*----------------------------------------------------------------------
433 | NPT_WinRtSocketOutputStream::Seek
434 +---------------------------------------------------------------------*/
436 NPT_WinRtSocketOutputStream::Seek(NPT_Position offset
)
438 return NPT_ERROR_NOT_SUPPORTED
;
441 /*----------------------------------------------------------------------
442 | NPT_WinRtSocketOutputStream::Tell
443 +---------------------------------------------------------------------*/
445 NPT_WinRtSocketOutputStream::Tell(NPT_Position
& where
)
448 return NPT_ERROR_NOT_SUPPORTED
;
451 /*----------------------------------------------------------------------
452 | NPT_WinRtSocketOutputStream
453 +---------------------------------------------------------------------*/
455 NPT_WinRtSocketOutputStream::Flush()
460 /*----------------------------------------------------------------------
461 | NPT_WinRtTcpClientSocket::NPT_WinRtTcpClientSocket
462 +---------------------------------------------------------------------*/
463 NPT_WinRtTcpClientSocket::NPT_WinRtTcpClientSocket() :
464 m_ReadTimeout(NPT_WINRT_SOCKET_DEFAULT_READ_TIMEOUT
),
465 m_WriteTimeout(NPT_WINRT_SOCKET_DEFAULT_WRITE_TIMEOUT
)
467 m_Socket
= ref
new StreamSocket();
468 m_WaitEvent
= CreateEventExW(NULL
, L
"", 0, EVENT_ALL_ACCESS
);
471 /*----------------------------------------------------------------------
472 | NPT_WinRtTcpClientSocket::NPT_WinRtTcpClientSocket
473 +---------------------------------------------------------------------*/
474 NPT_WinRtTcpClientSocket::~NPT_WinRtTcpClientSocket()
476 CloseHandle(m_WaitEvent
);
479 /*----------------------------------------------------------------------
480 | NPT_WinRtTcpClientSocket::Bind
481 +---------------------------------------------------------------------*/
483 NPT_WinRtTcpClientSocket::Bind(const NPT_SocketAddress
& address
, bool reuse_address
)
485 return NPT_ERROR_NOT_IMPLEMENTED
;
488 /*----------------------------------------------------------------------
489 | NPT_WinRtTcpClientSocket::Connect
490 +---------------------------------------------------------------------*/
492 NPT_WinRtTcpClientSocket::Connect(const NPT_SocketAddress
& address
, NPT_Timeout timeout
)
495 NPT_LOG_FINE_1("connecting to %s", address
.GetIpAddress().m_HostName
.GetChars());
497 m_RemoteHostName
= ref
new HostName(StringFromUTF8(address
.GetIpAddress().m_HostName
.GetChars()));
498 String
^ remote_service
= ref
new String();
499 NPT_String port
= NPT_String::FromIntegerU(address
.GetPort());
500 IAsyncAction
^ connection
= m_Socket
->ConnectAsync(m_RemoteHostName
, StringFromUTF8(port
.GetChars()));
502 // wait for the connection to be established
503 NPT_Result result
= WaitForAsyncAction(connection
, m_WaitEvent
, timeout
);
504 if (NPT_FAILED(result
)) {
505 NPT_LOG_FINE_1("connection failed (%d)", result
);
507 NPT_LOG_FINE("connected");
510 } catch (Exception
^ e
) {
511 NPT_LOG_FINE("exception caught");
516 /*----------------------------------------------------------------------
517 | NPT_WinRtTcpClientSocket::GetInputStream
518 +---------------------------------------------------------------------*/
520 NPT_WinRtTcpClientSocket::GetInputStream(NPT_InputStreamReference
& stream
)
522 stream
= new NPT_WinRtSocketInputStream(m_Socket
, m_ReadTimeout
);
526 /*----------------------------------------------------------------------
527 | NPT_WinRtTcpClientSocket::GetOutputStream
528 +---------------------------------------------------------------------*/
530 NPT_WinRtTcpClientSocket::GetOutputStream(NPT_OutputStreamReference
& stream
)
532 stream
= new NPT_WinRtSocketOutputStream(m_Socket
, m_WriteTimeout
);
536 /*----------------------------------------------------------------------
537 | NPT_WinRtTcpClientSocket::GetInfo
538 +---------------------------------------------------------------------*/
540 NPT_WinRtTcpClientSocket::GetInfo(NPT_SocketInfo
& info
)
545 /*----------------------------------------------------------------------
546 | NPT_WinRtTcpClientSocket::SetReadTimeout
547 +---------------------------------------------------------------------*/
549 NPT_WinRtTcpClientSocket::SetReadTimeout(NPT_Timeout timeout
)
551 m_ReadTimeout
= timeout
;
555 /*----------------------------------------------------------------------
556 | NPT_WinRtTcpClientSocket::SetWriteTimeout
557 +---------------------------------------------------------------------*/
559 NPT_WinRtTcpClientSocket::SetWriteTimeout(NPT_Timeout timeout
)
561 m_WriteTimeout
= timeout
;
565 /*----------------------------------------------------------------------
566 | NPT_WinRtTcpClientSocket::Cancel
567 +---------------------------------------------------------------------*/
569 NPT_WinRtTcpClientSocket::Cancel(bool shutdown
)
574 /*----------------------------------------------------------------------
575 | NPT_Socket::~NPT_Socket
576 +---------------------------------------------------------------------*/
577 NPT_Socket::~NPT_Socket()
579 delete m_SocketDelegate
;
582 /*----------------------------------------------------------------------
583 | NPT_UdpSocket::NPT_UdpSocket
584 +---------------------------------------------------------------------*/
585 NPT_UdpSocket::NPT_UdpSocket(NPT_Flags flags
)
587 m_SocketDelegate
= NULL
;
588 m_UdpSocketDelegate
= NULL
;
591 /*----------------------------------------------------------------------
592 | NPT_UdpSocket::NPT_UdpSocket
593 +---------------------------------------------------------------------*/
594 NPT_UdpSocket::NPT_UdpSocket(NPT_UdpSocketInterface
* delegate
) :
595 m_UdpSocketDelegate(delegate
)
599 /*----------------------------------------------------------------------
600 | NPT_UdpSocket::~NPT_UdpSocket
601 +---------------------------------------------------------------------*/
602 NPT_UdpSocket::~NPT_UdpSocket()
604 m_UdpSocketDelegate
= NULL
;
605 m_SocketDelegate
= NULL
;
608 /*----------------------------------------------------------------------
609 | NPT_UdpMulticastSocket::NPT_UdpMulticastSocket
610 +---------------------------------------------------------------------*/
611 NPT_UdpMulticastSocket::NPT_UdpMulticastSocket(NPT_Flags flags
) :
612 NPT_UdpSocket((NPT_UdpSocketInterface
*)0)
614 m_SocketDelegate
= NULL
;
615 m_UdpSocketDelegate
= NULL
;
616 m_UdpMulticastSocketDelegate
= NULL
;
619 /*----------------------------------------------------------------------
620 | NPT_UdpMulticastSocket::~NPT_UdpMulticastSocket
621 +---------------------------------------------------------------------*/
622 NPT_UdpMulticastSocket::~NPT_UdpMulticastSocket()
624 m_SocketDelegate
= NULL
;
625 m_UdpSocketDelegate
= NULL
;
626 m_UdpMulticastSocketDelegate
= NULL
;
629 /*----------------------------------------------------------------------
630 | NPT_TcpClientSocket::NPT_TcpClientSocket
631 +---------------------------------------------------------------------*/
632 NPT_TcpClientSocket::NPT_TcpClientSocket(NPT_Flags flags
) :
635 m_SocketDelegate
= new NPT_WinRtTcpClientSocket();
638 /*----------------------------------------------------------------------
639 | NPT_TcpClientSocket::NPT_TcpClientSocket
640 +---------------------------------------------------------------------*/
641 NPT_TcpClientSocket::~NPT_TcpClientSocket()
643 delete m_SocketDelegate
;
645 m_SocketDelegate
= NULL
;
648 /*----------------------------------------------------------------------
649 | NPT_TcpServerSocket::NPT_TcpServerSocket
650 +---------------------------------------------------------------------*/
651 NPT_TcpServerSocket::NPT_TcpServerSocket(NPT_Flags flags
)
653 m_SocketDelegate
= NULL
;
654 m_TcpServerSocketDelegate
= NULL
;
657 /*----------------------------------------------------------------------
658 | NPT_TcpServerSocket::NPT_TcpServerSocket
659 +---------------------------------------------------------------------*/
660 NPT_TcpServerSocket::~NPT_TcpServerSocket()
662 m_SocketDelegate
= NULL
;
663 m_TcpServerSocketDelegate
= NULL
;