1 /* $Id$ */
2 /*
3 * Copyright (C) 2016 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include <pj/assert.h>
20 #include <pj/errno.h>
21 #include <pj/math.h>
22 #include <pj/os.h>
23 #include <pj/compat/socket.h>
24
25 #include <ppltasks.h>
26 #include <string>
27
28 #define THIS_FILE "sock_uwp.cpp"
29
30 #include "sock_uwp.h"
31
32 /*
33 * Address families conversion.
34 * The values here are indexed based on pj_addr_family.
35 */
36 const pj_uint16_t PJ_AF_UNSPEC = AF_UNSPEC;
37 const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
38 const pj_uint16_t PJ_AF_INET = AF_INET;
39 const pj_uint16_t PJ_AF_INET6 = AF_INET6;
40 #ifdef AF_PACKET
41 const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
42 #else
43 const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
44 #endif
45 #ifdef AF_IRDA
46 const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
47 #else
48 const pj_uint16_t PJ_AF_IRDA = 0xFFFF;
49 #endif
50
51 /*
52 * Socket types conversion.
53 * The values here are indexed based on pj_sock_type
54 */
55 const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
56 const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
57 const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
58 const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
59
60 /*
61 * Socket level values.
62 */
63 const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
64 #ifdef SOL_IP
65 const pj_uint16_t PJ_SOL_IP = SOL_IP;
66 #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
67 const pj_uint16_t PJ_SOL_IP = IPPROTO_IP;
68 #else
69 const pj_uint16_t PJ_SOL_IP = 0;
70 #endif /* SOL_IP */
71
72 #if defined(SOL_TCP)
73 const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
74 #elif defined(IPPROTO_TCP)
75 const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
76 #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
77 const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
78 #else
79 const pj_uint16_t PJ_SOL_TCP = 6;
80 #endif /* SOL_TCP */
81
82 #ifdef SOL_UDP
83 const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
84 #elif defined(IPPROTO_UDP)
85 const pj_uint16_t PJ_SOL_UDP = IPPROTO_UDP;
86 #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
87 const pj_uint16_t PJ_SOL_UDP = IPPROTO_UDP;
88 #else
89 const pj_uint16_t PJ_SOL_UDP = 17;
90 #endif /* SOL_UDP */
91
92 #ifdef SOL_IPV6
93 const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
94 #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
95 # if defined(IPPROTO_IPV6) || (_WIN32_WINNT >= 0x0501)
96 const pj_uint16_t PJ_SOL_IPV6 = IPPROTO_IPV6;
97 # else
98 const pj_uint16_t PJ_SOL_IPV6 = 41;
99 # endif
100 #else
101 const pj_uint16_t PJ_SOL_IPV6 = 41;
102 #endif /* SOL_IPV6 */
103
104 /* IP_TOS */
105 #ifdef IP_TOS
106 const pj_uint16_t PJ_IP_TOS = IP_TOS;
107 #else
108 const pj_uint16_t PJ_IP_TOS = 1;
109 #endif
110
111
112 /* TOS settings (declared in netinet/ip.h) */
113 #ifdef IPTOS_LOWDELAY
114 const pj_uint16_t PJ_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
115 #else
116 const pj_uint16_t PJ_IPTOS_LOWDELAY = 0x10;
117 #endif
118 #ifdef IPTOS_THROUGHPUT
119 const pj_uint16_t PJ_IPTOS_THROUGHPUT = IPTOS_THROUGHPUT;
120 #else
121 const pj_uint16_t PJ_IPTOS_THROUGHPUT = 0x08;
122 #endif
123 #ifdef IPTOS_RELIABILITY
124 const pj_uint16_t PJ_IPTOS_RELIABILITY = IPTOS_RELIABILITY;
125 #else
126 const pj_uint16_t PJ_IPTOS_RELIABILITY = 0x04;
127 #endif
128 #ifdef IPTOS_MINCOST
129 const pj_uint16_t PJ_IPTOS_MINCOST = IPTOS_MINCOST;
130 #else
131 const pj_uint16_t PJ_IPTOS_MINCOST = 0x02;
132 #endif
133
134
135 /* optname values. */
136 const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
137 const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
138 const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
139 const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
140 const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
141 #ifdef SO_NOSIGPIPE
142 const pj_uint16_t PJ_SO_NOSIGPIPE = SO_NOSIGPIPE;
143 #else
144 const pj_uint16_t PJ_SO_NOSIGPIPE = 0xFFFF;
145 #endif
146 #if defined(SO_PRIORITY)
147 const pj_uint16_t PJ_SO_PRIORITY = SO_PRIORITY;
148 #else
149 /* This is from Linux, YMMV */
150 const pj_uint16_t PJ_SO_PRIORITY = 12;
151 #endif
152
153 /* Multicasting is not supported e.g. in PocketPC 2003 SDK */
154 #ifdef IP_MULTICAST_IF
155 const pj_uint16_t PJ_IP_MULTICAST_IF = IP_MULTICAST_IF;
156 const pj_uint16_t PJ_IP_MULTICAST_TTL = IP_MULTICAST_TTL;
157 const pj_uint16_t PJ_IP_MULTICAST_LOOP = IP_MULTICAST_LOOP;
158 const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = IP_ADD_MEMBERSHIP;
159 const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
160 #else
161 const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
162 const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
163 const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
164 const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
165 const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
166 #endif
167
168 /* recv() and send() flags */
169 const int PJ_MSG_OOB = MSG_OOB;
170 const int PJ_MSG_PEEK = MSG_PEEK;
171 const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
172
173
174
175 using namespace Platform;
176 using namespace Windows::Foundation;
177 using namespace Windows::Networking;
178 using namespace Windows::Networking::Sockets;
179 using namespace Windows::Storage::Streams;
180
181
182 ref class PjUwpSocketDatagramRecvHelper sealed
183 {
184 internal:
185 PjUwpSocketDatagramRecvHelper(PjUwpSocket* uwp_sock_) :
186 uwp_sock(uwp_sock_), avail_data_len(0), recv_args(nullptr)
187 {
188 recv_wait = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
189 event_token = uwp_sock->datagram_sock->MessageReceived +=
190 ref new TypedEventHandler<DatagramSocket^,
191 DatagramSocketMessageReceivedEventArgs^>
192 (this, &PjUwpSocketDatagramRecvHelper::OnMessageReceived);
193 }
194
195 void OnMessageReceived(DatagramSocket ^sender,
196 DatagramSocketMessageReceivedEventArgs ^args)
197 {
198 try {
199 if (uwp_sock->sock_state >= SOCKSTATE_DISCONNECTED)
200 return;
201
202 recv_args = args;
203 avail_data_len = args->GetDataReader()->UnconsumedBufferLength;
204
205 if (uwp_sock->cb.on_read) {
206 (*uwp_sock->cb.on_read)(uwp_sock, avail_data_len);
207 }
208
209 WaitForSingleObjectEx(recv_wait, INFINITE, false);
210 } catch (...) {}
211 }
212
ReadDataIfAvailable(void * buf,pj_ssize_t * len,pj_sockaddr_t * from)213 pj_status_t ReadDataIfAvailable(void *buf, pj_ssize_t *len,
214 pj_sockaddr_t *from)
215 {
216 if (avail_data_len <= 0)
217 return PJ_ENOTFOUND;
218
219 if (*len < avail_data_len)
220 return PJ_ETOOSMALL;
221
222 // Read data
223 auto reader = recv_args->GetDataReader();
224 auto buffer = reader->ReadBuffer(avail_data_len);
225 unsigned char *p;
226 GetRawBufferFromIBuffer(buffer, &p);
227 pj_memcpy((void*) buf, p, avail_data_len);
228 *len = avail_data_len;
229
230 // Get source address
231 wstr_addr_to_sockaddr(recv_args->RemoteAddress->CanonicalName->Data(),
232 recv_args->RemotePort->Data(), from);
233
234 // finally
235 avail_data_len = 0;
236 SetEvent(recv_wait);
237
238 return PJ_SUCCESS;
239 }
240
241 private:
242
~PjUwpSocketDatagramRecvHelper()243 ~PjUwpSocketDatagramRecvHelper()
244 {
245 if (uwp_sock->datagram_sock)
246 uwp_sock->datagram_sock->MessageReceived -= event_token;
247
248 SetEvent(recv_wait);
249 CloseHandle(recv_wait);
250 }
251
252 PjUwpSocket* uwp_sock;
253 DatagramSocketMessageReceivedEventArgs^ recv_args;
254 EventRegistrationToken event_token;
255 HANDLE recv_wait;
256 int avail_data_len;
257 };
258
259
260 ref class PjUwpSocketListenerHelper sealed
261 {
262 internal:
263 PjUwpSocketListenerHelper(PjUwpSocket* uwp_sock_) :
264 uwp_sock(uwp_sock_), conn_args(nullptr)
265 {
266 conn_wait = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
267 event_token = uwp_sock->listener_sock->ConnectionReceived +=
268 ref new TypedEventHandler<StreamSocketListener^, StreamSocketListenerConnectionReceivedEventArgs^>
269 (this, &PjUwpSocketListenerHelper::OnConnectionReceived);
270 }
271
272 void OnConnectionReceived(StreamSocketListener ^sender,
273 StreamSocketListenerConnectionReceivedEventArgs ^args)
274 {
275 try {
276 conn_args = args;
277
278 if (uwp_sock->cb.on_accept) {
279 (*uwp_sock->cb.on_accept)(uwp_sock);
280 }
281
282 WaitForSingleObjectEx(conn_wait, INFINITE, false);
283 } catch (Exception^ e) {}
284 }
285
286 pj_status_t GetAcceptedSocket(StreamSocket^& stream_sock)
287 {
288 if (conn_args == nullptr)
289 return PJ_ENOTFOUND;
290
291 stream_sock = conn_args->Socket;
292
293 // finally
294 conn_args = nullptr;
295 SetEvent(conn_wait);
296
297 return PJ_SUCCESS;
298 }
299
300 private:
301
~PjUwpSocketListenerHelper()302 ~PjUwpSocketListenerHelper()
303 {
304 if (uwp_sock->listener_sock)
305 uwp_sock->listener_sock->ConnectionReceived -= event_token;
306
307 SetEvent(conn_wait);
308 CloseHandle(conn_wait);
309 }
310
311 PjUwpSocket* uwp_sock;
312 StreamSocketListenerConnectionReceivedEventArgs^ conn_args;
313 EventRegistrationToken event_token;
314 HANDLE conn_wait;
315 };
316
317
PjUwpSocket(int af_,int type_,int proto_)318 PjUwpSocket::PjUwpSocket(int af_, int type_, int proto_) :
319 af(af_), type(type_), proto(proto_),
320 sock_type(SOCKTYPE_UNKNOWN),
321 sock_state(SOCKSTATE_NULL),
322 is_blocking(PJ_TRUE),
323 has_pending_bind(PJ_FALSE),
324 has_pending_send(PJ_FALSE),
325 has_pending_recv(PJ_FALSE)
326 {
327 pj_sockaddr_init(pj_AF_INET(), &local_addr, NULL, 0);
328 pj_sockaddr_init(pj_AF_INET(), &remote_addr, NULL, 0);
329 }
330
~PjUwpSocket()331 PjUwpSocket::~PjUwpSocket()
332 {
333 DeinitSocket();
334 }
335
336 PjUwpSocket* PjUwpSocket::CreateAcceptSocket(Windows::Networking::Sockets::StreamSocket^ stream_sock_)
337 {
338 PjUwpSocket *new_sock = new PjUwpSocket(pj_AF_INET(), pj_SOCK_STREAM(), 0);
339 new_sock->stream_sock = stream_sock_;
340 new_sock->sock_type = SOCKTYPE_STREAM;
341 new_sock->sock_state = SOCKSTATE_CONNECTED;
342 new_sock->socket_reader = ref new DataReader(new_sock->stream_sock->InputStream);
343 new_sock->socket_writer = ref new DataWriter(new_sock->stream_sock->OutputStream);
344 new_sock->socket_reader->InputStreamOptions = InputStreamOptions::Partial;
345 new_sock->send_buffer = ref new Buffer(SEND_BUFFER_SIZE);
346 new_sock->is_blocking = is_blocking;
347
348 // Update local & remote address
349 wstr_addr_to_sockaddr(stream_sock_->Information->RemoteAddress->CanonicalName->Data(),
350 stream_sock_->Information->RemotePort->Data(),
351 &new_sock->remote_addr);
352 wstr_addr_to_sockaddr(stream_sock_->Information->LocalAddress->CanonicalName->Data(),
353 stream_sock_->Information->LocalPort->Data(),
354 &new_sock->local_addr);
355
356 return new_sock;
357 }
358
359
InitSocket(enum PjUwpSocketType sock_type_)360 pj_status_t PjUwpSocket::InitSocket(enum PjUwpSocketType sock_type_)
361 {
362 PJ_ASSERT_RETURN(sock_type_ > SOCKTYPE_UNKNOWN, PJ_EINVAL);
363
364 sock_type = sock_type_;
365 if (sock_type == SOCKTYPE_LISTENER) {
366 listener_sock = ref new StreamSocketListener();
367 } else if (sock_type == SOCKTYPE_STREAM) {
368 stream_sock = ref new StreamSocket();
369 } else if (sock_type == SOCKTYPE_DATAGRAM) {
370 datagram_sock = ref new DatagramSocket();
371 } else {
372 pj_assert(!"Invalid socket type");
373 return PJ_EINVAL;
374 }
375
376 if (sock_type == SOCKTYPE_DATAGRAM || sock_type == SOCKTYPE_STREAM) {
377 send_buffer = ref new Buffer(SEND_BUFFER_SIZE);
378 }
379
380 sock_state = SOCKSTATE_INITIALIZED;
381
382 return PJ_SUCCESS;
383 }
384
385
DeinitSocket()386 void PjUwpSocket::DeinitSocket()
387 {
388 if (stream_sock) {
389 concurrency::create_task(stream_sock->CancelIOAsync()).wait();
390 }
391 if (datagram_sock && has_pending_send) {
392 concurrency::create_task(datagram_sock->CancelIOAsync()).wait();
393 }
394 if (listener_sock) {
395 concurrency::create_task(listener_sock->CancelIOAsync()).wait();
396 }
397 while (has_pending_recv) pj_thread_sleep(10);
398
399 stream_sock = nullptr;
400 datagram_sock = nullptr;
401 dgram_recv_helper = nullptr;
402 listener_sock = nullptr;
403 listener_helper = nullptr;
404 socket_writer = nullptr;
405 socket_reader = nullptr;
406 sock_state = SOCKSTATE_NULL;
407 }
408
Bind(const pj_sockaddr_t * addr)409 pj_status_t PjUwpSocket::Bind(const pj_sockaddr_t *addr)
410 {
411 /* Not initialized yet, socket type is perhaps TCP, just not decided yet
412 * whether it is a stream or a listener.
413 */
414 if (sock_state < SOCKSTATE_INITIALIZED) {
415 pj_sockaddr_cp(&local_addr, addr);
416 has_pending_bind = PJ_TRUE;
417 return PJ_SUCCESS;
418 }
419
420 PJ_ASSERT_RETURN(sock_state == SOCKSTATE_INITIALIZED, PJ_EINVALIDOP);
421 if (sock_type != SOCKTYPE_DATAGRAM && sock_type != SOCKTYPE_LISTENER)
422 return PJ_EINVALIDOP;
423
424 if (has_pending_bind) {
425 has_pending_bind = PJ_FALSE;
426 if (!addr)
427 addr = &local_addr;
428 }
429
430 /* If no bound address is set, just return */
431 if (!pj_sockaddr_has_addr(addr) && !pj_sockaddr_get_port(addr))
432 return PJ_SUCCESS;
433
434 if (addr != &local_addr)
435 pj_sockaddr_cp(&local_addr, addr);
436
437 HRESULT err = 0;
438 concurrency::create_task([this, addr, &err]() {
439 HostName ^host;
440 int port;
441
442 sockaddr_to_hostname_port(addr, host, &port);
443 if (pj_sockaddr_has_addr(addr)) {
444 if (sock_type == SOCKTYPE_DATAGRAM)
445 return datagram_sock->BindEndpointAsync(host, port.ToString());
446 else
447 return listener_sock->BindEndpointAsync(host, port.ToString());
448 } else /* if (pj_sockaddr_get_port(addr) != 0) */ {
449 if (sock_type == SOCKTYPE_DATAGRAM)
450 return datagram_sock->BindServiceNameAsync(port.ToString());
451 else
452 return listener_sock->BindServiceNameAsync(port.ToString());
453 }
454 }).then([this, &err](concurrency::task<void> t)
455 {
456 try {
457 if (!err)
458 t.get();
459 } catch (Exception^ e) {
460 err = e->HResult;
461 }
462 }).get();
463
464 return (err? PJ_RETURN_OS_ERROR(err) : PJ_SUCCESS);
465 }
466
467
SendImp(const void * buf,pj_ssize_t * len)468 pj_status_t PjUwpSocket::SendImp(const void *buf, pj_ssize_t *len)
469 {
470 if (has_pending_send)
471 return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
472
473 if (*len > (pj_ssize_t)send_buffer->Capacity)
474 return PJ_ETOOBIG;
475
476 CopyToIBuffer((unsigned char*)buf, *len, send_buffer);
477 send_buffer->Length = *len;
478 socket_writer->WriteBuffer(send_buffer);
479
480 /* Blocking version */
481 if (is_blocking) {
482 pj_status_t status = PJ_SUCCESS;
483 concurrency::cancellation_token_source cts;
484 auto cts_token = cts.get_token();
485 auto t = concurrency::create_task(socket_writer->StoreAsync(),
486 cts_token);
487 *len = cancel_after_timeout(t, cts, (unsigned int)WRITE_TIMEOUT).
488 then([cts_token, &status](concurrency::task<unsigned int> t_)
489 {
490 int sent = 0;
491 try {
492 if (cts_token.is_canceled())
493 status = PJ_ETIMEDOUT;
494 else
495 sent = t_.get();
496 } catch (Exception^ e) {
497 status = PJ_RETURN_OS_ERROR(e->HResult);
498 }
499 return sent;
500 }).get();
501
502 return status;
503 }
504
505 /* Non-blocking version */
506 has_pending_send = PJ_TRUE;
507 concurrency::create_task(socket_writer->StoreAsync()).
508 then([this](concurrency::task<unsigned int> t_)
509 {
510 try {
511 unsigned int l = t_.get();
512 has_pending_send = PJ_FALSE;
513
514 // invoke callback
515 if (cb.on_write) {
516 (*cb.on_write)(this, l);
517 }
518 } catch (...) {
519 has_pending_send = PJ_FALSE;
520 sock_state = SOCKSTATE_ERROR;
521 DeinitSocket();
522
523 // invoke callback
524 if (cb.on_write) {
525 (*cb.on_write)(this, -PJ_EUNKNOWN);
526 }
527 }
528 });
529
530 return PJ_SUCCESS;
531 }
532
533
Send(const void * buf,pj_ssize_t * len)534 pj_status_t PjUwpSocket::Send(const void *buf, pj_ssize_t *len)
535 {
536 if ((sock_type!=SOCKTYPE_STREAM && sock_type!=SOCKTYPE_DATAGRAM) ||
537 (sock_state!=SOCKSTATE_CONNECTED))
538 {
539 return PJ_EINVALIDOP;
540 }
541
542 /* Sending for SOCKTYPE_DATAGRAM is implemented in pj_sock_sendto() */
543 if (sock_type == SOCKTYPE_DATAGRAM) {
544 return SendTo(buf, len, &remote_addr);
545 }
546
547 return SendImp(buf, len);
548 }
549
550
SendTo(const void * buf,pj_ssize_t * len,const pj_sockaddr_t * to)551 pj_status_t PjUwpSocket::SendTo(const void *buf, pj_ssize_t *len,
552 const pj_sockaddr_t *to)
553 {
554 if (sock_type != SOCKTYPE_DATAGRAM || sock_state < SOCKSTATE_INITIALIZED
555 || sock_state >= SOCKSTATE_DISCONNECTED)
556 {
557 return PJ_EINVALIDOP;
558 }
559
560 if (has_pending_send)
561 return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
562
563 if (*len > (pj_ssize_t)send_buffer->Capacity)
564 return PJ_ETOOBIG;
565
566 HostName ^hostname;
567 int port;
568 sockaddr_to_hostname_port(to, hostname, &port);
569
570 concurrency::cancellation_token_source cts;
571 auto cts_token = cts.get_token();
572 auto t = concurrency::create_task(datagram_sock->GetOutputStreamAsync(
573 hostname, port.ToString()), cts_token);
574 pj_status_t status = PJ_SUCCESS;
575
576 cancel_after_timeout(t, cts, (unsigned int)WRITE_TIMEOUT).
577 then([this, cts_token, &status](concurrency::task<IOutputStream^> t_)
578 {
579 try {
580 if (cts_token.is_canceled()) {
581 status = PJ_ETIMEDOUT;
582 } else {
583 IOutputStream^ outstream = t_.get();
584 socket_writer = ref new DataWriter(outstream);
585 }
586 } catch (Exception^ e) {
587 status = PJ_RETURN_OS_ERROR(e->HResult);
588 }
589 }).get();
590
591 if (status != PJ_SUCCESS)
592 return status;
593
594 status = SendImp(buf, len);
595 if ((status == PJ_SUCCESS || status == PJ_EPENDING) &&
596 sock_state < SOCKSTATE_CONNECTED)
597 {
598 sock_state = SOCKSTATE_CONNECTED;
599 }
600
601 return status;
602 }
603
604
ConsumeReadBuffer(void * buf,int max_len)605 int PjUwpSocket::ConsumeReadBuffer(void *buf, int max_len)
606 {
607 if (socket_reader->UnconsumedBufferLength == 0)
608 return 0;
609
610 int read_len = PJ_MIN((int)socket_reader->UnconsumedBufferLength,max_len);
611 IBuffer^ buffer = socket_reader->ReadBuffer(read_len);
612 read_len = buffer->Length;
613 CopyFromIBuffer((unsigned char*)buf, read_len, buffer);
614 return read_len;
615 }
616
617
Recv(void * buf,pj_ssize_t * len)618 pj_status_t PjUwpSocket::Recv(void *buf, pj_ssize_t *len)
619 {
620 /* Only for TCP, at least for now! */
621 if (sock_type == SOCKTYPE_DATAGRAM)
622 return PJ_ENOTSUP;
623
624 if (sock_type != SOCKTYPE_STREAM || sock_state != SOCKSTATE_CONNECTED)
625 return PJ_EINVALIDOP;
626
627 if (has_pending_recv)
628 return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
629
630 /* First check if there is already some data in the read buffer */
631 if (buf) {
632 int avail_len = ConsumeReadBuffer(buf, *len);
633 if (avail_len > 0) {
634 *len = avail_len;
635 return PJ_SUCCESS;
636 }
637 }
638
639 /* Blocking version */
640 if (is_blocking) {
641 pj_status_t status = PJ_SUCCESS;
642 concurrency::cancellation_token_source cts;
643 auto cts_token = cts.get_token();
644 auto t = concurrency::create_task(socket_reader->LoadAsync(*len),
645 cts_token);
646 *len = cancel_after_timeout(t, cts, READ_TIMEOUT)
647 .then([this, len, buf, cts_token, &status]
648 (concurrency::task<unsigned int> t_)
649 {
650 try {
651 if (cts_token.is_canceled()) {
652 status = PJ_ETIMEDOUT;
653 return 0;
654 }
655 t_.get();
656 } catch (Exception^) {
657 status = PJ_ETIMEDOUT;
658 return 0;
659 }
660
661 *len = ConsumeReadBuffer(buf, *len);
662 return (int)*len;
663 }).get();
664
665 return status;
666 }
667
668 /* Non-blocking version */
669
670 concurrency::cancellation_token_source cts;
671 auto cts_token = cts.get_token();
672
673 has_pending_recv = PJ_TRUE;
674 concurrency::create_task(socket_reader->LoadAsync(*len), cts_token)
675 .then([this, cts_token](concurrency::task<unsigned int> t_)
676 {
677 try {
678 if (cts_token.is_canceled()) {
679 has_pending_recv = PJ_FALSE;
680
681 // invoke callback
682 if (cb.on_read) {
683 (*cb.on_read)(this, -PJ_EUNKNOWN);
684 }
685 return;
686 }
687
688 t_.get();
689 has_pending_recv = PJ_FALSE;
690
691 // invoke callback
692 int read_len = socket_reader->UnconsumedBufferLength;
693 if (read_len > 0 && cb.on_read) {
694 (*cb.on_read)(this, read_len);
695 }
696 } catch (...) {
697 has_pending_recv = PJ_FALSE;
698
699 // invoke callback
700 if (cb.on_read) {
701 (*cb.on_read)(this, -PJ_EUNKNOWN);
702 }
703 }
704 });
705
706 return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
707 }
708
709
RecvFrom(void * buf,pj_ssize_t * len,pj_sockaddr_t * from)710 pj_status_t PjUwpSocket::RecvFrom(void *buf, pj_ssize_t *len,
711 pj_sockaddr_t *from)
712 {
713 if (sock_type != SOCKTYPE_DATAGRAM || sock_state < SOCKSTATE_INITIALIZED
714 || sock_state >= SOCKSTATE_DISCONNECTED)
715 {
716 return PJ_EINVALIDOP;
717 }
718
719 /* Start receive, if not yet */
720 if (dgram_recv_helper == nullptr) {
721 dgram_recv_helper = ref new PjUwpSocketDatagramRecvHelper(this);
722 }
723
724 /* Try to read any available data first */
725 if (buf || is_blocking) {
726 pj_status_t status;
727 status = dgram_recv_helper->ReadDataIfAvailable(buf, len, from);
728 if (status != PJ_ENOTFOUND)
729 return status;
730 }
731
732 /* Blocking version */
733 if (is_blocking) {
734 int max_loop = 0;
735 pj_status_t status = PJ_ENOTFOUND;
736 while (status == PJ_ENOTFOUND && sock_state <= SOCKSTATE_CONNECTED)
737 {
738 status = dgram_recv_helper->ReadDataIfAvailable(buf, len, from);
739 if (status != PJ_SUCCESS)
740 pj_thread_sleep(100);
741
742 if (++max_loop > 10)
743 return PJ_ETIMEDOUT;
744 }
745 return status;
746 }
747
748 /* For non-blocking version, just return PJ_EPENDING */
749 return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
750 }
751
752
Connect(const pj_sockaddr_t * addr)753 pj_status_t PjUwpSocket::Connect(const pj_sockaddr_t *addr)
754 {
755 pj_status_t status;
756
757 PJ_ASSERT_RETURN((sock_type == SOCKTYPE_UNKNOWN && sock_state == SOCKSTATE_NULL) ||
758 (sock_type == SOCKTYPE_DATAGRAM && sock_state == SOCKSTATE_INITIALIZED),
759 PJ_EINVALIDOP);
760
761 if (sock_type == SOCKTYPE_UNKNOWN) {
762 InitSocket(SOCKTYPE_STREAM);
763 // No need to check pending bind, no bind for TCP client socket
764 }
765
766 pj_sockaddr_cp(&remote_addr, addr);
767
768 auto t = concurrency::create_task([this, addr]()
769 {
770 HostName ^hostname;
771 int port;
772 sockaddr_to_hostname_port(&remote_addr, hostname, &port);
773 if (sock_type == SOCKTYPE_STREAM)
774 return stream_sock->ConnectAsync(hostname, port.ToString(),
775 SocketProtectionLevel::PlainSocket);
776 else
777 return datagram_sock->ConnectAsync(hostname, port.ToString());
778 }).then([=](concurrency::task<void> t_)
779 {
780 try {
781 t_.get();
782
783 sock_state = SOCKSTATE_CONNECTED;
784
785 // Update local & remote address
786 HostName^ local_address;
787 String^ local_port;
788
789 if (sock_type == SOCKTYPE_STREAM) {
790 local_address = stream_sock->Information->LocalAddress;
791 local_port = stream_sock->Information->LocalPort;
792
793 socket_reader = ref new DataReader(stream_sock->InputStream);
794 socket_writer = ref new DataWriter(stream_sock->OutputStream);
795 socket_reader->InputStreamOptions = InputStreamOptions::Partial;
796 } else {
797 local_address = datagram_sock->Information->LocalAddress;
798 local_port = datagram_sock->Information->LocalPort;
799 }
800 if (local_address && local_port) {
801 wstr_addr_to_sockaddr(local_address->CanonicalName->Data(),
802 local_port->Data(),
803 &local_addr);
804 }
805
806 if (!is_blocking && cb.on_connect) {
807 (*cb.on_connect)(this, PJ_SUCCESS);
808 }
809 return (pj_status_t)PJ_SUCCESS;
810
811 } catch (Exception^ ex) {
812
813 SocketErrorStatus status = SocketError::GetStatus(ex->HResult);
814
815 switch (status)
816 {
817 case SocketErrorStatus::UnreachableHost:
818 break;
819 case SocketErrorStatus::ConnectionTimedOut:
820 break;
821 case SocketErrorStatus::ConnectionRefused:
822 break;
823 default:
824 break;
825 }
826
827 if (!is_blocking && cb.on_connect) {
828 (*cb.on_connect)(this, PJ_EUNKNOWN);
829 }
830
831 return (pj_status_t)PJ_EUNKNOWN;
832 }
833 });
834
835 if (!is_blocking)
836 return PJ_RETURN_OS_ERROR(PJ_BLOCKING_CONNECT_ERROR_VAL);
837
838 try {
839 status = t.get();
840 } catch (Exception^) {
841 return PJ_EUNKNOWN;
842 }
843 return status;
844 }
845
Listen()846 pj_status_t PjUwpSocket::Listen()
847 {
848 PJ_ASSERT_RETURN((sock_type == SOCKTYPE_UNKNOWN) ||
849 (sock_type == SOCKTYPE_LISTENER &&
850 sock_state == SOCKSTATE_INITIALIZED),
851 PJ_EINVALIDOP);
852
853 if (sock_type == SOCKTYPE_UNKNOWN)
854 InitSocket(SOCKTYPE_LISTENER);
855
856 if (has_pending_bind)
857 Bind();
858
859 /* Start listen */
860 if (listener_helper == nullptr) {
861 listener_helper = ref new PjUwpSocketListenerHelper(this);
862 }
863
864 return PJ_SUCCESS;
865 }
866
Accept(PjUwpSocket ** new_sock)867 pj_status_t PjUwpSocket::Accept(PjUwpSocket **new_sock)
868 {
869 if (sock_type != SOCKTYPE_LISTENER || sock_state != SOCKSTATE_INITIALIZED)
870 return PJ_EINVALIDOP;
871
872 StreamSocket^ accepted_sock;
873 pj_status_t status = listener_helper->GetAcceptedSocket(accepted_sock);
874 if (status == PJ_ENOTFOUND)
875 return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
876
877 if (status != PJ_SUCCESS)
878 return status;
879
880 *new_sock = CreateAcceptSocket(accepted_sock);
881 return PJ_SUCCESS;
882 }
883
884
885 /////////////////////////////////////////////////////////////////////////////
886 //
887 // PJLIB's sock.h implementation
888 //
889
890 /*
891 * Convert 16-bit value from network byte order to host byte order.
892 */
pj_ntohs(pj_uint16_t netshort)893 PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
894 {
895 return ntohs(netshort);
896 }
897
898 /*
899 * Convert 16-bit value from host byte order to network byte order.
900 */
pj_htons(pj_uint16_t hostshort)901 PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
902 {
903 return htons(hostshort);
904 }
905
906 /*
907 * Convert 32-bit value from network byte order to host byte order.
908 */
pj_ntohl(pj_uint32_t netlong)909 PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
910 {
911 return ntohl(netlong);
912 }
913
914 /*
915 * Convert 32-bit value from host byte order to network byte order.
916 */
pj_htonl(pj_uint32_t hostlong)917 PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
918 {
919 return htonl(hostlong);
920 }
921
922 /*
923 * Convert an Internet host address given in network byte order
924 * to string in standard numbers and dots notation.
925 */
pj_inet_ntoa(pj_in_addr inaddr)926 PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
927 {
928 return inet_ntoa(*(struct in_addr*)&inaddr);
929 }
930
931 /*
932 * This function converts the Internet host address cp from the standard
933 * numbers-and-dots notation into binary data and stores it in the structure
934 * that inp points to.
935 */
pj_inet_aton(const pj_str_t * cp,pj_in_addr * inp)936 PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp)
937 {
938 char tempaddr[PJ_INET_ADDRSTRLEN];
939
940 /* Initialize output with PJ_INADDR_NONE.
941 * Some apps relies on this instead of the return value
942 * (and anyway the return value is quite confusing!)
943 */
944 inp->s_addr = PJ_INADDR_NONE;
945
946 /* Caution:
947 * this function might be called with cp->slen >= 16
948 * (i.e. when called with hostname to check if it's an IP addr).
949 */
950 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
951 if (cp->slen >= PJ_INET_ADDRSTRLEN) {
952 return 0;
953 }
954
955 pj_memcpy(tempaddr, cp->ptr, cp->slen);
956 tempaddr[cp->slen] = '\0';
957
958 #if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
959 return inet_aton(tempaddr, (struct in_addr*)inp);
960 #else
961 inp->s_addr = inet_addr(tempaddr);
962 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
963 #endif
964 }
965
966 /*
967 * Convert text to IPv4/IPv6 address.
968 */
pj_inet_pton(int af,const pj_str_t * src,void * dst)969 PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
970 {
971 char tempaddr[PJ_INET6_ADDRSTRLEN];
972
973 PJ_ASSERT_RETURN(af == PJ_AF_INET || af == PJ_AF_INET6, PJ_EAFNOTSUP);
974 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
975
976 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
977 * compatible with pj_inet_aton()
978 */
979 if (af == PJ_AF_INET) {
980 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
981 }
982
983 /* Caution:
984 * this function might be called with cp->slen >= 46
985 * (i.e. when called with hostname to check if it's an IP addr).
986 */
987 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
988 return PJ_ENAMETOOLONG;
989 }
990
991 pj_memcpy(tempaddr, src->ptr, src->slen);
992 tempaddr[src->slen] = '\0';
993
994 #if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
995 /*
996 * Implementation using inet_pton()
997 */
998 if (inet_pton(af, tempaddr, dst) != 1) {
999 pj_status_t status = pj_get_netos_error();
1000 if (status == PJ_SUCCESS)
1001 status = PJ_EUNKNOWN;
1002
1003 return status;
1004 }
1005
1006 return PJ_SUCCESS;
1007
1008 #elif defined(PJ_WIN32) || defined(PJ_WIN64) || defined(PJ_WIN32_WINCE)
1009 /*
1010 * Implementation on Windows, using WSAStringToAddress().
1011 * Should also work on Unicode systems.
1012 */
1013 {
1014 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr, PJ_INET6_ADDRSTRLEN)
1015 pj_sockaddr sock_addr;
1016 int addr_len = sizeof(sock_addr);
1017 int rc;
1018
1019 sock_addr.addr.sa_family = (pj_uint16_t)af;
1020 rc = WSAStringToAddress(
1021 PJ_STRING_TO_NATIVE(tempaddr, wtempaddr, sizeof(wtempaddr)),
1022 af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
1023 if (rc != 0) {
1024 /* If you get rc 130022 Invalid argument (WSAEINVAL) with IPv6,
1025 * check that you have IPv6 enabled (install it in the network
1026 * adapter).
1027 */
1028 pj_status_t status = pj_get_netos_error();
1029 if (status == PJ_SUCCESS)
1030 status = PJ_EUNKNOWN;
1031
1032 return status;
1033 }
1034
1035 if (sock_addr.addr.sa_family == PJ_AF_INET) {
1036 pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
1037 return PJ_SUCCESS;
1038 }
1039 else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
1040 pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
1041 return PJ_SUCCESS;
1042 }
1043 else {
1044 pj_assert(!"Shouldn't happen");
1045 return PJ_EBUG;
1046 }
1047 }
1048 #elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
1049 /* IPv6 support is disabled, just return error without raising assertion */
1050 return PJ_EIPV6NOTSUP;
1051 #else
1052 pj_assert(!"Not supported");
1053 return PJ_EIPV6NOTSUP;
1054 #endif
1055 }
1056
1057 /*
1058 * Convert IPv4/IPv6 address to text.
1059 */
pj_inet_ntop(int af,const void * src,char * dst,int size)1060 PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
1061 char *dst, int size)
1062
1063 {
1064 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
1065 PJ_ASSERT_RETURN(af == PJ_AF_INET || af == PJ_AF_INET6, PJ_EAFNOTSUP);
1066
1067 *dst = '\0';
1068
1069 #if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
1070 /*
1071 * Implementation using inet_ntop()
1072 */
1073 if (inet_ntop(af, src, dst, size) == NULL) {
1074 pj_status_t status = pj_get_netos_error();
1075 if (status == PJ_SUCCESS)
1076 status = PJ_EUNKNOWN;
1077
1078 return status;
1079 }
1080
1081 return PJ_SUCCESS;
1082
1083 #elif defined(PJ_WIN32) || defined(PJ_WIN64) || defined(PJ_WIN32_WINCE)
1084 /*
1085 * Implementation on Windows, using WSAAddressToString().
1086 * Should also work on Unicode systems.
1087 */
1088 {
1089 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr, PJ_INET6_ADDRSTRLEN)
1090 pj_sockaddr sock_addr;
1091 DWORD addr_len, addr_str_len;
1092 int rc;
1093
1094 pj_bzero(&sock_addr, sizeof(sock_addr));
1095 sock_addr.addr.sa_family = (pj_uint16_t)af;
1096 if (af == PJ_AF_INET) {
1097 if (size < PJ_INET_ADDRSTRLEN)
1098 return PJ_ETOOSMALL;
1099 pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
1100 addr_len = sizeof(pj_sockaddr_in);
1101 addr_str_len = PJ_INET_ADDRSTRLEN;
1102 }
1103 else if (af == PJ_AF_INET6) {
1104 if (size < PJ_INET6_ADDRSTRLEN)
1105 return PJ_ETOOSMALL;
1106 pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
1107 addr_len = sizeof(pj_sockaddr_in6);
1108 addr_str_len = PJ_INET6_ADDRSTRLEN;
1109 }
1110 else {
1111 pj_assert(!"Unsupported address family");
1112 return PJ_EAFNOTSUP;
1113 }
1114
1115 #if PJ_NATIVE_STRING_IS_UNICODE
1116 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
1117 NULL, wtempaddr, &addr_str_len);
1118 if (rc == 0) {
1119 pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
1120 }
1121 #else
1122 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
1123 NULL, dst, &addr_str_len);
1124 #endif
1125
1126 if (rc != 0) {
1127 pj_status_t status = pj_get_netos_error();
1128 if (status == PJ_SUCCESS)
1129 status = PJ_EUNKNOWN;
1130
1131 return status;
1132 }
1133
1134 return PJ_SUCCESS;
1135 }
1136
1137 #elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
1138 /* IPv6 support is disabled, just return error without raising assertion */
1139 return PJ_EIPV6NOTSUP;
1140 #else
1141 pj_assert(!"Not supported");
1142 return PJ_EIPV6NOTSUP;
1143 #endif
1144 }
1145
1146 /*
1147 * Get hostname.
1148 */
pj_gethostname(void)1149 PJ_DEF(const pj_str_t*) pj_gethostname(void)
1150 {
1151 static char buf[PJ_MAX_HOSTNAME];
1152 static pj_str_t hostname;
1153
1154 PJ_CHECK_STACK();
1155
1156 if (hostname.ptr == NULL) {
1157 hostname.ptr = buf;
1158 if (gethostname(buf, sizeof(buf)) != 0) {
1159 hostname.ptr[0] = '\0';
1160 hostname.slen = 0;
1161 }
1162 else {
1163 hostname.slen = strlen(buf);
1164 }
1165 }
1166 return &hostname;
1167 }
1168
1169 /*
1170 * Create new socket/endpoint for communication and returns a descriptor.
1171 */
pj_sock_socket(int af,int type,int proto,pj_sock_t * p_sock)1172 PJ_DEF(pj_status_t) pj_sock_socket(int af,
1173 int type,
1174 int proto,
1175 pj_sock_t *p_sock)
1176 {
1177 PJ_CHECK_STACK();
1178 PJ_ASSERT_RETURN(p_sock!=NULL, PJ_EINVAL);
1179
1180 PjUwpSocket *s = new PjUwpSocket(af, type, proto);
1181
1182 /* Init UDP socket here */
1183 if (type == pj_SOCK_DGRAM()) {
1184 s->InitSocket(SOCKTYPE_DATAGRAM);
1185 }
1186
1187 *p_sock = (pj_sock_t)s;
1188 return PJ_SUCCESS;
1189 }
1190
1191
1192 /*
1193 * Bind socket.
1194 */
pj_sock_bind(pj_sock_t sock,const pj_sockaddr_t * addr,int len)1195 PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
1196 const pj_sockaddr_t *addr,
1197 int len)
1198 {
1199 PJ_CHECK_STACK();
1200 PJ_ASSERT_RETURN(sock, PJ_EINVAL);
1201 PJ_ASSERT_RETURN(addr && len>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
1202 PjUwpSocket *s = (PjUwpSocket*)sock;
1203 return s->Bind(addr);
1204 }
1205
1206
1207 /*
1208 * Bind socket.
1209 */
pj_sock_bind_in(pj_sock_t sock,pj_uint32_t addr32,pj_uint16_t port)1210 PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
1211 pj_uint32_t addr32,
1212 pj_uint16_t port)
1213 {
1214 pj_sockaddr_in addr;
1215
1216 PJ_CHECK_STACK();
1217
1218 pj_bzero(&addr, sizeof(addr));
1219 addr.sin_family = PJ_AF_INET;
1220 addr.sin_addr.s_addr = pj_htonl(addr32);
1221 addr.sin_port = pj_htons(port);
1222
1223 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
1224 }
1225
1226
1227 /*
1228 * Close socket.
1229 */
pj_sock_close(pj_sock_t sock)1230 PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
1231 {
1232 PJ_CHECK_STACK();
1233 PJ_ASSERT_RETURN(sock, PJ_EINVAL);
1234
1235 if (sock == PJ_INVALID_SOCKET)
1236 return PJ_SUCCESS;
1237
1238 PjUwpSocket *s = (PjUwpSocket*)sock;
1239 delete s;
1240
1241 return PJ_SUCCESS;
1242 }
1243
1244 /*
1245 * Get remote's name.
1246 */
pj_sock_getpeername(pj_sock_t sock,pj_sockaddr_t * addr,int * namelen)1247 PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
1248 pj_sockaddr_t *addr,
1249 int *namelen)
1250 {
1251 PJ_CHECK_STACK();
1252 PJ_ASSERT_RETURN(sock && addr && namelen &&
1253 *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
1254
1255 PjUwpSocket *s = (PjUwpSocket*)sock;
1256 pj_sockaddr_cp(addr, s->GetRemoteAddr());
1257 *namelen = pj_sockaddr_get_len(addr);
1258
1259 return PJ_SUCCESS;
1260 }
1261
1262 /*
1263 * Get socket name.
1264 */
pj_sock_getsockname(pj_sock_t sock,pj_sockaddr_t * addr,int * namelen)1265 PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
1266 pj_sockaddr_t *addr,
1267 int *namelen)
1268 {
1269 PJ_CHECK_STACK();
1270 PJ_ASSERT_RETURN(sock && addr && namelen &&
1271 *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
1272
1273 PjUwpSocket *s = (PjUwpSocket*)sock;
1274 pj_sockaddr_cp(addr, s->GetLocalAddr());
1275 *namelen = pj_sockaddr_get_len(addr);
1276
1277 return PJ_SUCCESS;
1278 }
1279
1280
1281 /*
1282 * Send data
1283 */
pj_sock_send(pj_sock_t sock,const void * buf,pj_ssize_t * len,unsigned flags)1284 PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
1285 const void *buf,
1286 pj_ssize_t *len,
1287 unsigned flags)
1288 {
1289 PJ_CHECK_STACK();
1290 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
1291 PJ_UNUSED_ARG(flags);
1292
1293 PjUwpSocket *s = (PjUwpSocket*)sock;
1294 return s->Send(buf, len);
1295 }
1296
1297
1298 /*
1299 * Send data.
1300 */
pj_sock_sendto(pj_sock_t sock,const void * buf,pj_ssize_t * len,unsigned flags,const pj_sockaddr_t * to,int tolen)1301 PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
1302 const void *buf,
1303 pj_ssize_t *len,
1304 unsigned flags,
1305 const pj_sockaddr_t *to,
1306 int tolen)
1307 {
1308 PJ_CHECK_STACK();
1309 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
1310 PJ_UNUSED_ARG(flags);
1311 PJ_UNUSED_ARG(tolen);
1312
1313 PjUwpSocket *s = (PjUwpSocket*)sock;
1314 return s->SendTo(buf, len, to);
1315 }
1316
1317
1318 /*
1319 * Receive data.
1320 */
pj_sock_recv(pj_sock_t sock,void * buf,pj_ssize_t * len,unsigned flags)1321 PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
1322 void *buf,
1323 pj_ssize_t *len,
1324 unsigned flags)
1325 {
1326 PJ_CHECK_STACK();
1327 PJ_ASSERT_RETURN(sock && len && *len > 0, PJ_EINVAL);
1328
1329 PJ_UNUSED_ARG(flags);
1330
1331 PjUwpSocket *s = (PjUwpSocket*)sock;
1332 return s->Recv(buf, len);
1333 }
1334
1335 /*
1336 * Receive data.
1337 */
pj_sock_recvfrom(pj_sock_t sock,void * buf,pj_ssize_t * len,unsigned flags,pj_sockaddr_t * from,int * fromlen)1338 PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
1339 void *buf,
1340 pj_ssize_t *len,
1341 unsigned flags,
1342 pj_sockaddr_t *from,
1343 int *fromlen)
1344 {
1345 PJ_CHECK_STACK();
1346 PJ_ASSERT_RETURN(sock && buf && len && from && fromlen, PJ_EINVAL);
1347 PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
1348 PJ_ASSERT_RETURN(*fromlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);
1349
1350 PJ_UNUSED_ARG(flags);
1351
1352 PjUwpSocket *s = (PjUwpSocket*)sock;
1353 pj_status_t status = s->RecvFrom(buf, len, from);
1354 if (status == PJ_SUCCESS)
1355 *fromlen = pj_sockaddr_get_len(from);
1356 return status;
1357 }
1358
1359 /*
1360 * Get socket option.
1361 */
pj_sock_getsockopt(pj_sock_t sock,pj_uint16_t level,pj_uint16_t optname,void * optval,int * optlen)1362 PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
1363 pj_uint16_t level,
1364 pj_uint16_t optname,
1365 void *optval,
1366 int *optlen)
1367 {
1368 // Not supported for now.
1369 PJ_UNUSED_ARG(sock);
1370 PJ_UNUSED_ARG(level);
1371 PJ_UNUSED_ARG(optname);
1372 PJ_UNUSED_ARG(optval);
1373 PJ_UNUSED_ARG(optlen);
1374 return PJ_ENOTSUP;
1375 }
1376
1377
1378 /*
1379 * Set socket option.
1380 */
pj_sock_setsockopt(pj_sock_t sock,pj_uint16_t level,pj_uint16_t optname,const void * optval,int optlen)1381 PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
1382 pj_uint16_t level,
1383 pj_uint16_t optname,
1384 const void *optval,
1385 int optlen)
1386 {
1387 // Not supported for now.
1388 PJ_UNUSED_ARG(sock);
1389 PJ_UNUSED_ARG(level);
1390 PJ_UNUSED_ARG(optname);
1391 PJ_UNUSED_ARG(optval);
1392 PJ_UNUSED_ARG(optlen);
1393 return PJ_ENOTSUP;
1394 }
1395
1396
1397 /*
1398 * Set socket option.
1399 */
pj_sock_setsockopt_params(pj_sock_t sockfd,const pj_sockopt_params * params)1400 PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd,
1401 const pj_sockopt_params *params)
1402 {
1403 unsigned int i = 0;
1404 pj_status_t retval = PJ_SUCCESS;
1405 PJ_CHECK_STACK();
1406 PJ_ASSERT_RETURN(params, PJ_EINVAL);
1407
1408 for (;i<params->cnt && i<PJ_MAX_SOCKOPT_PARAMS;++i) {
1409 pj_status_t status = pj_sock_setsockopt(sockfd,
1410 (pj_uint16_t)params->options[i].level,
1411 (pj_uint16_t)params->options[i].optname,
1412 params->options[i].optval,
1413 params->options[i].optlen);
1414 if (status != PJ_SUCCESS) {
1415 retval = status;
1416 PJ_PERROR(4,(THIS_FILE, status,
1417 "Warning: error applying sock opt %d",
1418 params->options[i].optname));
1419 }
1420 }
1421
1422 return retval;
1423 }
1424
1425
1426 /*
1427 * Connect socket.
1428 */
pj_sock_connect(pj_sock_t sock,const pj_sockaddr_t * addr,int namelen)1429 PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
1430 const pj_sockaddr_t *addr,
1431 int namelen)
1432 {
1433 PJ_CHECK_STACK();
1434 PJ_ASSERT_RETURN(sock && addr, PJ_EINVAL);
1435 PJ_UNUSED_ARG(namelen);
1436
1437 PjUwpSocket *s = (PjUwpSocket*)sock;
1438 return s->Connect(addr);
1439 }
1440
1441
1442 /*
1443 * Shutdown socket.
1444 */
1445 #if PJ_HAS_TCP
pj_sock_shutdown(pj_sock_t sock,int how)1446 PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
1447 int how)
1448 {
1449 PJ_CHECK_STACK();
1450 PJ_ASSERT_RETURN(sock, PJ_EINVAL);
1451 PJ_UNUSED_ARG(how);
1452
1453 return pj_sock_close(sock);
1454 }
1455
1456 /*
1457 * Start listening to incoming connections.
1458 */
pj_sock_listen(pj_sock_t sock,int backlog)1459 PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
1460 int backlog)
1461 {
1462 PJ_CHECK_STACK();
1463 PJ_UNUSED_ARG(backlog);
1464 PJ_ASSERT_RETURN(sock, PJ_EINVAL);
1465
1466 PjUwpSocket *s = (PjUwpSocket*)sock;
1467 return s->Listen();
1468 }
1469
1470 /*
1471 * Accept incoming connections
1472 */
pj_sock_accept(pj_sock_t serverfd,pj_sock_t * newsock,pj_sockaddr_t * addr,int * addrlen)1473 PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
1474 pj_sock_t *newsock,
1475 pj_sockaddr_t *addr,
1476 int *addrlen)
1477 {
1478 pj_status_t status;
1479
1480 PJ_CHECK_STACK();
1481 PJ_ASSERT_RETURN(serverfd && newsock, PJ_EINVAL);
1482
1483 PjUwpSocket *s = (PjUwpSocket*)serverfd;
1484 PjUwpSocket *new_uwp_sock;
1485
1486 status = s->Accept(&new_uwp_sock);
1487 if (status != PJ_SUCCESS)
1488 return status;
1489 if (newsock == NULL)
1490 return PJ_ENOTFOUND;
1491
1492 *newsock = (pj_sock_t)new_uwp_sock;
1493
1494 if (addr)
1495 pj_sockaddr_cp(addr, new_uwp_sock->GetRemoteAddr());
1496
1497 if (addrlen)
1498 *addrlen = pj_sockaddr_get_len(addr);
1499
1500 return PJ_SUCCESS;
1501 }
1502 #endif /* PJ_HAS_TCP */
1503