sock_uwp.h 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * Copyright (C) 2016 Teluu Inc. (http://www.teluu.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #pragma once
  19. #include <pj/assert.h>
  20. #include <pj/sock.h>
  21. #include <pj/string.h>
  22. #include <pj/unicode.h>
  23. enum {
  24. READ_TIMEOUT = 60 * 1000,
  25. WRITE_TIMEOUT = 60 * 1000,
  26. SEND_BUFFER_SIZE = 128 * 1024,
  27. };
  28. enum PjUwpSocketType {
  29. SOCKTYPE_UNKNOWN, SOCKTYPE_LISTENER,
  30. SOCKTYPE_STREAM, SOCKTYPE_DATAGRAM
  31. };
  32. enum PjUwpSocketState {
  33. SOCKSTATE_NULL, SOCKSTATE_INITIALIZED, SOCKSTATE_CONNECTING,
  34. SOCKSTATE_CONNECTED, SOCKSTATE_DISCONNECTED, SOCKSTATE_ERROR
  35. };
  36. ref class PjUwpSocketDatagramRecvHelper;
  37. ref class PjUwpSocketListenerHelper;
  38. class PjUwpSocket;
  39. typedef struct PjUwpSocketCallback
  40. {
  41. void (*on_read)(PjUwpSocket *s, int bytes_read);
  42. void (*on_write)(PjUwpSocket *s, int bytes_sent);
  43. void (*on_accept)(PjUwpSocket *s);
  44. void (*on_connect)(PjUwpSocket *s, pj_status_t status);
  45. } PjUwpSocketCallback;
  46. /*
  47. * UWP Socket Wrapper.
  48. */
  49. class PjUwpSocket
  50. {
  51. public:
  52. PjUwpSocket(int af_, int type_, int proto_);
  53. virtual ~PjUwpSocket();
  54. pj_status_t InitSocket(enum PjUwpSocketType sock_type_);
  55. void DeinitSocket();
  56. void* GetUserData() { return user_data; }
  57. void SetNonBlocking(const PjUwpSocketCallback *cb_, void *user_data_)
  58. {
  59. is_blocking = PJ_FALSE;
  60. cb=*cb_;
  61. user_data = user_data_;
  62. }
  63. enum PjUwpSocketType GetType() { return sock_type; }
  64. enum PjUwpSocketState GetState() { return sock_state; }
  65. pj_sockaddr* GetLocalAddr() { return &local_addr; }
  66. pj_sockaddr* GetRemoteAddr() { return &remote_addr; }
  67. pj_status_t Bind(const pj_sockaddr_t *addr = NULL);
  68. pj_status_t Send(const void *buf, pj_ssize_t *len);
  69. pj_status_t SendTo(const void *buf, pj_ssize_t *len, const pj_sockaddr_t *to);
  70. pj_status_t Recv(void *buf, pj_ssize_t *len);
  71. pj_status_t RecvFrom(void *buf, pj_ssize_t *len, pj_sockaddr_t *from);
  72. pj_status_t Connect(const pj_sockaddr_t *addr);
  73. pj_status_t Listen();
  74. pj_status_t Accept(PjUwpSocket **new_sock);
  75. void (*on_read)(PjUwpSocket *s, int bytes_read);
  76. void (*on_write)(PjUwpSocket *s, int bytes_sent);
  77. void (*on_accept)(PjUwpSocket *s, pj_status_t status);
  78. void (*on_connect)(PjUwpSocket *s, pj_status_t status);
  79. private:
  80. PjUwpSocket* CreateAcceptSocket(Windows::Networking::Sockets::StreamSocket^ stream_sock_);
  81. pj_status_t SendImp(const void *buf, pj_ssize_t *len);
  82. int ConsumeReadBuffer(void *buf, int max_len);
  83. int af;
  84. int type;
  85. int proto;
  86. pj_sockaddr local_addr;
  87. pj_sockaddr remote_addr;
  88. pj_bool_t is_blocking;
  89. pj_bool_t has_pending_bind;
  90. pj_bool_t has_pending_send;
  91. pj_bool_t has_pending_recv;
  92. void *user_data;
  93. PjUwpSocketCallback cb;
  94. enum PjUwpSocketType sock_type;
  95. enum PjUwpSocketState sock_state;
  96. Windows::Networking::Sockets::DatagramSocket^ datagram_sock;
  97. Windows::Networking::Sockets::StreamSocket^ stream_sock;
  98. Windows::Networking::Sockets::StreamSocketListener^ listener_sock;
  99. /* Helper objects */
  100. PjUwpSocketDatagramRecvHelper^ dgram_recv_helper;
  101. PjUwpSocketListenerHelper^ listener_helper;
  102. Windows::Storage::Streams::DataReader^ socket_reader;
  103. Windows::Storage::Streams::DataWriter^ socket_writer;
  104. Windows::Storage::Streams::IBuffer^ send_buffer;
  105. friend PjUwpSocketDatagramRecvHelper;
  106. friend PjUwpSocketListenerHelper;
  107. };
  108. //////////////////////////////////
  109. // Misc
  110. inline pj_status_t wstr_addr_to_sockaddr(const wchar_t *waddr,
  111. const wchar_t *wport,
  112. pj_sockaddr_t *sockaddr)
  113. {
  114. #if 0
  115. char tmp_str_buf[PJ_INET6_ADDRSTRLEN+1];
  116. pj_assert(wcslen(waddr) < sizeof(tmp_str_buf));
  117. pj_unicode_to_ansi(waddr, wcslen(waddr), tmp_str_buf, sizeof(tmp_str_buf));
  118. pj_str_t remote_host;
  119. pj_strset(&remote_host, tmp_str_buf, pj_ansi_strlen(tmp_str_buf));
  120. pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &remote_host, (pj_sockaddr*)sockaddr);
  121. pj_sockaddr_set_port((pj_sockaddr*)sockaddr, (pj_uint16_t)_wtoi(wport));
  122. return PJ_SUCCESS;
  123. #endif
  124. char tmp_str_buf[PJ_INET6_ADDRSTRLEN+1];
  125. pj_assert(wcslen(waddr) < sizeof(tmp_str_buf));
  126. pj_unicode_to_ansi(waddr, wcslen(waddr), tmp_str_buf, sizeof(tmp_str_buf));
  127. pj_str_t remote_host;
  128. pj_strset(&remote_host, tmp_str_buf, pj_ansi_strlen(tmp_str_buf));
  129. pj_sockaddr *addr = (pj_sockaddr*)sockaddr;
  130. pj_bool_t got_addr = PJ_FALSE;
  131. if (pj_inet_pton(PJ_AF_INET, &remote_host, &addr->ipv4.sin_addr)
  132. == PJ_SUCCESS)
  133. {
  134. addr->addr.sa_family = PJ_AF_INET;
  135. got_addr = PJ_TRUE;
  136. } else if (pj_inet_pton(PJ_AF_INET6, &remote_host, &addr->ipv6.sin6_addr)
  137. == PJ_SUCCESS)
  138. {
  139. addr->addr.sa_family = PJ_AF_INET6;
  140. got_addr = PJ_TRUE;
  141. }
  142. if (!got_addr)
  143. return PJ_EINVAL;
  144. pj_sockaddr_set_port(addr, (pj_uint16_t)_wtoi(wport));
  145. return PJ_SUCCESS;
  146. }
  147. inline pj_status_t sockaddr_to_hostname_port(const pj_sockaddr_t *sockaddr,
  148. Windows::Networking::HostName ^&hostname,
  149. int *port)
  150. {
  151. char tmp[PJ_INET6_ADDRSTRLEN];
  152. wchar_t wtmp[PJ_INET6_ADDRSTRLEN];
  153. pj_sockaddr_print(sockaddr, tmp, PJ_INET6_ADDRSTRLEN, 0);
  154. pj_ansi_to_unicode(tmp, pj_ansi_strlen(tmp), wtmp,
  155. PJ_INET6_ADDRSTRLEN);
  156. hostname = ref new Windows::Networking::HostName(ref new Platform::String(wtmp));
  157. *port = pj_sockaddr_get_port(sockaddr);
  158. return PJ_SUCCESS;
  159. }
  160. /* Buffer helper */
  161. #include <Robuffer.h>
  162. #include <wrl/client.h>
  163. inline Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> GetBufferByteAccess(Windows::Storage::Streams::IBuffer^ buffer)
  164. {
  165. auto pUnk = reinterpret_cast<IUnknown*>(buffer);
  166. Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> comBuff;
  167. pUnk->QueryInterface(__uuidof(Windows::Storage::Streams::IBufferByteAccess), (void**)comBuff.ReleaseAndGetAddressOf());
  168. return comBuff;
  169. }
  170. inline void GetRawBufferFromIBuffer(Windows::Storage::Streams::IBuffer^ buffer, unsigned char** pbuffer)
  171. {
  172. Platform::Object^ obj = buffer;
  173. Microsoft::WRL::ComPtr<IInspectable> insp(reinterpret_cast<IInspectable*>(obj));
  174. Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
  175. insp.As(&bufferByteAccess);
  176. bufferByteAccess->Buffer(pbuffer);
  177. }
  178. inline void CopyToIBuffer(unsigned char* buffSource, unsigned int copyByteCount, Windows::Storage::Streams::IBuffer^ buffer, unsigned int writeStartPos = 0)
  179. {
  180. auto bufferLen = buffer->Capacity;
  181. assert(copyByteCount <= bufferLen);
  182. unsigned char* pBuffer;
  183. GetRawBufferFromIBuffer(buffer, &pBuffer);
  184. memcpy(pBuffer + writeStartPos, buffSource, copyByteCount);
  185. }
  186. inline void CopyFromIBuffer(unsigned char* buffDestination, unsigned int copyByteCount, Windows::Storage::Streams::IBuffer^ buffer, unsigned int readStartPos = 0)
  187. {
  188. assert(copyByteCount <= buffer->Capacity);
  189. unsigned char* pBuffer;
  190. GetRawBufferFromIBuffer(buffer, &pBuffer);
  191. memcpy(buffDestination, pBuffer + readStartPos, copyByteCount);
  192. }
  193. /* PPL helper */
  194. #include <ppltasks.h>
  195. #include <agents.h>
  196. // Creates a task that completes after the specified delay, in ms.
  197. inline concurrency::task<void> complete_after(unsigned int timeout)
  198. {
  199. // A task completion event that is set when a timer fires.
  200. concurrency::task_completion_event<void> tce;
  201. // Create a non-repeating timer.
  202. auto fire_once = new concurrency::timer<int>(timeout, 0, nullptr, false);
  203. // Create a call object that sets the completion event after the timer fires.
  204. auto callback = new concurrency::call<int>([tce](int)
  205. {
  206. tce.set();
  207. });
  208. // Connect the timer to the callback and start the timer.
  209. fire_once->link_target(callback);
  210. fire_once->start();
  211. // Create a task that completes after the completion event is set.
  212. concurrency::task<void> event_set(tce);
  213. // Create a continuation task that cleans up resources and
  214. // and return that continuation task.
  215. return event_set.then([callback, fire_once]()
  216. {
  217. delete callback;
  218. delete fire_once;
  219. });
  220. }
  221. // Cancels the provided task after the specifed delay, if the task
  222. // did not complete.
  223. template<typename T>
  224. inline concurrency::task<T> cancel_after_timeout(concurrency::task<T> t, concurrency::cancellation_token_source cts, unsigned int timeout)
  225. {
  226. // Create a task that returns true after the specified task completes.
  227. concurrency::task<bool> success_task = t.then([](T)
  228. {
  229. return true;
  230. });
  231. // Create a task that returns false after the specified timeout.
  232. concurrency::task<bool> failure_task = complete_after(timeout).then([]
  233. {
  234. return false;
  235. });
  236. // Create a continuation task that cancels the overall task
  237. // if the timeout task finishes first.
  238. return (failure_task || success_task).then([t, cts](bool success)
  239. {
  240. if (!success)
  241. {
  242. // Set the cancellation token. The task that is passed as the
  243. // t parameter should respond to the cancellation and stop
  244. // as soon as it can.
  245. cts.cancel();
  246. }
  247. // Return the original task.
  248. return t;
  249. });
  250. }