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