12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502 |
- /*
- * Copyright (C) 2016 Teluu Inc. (http://www.teluu.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <pj/assert.h>
- #include <pj/errno.h>
- #include <pj/math.h>
- #include <pj/os.h>
- #include <pj/compat/socket.h>
- #include <ppltasks.h>
- #include <string>
- #define THIS_FILE "sock_uwp.cpp"
- #include "sock_uwp.h"
- /*
- * Address families conversion.
- * The values here are indexed based on pj_addr_family.
- */
- const pj_uint16_t PJ_AF_UNSPEC = AF_UNSPEC;
- const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
- const pj_uint16_t PJ_AF_INET = AF_INET;
- const pj_uint16_t PJ_AF_INET6 = AF_INET6;
- #ifdef AF_PACKET
- const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
- #else
- const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
- #endif
- #ifdef AF_IRDA
- const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
- #else
- const pj_uint16_t PJ_AF_IRDA = 0xFFFF;
- #endif
- /*
- * Socket types conversion.
- * The values here are indexed based on pj_sock_type
- */
- const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
- const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
- const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
- const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
- const int PJ_SOCK_CLOEXEC = 0;
- /*
- * Socket level values.
- */
- const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
- #ifdef SOL_IP
- const pj_uint16_t PJ_SOL_IP = SOL_IP;
- #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
- const pj_uint16_t PJ_SOL_IP = IPPROTO_IP;
- #else
- const pj_uint16_t PJ_SOL_IP = 0;
- #endif /* SOL_IP */
- #if defined(SOL_TCP)
- const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
- #elif defined(IPPROTO_TCP)
- const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
- #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
- const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
- #else
- const pj_uint16_t PJ_SOL_TCP = 6;
- #endif /* SOL_TCP */
- #ifdef SOL_UDP
- const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
- #elif defined(IPPROTO_UDP)
- const pj_uint16_t PJ_SOL_UDP = IPPROTO_UDP;
- #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
- const pj_uint16_t PJ_SOL_UDP = IPPROTO_UDP;
- #else
- const pj_uint16_t PJ_SOL_UDP = 17;
- #endif /* SOL_UDP */
- #ifdef SOL_IPV6
- const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
- #elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
- # if defined(IPPROTO_IPV6) || (_WIN32_WINNT >= 0x0501)
- const pj_uint16_t PJ_SOL_IPV6 = IPPROTO_IPV6;
- # else
- const pj_uint16_t PJ_SOL_IPV6 = 41;
- # endif
- #else
- const pj_uint16_t PJ_SOL_IPV6 = 41;
- #endif /* SOL_IPV6 */
- /* IP_TOS */
- #ifdef IP_TOS
- const pj_uint16_t PJ_IP_TOS = IP_TOS;
- #else
- const pj_uint16_t PJ_IP_TOS = 1;
- #endif
- /* TOS settings (declared in netinet/ip.h) */
- #ifdef IPTOS_LOWDELAY
- const pj_uint16_t PJ_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
- #else
- const pj_uint16_t PJ_IPTOS_LOWDELAY = 0x10;
- #endif
- #ifdef IPTOS_THROUGHPUT
- const pj_uint16_t PJ_IPTOS_THROUGHPUT = IPTOS_THROUGHPUT;
- #else
- const pj_uint16_t PJ_IPTOS_THROUGHPUT = 0x08;
- #endif
- #ifdef IPTOS_RELIABILITY
- const pj_uint16_t PJ_IPTOS_RELIABILITY = IPTOS_RELIABILITY;
- #else
- const pj_uint16_t PJ_IPTOS_RELIABILITY = 0x04;
- #endif
- #ifdef IPTOS_MINCOST
- const pj_uint16_t PJ_IPTOS_MINCOST = IPTOS_MINCOST;
- #else
- const pj_uint16_t PJ_IPTOS_MINCOST = 0x02;
- #endif
- /* optname values. */
- const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
- const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
- const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
- const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
- const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
- #ifdef SO_NOSIGPIPE
- const pj_uint16_t PJ_SO_NOSIGPIPE = SO_NOSIGPIPE;
- #else
- const pj_uint16_t PJ_SO_NOSIGPIPE = 0xFFFF;
- #endif
- #if defined(SO_PRIORITY)
- const pj_uint16_t PJ_SO_PRIORITY = SO_PRIORITY;
- #else
- /* This is from Linux, YMMV */
- const pj_uint16_t PJ_SO_PRIORITY = 12;
- #endif
- /* Multicasting is not supported e.g. in PocketPC 2003 SDK */
- #ifdef IP_MULTICAST_IF
- const pj_uint16_t PJ_IP_MULTICAST_IF = IP_MULTICAST_IF;
- const pj_uint16_t PJ_IP_MULTICAST_TTL = IP_MULTICAST_TTL;
- const pj_uint16_t PJ_IP_MULTICAST_LOOP = IP_MULTICAST_LOOP;
- const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = IP_ADD_MEMBERSHIP;
- const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
- #else
- const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
- const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
- const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
- const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
- const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
- #endif
- /* recv() and send() flags */
- const int PJ_MSG_OOB = MSG_OOB;
- const int PJ_MSG_PEEK = MSG_PEEK;
- const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
- using namespace Platform;
- using namespace Windows::Foundation;
- using namespace Windows::Networking;
- using namespace Windows::Networking::Sockets;
- using namespace Windows::Storage::Streams;
- ref class PjUwpSocketDatagramRecvHelper sealed
- {
- internal:
- PjUwpSocketDatagramRecvHelper(PjUwpSocket* uwp_sock_) :
- uwp_sock(uwp_sock_), avail_data_len(0), recv_args(nullptr)
- {
- recv_wait = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
- event_token = uwp_sock->datagram_sock->MessageReceived +=
- ref new TypedEventHandler<DatagramSocket^,
- DatagramSocketMessageReceivedEventArgs^>
- (this, &PjUwpSocketDatagramRecvHelper::OnMessageReceived);
- }
- void OnMessageReceived(DatagramSocket ^sender,
- DatagramSocketMessageReceivedEventArgs ^args)
- {
- try {
- if (uwp_sock->sock_state >= SOCKSTATE_DISCONNECTED)
- return;
- recv_args = args;
- avail_data_len = args->GetDataReader()->UnconsumedBufferLength;
- if (uwp_sock->cb.on_read) {
- (*uwp_sock->cb.on_read)(uwp_sock, avail_data_len);
- }
- WaitForSingleObjectEx(recv_wait, INFINITE, false);
- } catch (...) {}
- }
- pj_status_t ReadDataIfAvailable(void *buf, pj_ssize_t *len,
- pj_sockaddr_t *from)
- {
- if (avail_data_len <= 0)
- return PJ_ENOTFOUND;
- if (*len < avail_data_len)
- return PJ_ETOOSMALL;
- // Read data
- auto reader = recv_args->GetDataReader();
- auto buffer = reader->ReadBuffer(avail_data_len);
- unsigned char *p;
- GetRawBufferFromIBuffer(buffer, &p);
- pj_memcpy((void*) buf, p, avail_data_len);
- *len = avail_data_len;
- // Get source address
- wstr_addr_to_sockaddr(recv_args->RemoteAddress->CanonicalName->Data(),
- recv_args->RemotePort->Data(), from);
- // finally
- avail_data_len = 0;
- SetEvent(recv_wait);
- return PJ_SUCCESS;
- }
- private:
- ~PjUwpSocketDatagramRecvHelper()
- {
- if (uwp_sock->datagram_sock)
- uwp_sock->datagram_sock->MessageReceived -= event_token;
- SetEvent(recv_wait);
- CloseHandle(recv_wait);
- }
- PjUwpSocket* uwp_sock;
- DatagramSocketMessageReceivedEventArgs^ recv_args;
- EventRegistrationToken event_token;
- HANDLE recv_wait;
- int avail_data_len;
- };
- ref class PjUwpSocketListenerHelper sealed
- {
- internal:
- PjUwpSocketListenerHelper(PjUwpSocket* uwp_sock_) :
- uwp_sock(uwp_sock_), conn_args(nullptr)
- {
- conn_wait = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
- event_token = uwp_sock->listener_sock->ConnectionReceived +=
- ref new TypedEventHandler<StreamSocketListener^, StreamSocketListenerConnectionReceivedEventArgs^>
- (this, &PjUwpSocketListenerHelper::OnConnectionReceived);
- }
- void OnConnectionReceived(StreamSocketListener ^sender,
- StreamSocketListenerConnectionReceivedEventArgs ^args)
- {
- try {
- conn_args = args;
- if (uwp_sock->cb.on_accept) {
- (*uwp_sock->cb.on_accept)(uwp_sock);
- }
- WaitForSingleObjectEx(conn_wait, INFINITE, false);
- } catch (Exception^ e) {}
- }
- pj_status_t GetAcceptedSocket(StreamSocket^& stream_sock)
- {
- if (conn_args == nullptr)
- return PJ_ENOTFOUND;
- stream_sock = conn_args->Socket;
- // finally
- conn_args = nullptr;
- SetEvent(conn_wait);
- return PJ_SUCCESS;
- }
- private:
- ~PjUwpSocketListenerHelper()
- {
- if (uwp_sock->listener_sock)
- uwp_sock->listener_sock->ConnectionReceived -= event_token;
- SetEvent(conn_wait);
- CloseHandle(conn_wait);
- }
- PjUwpSocket* uwp_sock;
- StreamSocketListenerConnectionReceivedEventArgs^ conn_args;
- EventRegistrationToken event_token;
- HANDLE conn_wait;
- };
- PjUwpSocket::PjUwpSocket(int af_, int type_, int proto_) :
- af(af_), type(type_), proto(proto_),
- sock_type(SOCKTYPE_UNKNOWN),
- sock_state(SOCKSTATE_NULL),
- is_blocking(PJ_TRUE),
- has_pending_bind(PJ_FALSE),
- has_pending_send(PJ_FALSE),
- has_pending_recv(PJ_FALSE)
- {
- pj_sockaddr_init(pj_AF_INET(), &local_addr, NULL, 0);
- pj_sockaddr_init(pj_AF_INET(), &remote_addr, NULL, 0);
- }
- PjUwpSocket::~PjUwpSocket()
- {
- DeinitSocket();
- }
- PjUwpSocket* PjUwpSocket::CreateAcceptSocket(Windows::Networking::Sockets::StreamSocket^ stream_sock_)
- {
- PjUwpSocket *new_sock = new PjUwpSocket(pj_AF_INET(), pj_SOCK_STREAM(), 0);
- new_sock->stream_sock = stream_sock_;
- new_sock->sock_type = SOCKTYPE_STREAM;
- new_sock->sock_state = SOCKSTATE_CONNECTED;
- new_sock->socket_reader = ref new DataReader(new_sock->stream_sock->InputStream);
- new_sock->socket_writer = ref new DataWriter(new_sock->stream_sock->OutputStream);
- new_sock->socket_reader->InputStreamOptions = InputStreamOptions::Partial;
- new_sock->send_buffer = ref new Buffer(SEND_BUFFER_SIZE);
- new_sock->is_blocking = is_blocking;
- // Update local & remote address
- wstr_addr_to_sockaddr(stream_sock_->Information->RemoteAddress->CanonicalName->Data(),
- stream_sock_->Information->RemotePort->Data(),
- &new_sock->remote_addr);
- wstr_addr_to_sockaddr(stream_sock_->Information->LocalAddress->CanonicalName->Data(),
- stream_sock_->Information->LocalPort->Data(),
- &new_sock->local_addr);
- return new_sock;
- }
- pj_status_t PjUwpSocket::InitSocket(enum PjUwpSocketType sock_type_)
- {
- PJ_ASSERT_RETURN(sock_type_ > SOCKTYPE_UNKNOWN, PJ_EINVAL);
- sock_type = sock_type_;
- if (sock_type == SOCKTYPE_LISTENER) {
- listener_sock = ref new StreamSocketListener();
- } else if (sock_type == SOCKTYPE_STREAM) {
- stream_sock = ref new StreamSocket();
- } else if (sock_type == SOCKTYPE_DATAGRAM) {
- datagram_sock = ref new DatagramSocket();
- } else {
- pj_assert(!"Invalid socket type");
- return PJ_EINVAL;
- }
- if (sock_type == SOCKTYPE_DATAGRAM || sock_type == SOCKTYPE_STREAM) {
- send_buffer = ref new Buffer(SEND_BUFFER_SIZE);
- }
- sock_state = SOCKSTATE_INITIALIZED;
- return PJ_SUCCESS;
- }
- void PjUwpSocket::DeinitSocket()
- {
- if (stream_sock) {
- concurrency::create_task(stream_sock->CancelIOAsync()).wait();
- }
- if (datagram_sock && has_pending_send) {
- concurrency::create_task(datagram_sock->CancelIOAsync()).wait();
- }
- if (listener_sock) {
- concurrency::create_task(listener_sock->CancelIOAsync()).wait();
- }
- while (has_pending_recv) pj_thread_sleep(10);
- stream_sock = nullptr;
- datagram_sock = nullptr;
- dgram_recv_helper = nullptr;
- listener_sock = nullptr;
- listener_helper = nullptr;
- socket_writer = nullptr;
- socket_reader = nullptr;
- sock_state = SOCKSTATE_NULL;
- }
- pj_status_t PjUwpSocket::Bind(const pj_sockaddr_t *addr)
- {
- /* Not initialized yet, socket type is perhaps TCP, just not decided yet
- * whether it is a stream or a listener.
- */
- if (sock_state < SOCKSTATE_INITIALIZED) {
- pj_sockaddr_cp(&local_addr, addr);
- has_pending_bind = PJ_TRUE;
- return PJ_SUCCESS;
- }
-
- PJ_ASSERT_RETURN(sock_state == SOCKSTATE_INITIALIZED, PJ_EINVALIDOP);
- if (sock_type != SOCKTYPE_DATAGRAM && sock_type != SOCKTYPE_LISTENER)
- return PJ_EINVALIDOP;
- if (has_pending_bind) {
- has_pending_bind = PJ_FALSE;
- if (!addr)
- addr = &local_addr;
- }
- /* If no bound address is set, just return */
- if (!pj_sockaddr_has_addr(addr) && !pj_sockaddr_get_port(addr))
- return PJ_SUCCESS;
- if (addr != &local_addr)
- pj_sockaddr_cp(&local_addr, addr);
- HRESULT err = 0;
- concurrency::create_task([this, addr, &err]() {
- HostName ^host;
- int port;
- sockaddr_to_hostname_port(addr, host, &port);
- if (pj_sockaddr_has_addr(addr)) {
- if (sock_type == SOCKTYPE_DATAGRAM)
- return datagram_sock->BindEndpointAsync(host, port.ToString());
- else
- return listener_sock->BindEndpointAsync(host, port.ToString());
- } else /* if (pj_sockaddr_get_port(addr) != 0) */ {
- if (sock_type == SOCKTYPE_DATAGRAM)
- return datagram_sock->BindServiceNameAsync(port.ToString());
- else
- return listener_sock->BindServiceNameAsync(port.ToString());
- }
- }).then([this, &err](concurrency::task<void> t)
- {
- try {
- if (!err)
- t.get();
- } catch (Exception^ e) {
- err = e->HResult;
- }
- }).get();
- return (err? PJ_RETURN_OS_ERROR(err) : PJ_SUCCESS);
- }
- pj_status_t PjUwpSocket::SendImp(const void *buf, pj_ssize_t *len)
- {
- if (has_pending_send)
- return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
- if (*len > (pj_ssize_t)send_buffer->Capacity)
- return PJ_ETOOBIG;
- CopyToIBuffer((unsigned char*)buf, *len, send_buffer);
- send_buffer->Length = *len;
- socket_writer->WriteBuffer(send_buffer);
- /* Blocking version */
- if (is_blocking) {
- pj_status_t status = PJ_SUCCESS;
- concurrency::cancellation_token_source cts;
- auto cts_token = cts.get_token();
- auto t = concurrency::create_task(socket_writer->StoreAsync(),
- cts_token);
- *len = cancel_after_timeout(t, cts, (unsigned int)WRITE_TIMEOUT).
- then([cts_token, &status](concurrency::task<unsigned int> t_)
- {
- int sent = 0;
- try {
- if (cts_token.is_canceled())
- status = PJ_ETIMEDOUT;
- else
- sent = t_.get();
- } catch (Exception^ e) {
- status = PJ_RETURN_OS_ERROR(e->HResult);
- }
- return sent;
- }).get();
- return status;
- }
- /* Non-blocking version */
- has_pending_send = PJ_TRUE;
- concurrency::create_task(socket_writer->StoreAsync()).
- then([this](concurrency::task<unsigned int> t_)
- {
- try {
- unsigned int l = t_.get();
- has_pending_send = PJ_FALSE;
- // invoke callback
- if (cb.on_write) {
- (*cb.on_write)(this, l);
- }
- } catch (...) {
- has_pending_send = PJ_FALSE;
- sock_state = SOCKSTATE_ERROR;
- DeinitSocket();
- // invoke callback
- if (cb.on_write) {
- (*cb.on_write)(this, -PJ_EUNKNOWN);
- }
- }
- });
- return PJ_SUCCESS;
- }
- pj_status_t PjUwpSocket::Send(const void *buf, pj_ssize_t *len)
- {
- if ((sock_type!=SOCKTYPE_STREAM && sock_type!=SOCKTYPE_DATAGRAM) ||
- (sock_state!=SOCKSTATE_CONNECTED))
- {
- return PJ_EINVALIDOP;
- }
- /* Sending for SOCKTYPE_DATAGRAM is implemented in pj_sock_sendto() */
- if (sock_type == SOCKTYPE_DATAGRAM) {
- return SendTo(buf, len, &remote_addr);
- }
- return SendImp(buf, len);
- }
- pj_status_t PjUwpSocket::SendTo(const void *buf, pj_ssize_t *len,
- const pj_sockaddr_t *to)
- {
- if (sock_type != SOCKTYPE_DATAGRAM || sock_state < SOCKSTATE_INITIALIZED
- || sock_state >= SOCKSTATE_DISCONNECTED)
- {
- return PJ_EINVALIDOP;
- }
- if (has_pending_send)
- return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
- if (*len > (pj_ssize_t)send_buffer->Capacity)
- return PJ_ETOOBIG;
- HostName ^hostname;
- int port;
- sockaddr_to_hostname_port(to, hostname, &port);
- concurrency::cancellation_token_source cts;
- auto cts_token = cts.get_token();
- auto t = concurrency::create_task(datagram_sock->GetOutputStreamAsync(
- hostname, port.ToString()), cts_token);
- pj_status_t status = PJ_SUCCESS;
- cancel_after_timeout(t, cts, (unsigned int)WRITE_TIMEOUT).
- then([this, cts_token, &status](concurrency::task<IOutputStream^> t_)
- {
- try {
- if (cts_token.is_canceled()) {
- status = PJ_ETIMEDOUT;
- } else {
- IOutputStream^ outstream = t_.get();
- socket_writer = ref new DataWriter(outstream);
- }
- } catch (Exception^ e) {
- status = PJ_RETURN_OS_ERROR(e->HResult);
- }
- }).get();
- if (status != PJ_SUCCESS)
- return status;
- status = SendImp(buf, len);
- if ((status == PJ_SUCCESS || status == PJ_EPENDING) &&
- sock_state < SOCKSTATE_CONNECTED)
- {
- sock_state = SOCKSTATE_CONNECTED;
- }
- return status;
- }
- int PjUwpSocket::ConsumeReadBuffer(void *buf, int max_len)
- {
- if (socket_reader->UnconsumedBufferLength == 0)
- return 0;
- int read_len = PJ_MIN((int)socket_reader->UnconsumedBufferLength,max_len);
- IBuffer^ buffer = socket_reader->ReadBuffer(read_len);
- read_len = buffer->Length;
- CopyFromIBuffer((unsigned char*)buf, read_len, buffer);
- return read_len;
- }
- pj_status_t PjUwpSocket::Recv(void *buf, pj_ssize_t *len)
- {
- /* Only for TCP, at least for now! */
- if (sock_type == SOCKTYPE_DATAGRAM)
- return PJ_ENOTSUP;
- if (sock_type != SOCKTYPE_STREAM || sock_state != SOCKSTATE_CONNECTED)
- return PJ_EINVALIDOP;
- if (has_pending_recv)
- return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
- /* First check if there is already some data in the read buffer */
- if (buf) {
- int avail_len = ConsumeReadBuffer(buf, *len);
- if (avail_len > 0) {
- *len = avail_len;
- return PJ_SUCCESS;
- }
- }
- /* Blocking version */
- if (is_blocking) {
- pj_status_t status = PJ_SUCCESS;
- concurrency::cancellation_token_source cts;
- auto cts_token = cts.get_token();
- auto t = concurrency::create_task(socket_reader->LoadAsync(*len),
- cts_token);
- *len = cancel_after_timeout(t, cts, READ_TIMEOUT)
- .then([this, len, buf, cts_token, &status]
- (concurrency::task<unsigned int> t_)
- {
- try {
- if (cts_token.is_canceled()) {
- status = PJ_ETIMEDOUT;
- return 0;
- }
- t_.get();
- } catch (Exception^) {
- status = PJ_ETIMEDOUT;
- return 0;
- }
- *len = ConsumeReadBuffer(buf, *len);
- return (int)*len;
- }).get();
- return status;
- }
- /* Non-blocking version */
- concurrency::cancellation_token_source cts;
- auto cts_token = cts.get_token();
- has_pending_recv = PJ_TRUE;
- concurrency::create_task(socket_reader->LoadAsync(*len), cts_token)
- .then([this, cts_token](concurrency::task<unsigned int> t_)
- {
- try {
- if (cts_token.is_canceled()) {
- has_pending_recv = PJ_FALSE;
- // invoke callback
- if (cb.on_read) {
- (*cb.on_read)(this, -PJ_EUNKNOWN);
- }
- return;
- }
- t_.get();
- has_pending_recv = PJ_FALSE;
- // invoke callback
- int read_len = socket_reader->UnconsumedBufferLength;
- if (read_len > 0 && cb.on_read) {
- (*cb.on_read)(this, read_len);
- }
- } catch (...) {
- has_pending_recv = PJ_FALSE;
- // invoke callback
- if (cb.on_read) {
- (*cb.on_read)(this, -PJ_EUNKNOWN);
- }
- }
- });
- return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
- }
- pj_status_t PjUwpSocket::RecvFrom(void *buf, pj_ssize_t *len,
- pj_sockaddr_t *from)
- {
- if (sock_type != SOCKTYPE_DATAGRAM || sock_state < SOCKSTATE_INITIALIZED
- || sock_state >= SOCKSTATE_DISCONNECTED)
- {
- return PJ_EINVALIDOP;
- }
- /* Start receive, if not yet */
- if (dgram_recv_helper == nullptr) {
- dgram_recv_helper = ref new PjUwpSocketDatagramRecvHelper(this);
- }
- /* Try to read any available data first */
- if (buf || is_blocking) {
- pj_status_t status;
- status = dgram_recv_helper->ReadDataIfAvailable(buf, len, from);
- if (status != PJ_ENOTFOUND)
- return status;
- }
- /* Blocking version */
- if (is_blocking) {
- int max_loop = 0;
- pj_status_t status = PJ_ENOTFOUND;
- while (status == PJ_ENOTFOUND && sock_state <= SOCKSTATE_CONNECTED)
- {
- status = dgram_recv_helper->ReadDataIfAvailable(buf, len, from);
- if (status != PJ_SUCCESS)
- pj_thread_sleep(100);
- if (++max_loop > 10)
- return PJ_ETIMEDOUT;
- }
- return status;
- }
- /* For non-blocking version, just return PJ_EPENDING */
- return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
- }
- pj_status_t PjUwpSocket::Connect(const pj_sockaddr_t *addr)
- {
- pj_status_t status;
- PJ_ASSERT_RETURN((sock_type == SOCKTYPE_UNKNOWN && sock_state == SOCKSTATE_NULL) ||
- (sock_type == SOCKTYPE_DATAGRAM && sock_state == SOCKSTATE_INITIALIZED),
- PJ_EINVALIDOP);
- if (sock_type == SOCKTYPE_UNKNOWN) {
- InitSocket(SOCKTYPE_STREAM);
- // No need to check pending bind, no bind for TCP client socket
- }
- pj_sockaddr_cp(&remote_addr, addr);
- auto t = concurrency::create_task([this, addr]()
- {
- HostName ^hostname;
- int port;
- sockaddr_to_hostname_port(&remote_addr, hostname, &port);
- if (sock_type == SOCKTYPE_STREAM)
- return stream_sock->ConnectAsync(hostname, port.ToString(),
- SocketProtectionLevel::PlainSocket);
- else
- return datagram_sock->ConnectAsync(hostname, port.ToString());
- }).then([=](concurrency::task<void> t_)
- {
- try {
- t_.get();
- sock_state = SOCKSTATE_CONNECTED;
- // Update local & remote address
- HostName^ local_address;
- String^ local_port;
- if (sock_type == SOCKTYPE_STREAM) {
- local_address = stream_sock->Information->LocalAddress;
- local_port = stream_sock->Information->LocalPort;
- socket_reader = ref new DataReader(stream_sock->InputStream);
- socket_writer = ref new DataWriter(stream_sock->OutputStream);
- socket_reader->InputStreamOptions = InputStreamOptions::Partial;
- } else {
- local_address = datagram_sock->Information->LocalAddress;
- local_port = datagram_sock->Information->LocalPort;
- }
- if (local_address && local_port) {
- wstr_addr_to_sockaddr(local_address->CanonicalName->Data(),
- local_port->Data(),
- &local_addr);
- }
- if (!is_blocking && cb.on_connect) {
- (*cb.on_connect)(this, PJ_SUCCESS);
- }
- return (pj_status_t)PJ_SUCCESS;
- } catch (Exception^ ex) {
- SocketErrorStatus status = SocketError::GetStatus(ex->HResult);
- switch (status)
- {
- case SocketErrorStatus::UnreachableHost:
- break;
- case SocketErrorStatus::ConnectionTimedOut:
- break;
- case SocketErrorStatus::ConnectionRefused:
- break;
- default:
- break;
- }
- if (!is_blocking && cb.on_connect) {
- (*cb.on_connect)(this, PJ_EUNKNOWN);
- }
- return (pj_status_t)PJ_EUNKNOWN;
- }
- });
- if (!is_blocking)
- return PJ_RETURN_OS_ERROR(PJ_BLOCKING_CONNECT_ERROR_VAL);
- try {
- status = t.get();
- } catch (Exception^) {
- return PJ_EUNKNOWN;
- }
- return status;
- }
- pj_status_t PjUwpSocket::Listen()
- {
- PJ_ASSERT_RETURN((sock_type == SOCKTYPE_UNKNOWN) ||
- (sock_type == SOCKTYPE_LISTENER &&
- sock_state == SOCKSTATE_INITIALIZED),
- PJ_EINVALIDOP);
- if (sock_type == SOCKTYPE_UNKNOWN)
- InitSocket(SOCKTYPE_LISTENER);
- if (has_pending_bind)
- Bind();
- /* Start listen */
- if (listener_helper == nullptr) {
- listener_helper = ref new PjUwpSocketListenerHelper(this);
- }
- return PJ_SUCCESS;
- }
- pj_status_t PjUwpSocket::Accept(PjUwpSocket **new_sock)
- {
- if (sock_type != SOCKTYPE_LISTENER || sock_state != SOCKSTATE_INITIALIZED)
- return PJ_EINVALIDOP;
- StreamSocket^ accepted_sock;
- pj_status_t status = listener_helper->GetAcceptedSocket(accepted_sock);
- if (status == PJ_ENOTFOUND)
- return PJ_RETURN_OS_ERROR(PJ_BLOCKING_ERROR_VAL);
- if (status != PJ_SUCCESS)
- return status;
- *new_sock = CreateAcceptSocket(accepted_sock);
- return PJ_SUCCESS;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // PJLIB's sock.h implementation
- //
- /*
- * Convert 16-bit value from network byte order to host byte order.
- */
- PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
- {
- return ntohs(netshort);
- }
- /*
- * Convert 16-bit value from host byte order to network byte order.
- */
- PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
- {
- return htons(hostshort);
- }
- /*
- * Convert 32-bit value from network byte order to host byte order.
- */
- PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
- {
- return ntohl(netlong);
- }
- /*
- * Convert 32-bit value from host byte order to network byte order.
- */
- PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
- {
- return htonl(hostlong);
- }
- /*
- * Convert an Internet host address given in network byte order
- * to string in standard numbers and dots notation.
- */
- PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
- {
- return inet_ntoa(*(struct in_addr*)&inaddr);
- }
- /*
- * This function converts the Internet host address cp from the standard
- * numbers-and-dots notation into binary data and stores it in the structure
- * that inp points to.
- */
- PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp)
- {
- char tempaddr[PJ_INET_ADDRSTRLEN];
- /* Initialize output with PJ_INADDR_NONE.
- * Some apps relies on this instead of the return value
- * (and anyway the return value is quite confusing!)
- */
- inp->s_addr = PJ_INADDR_NONE;
- /* Caution:
- * this function might be called with cp->slen >= 16
- * (i.e. when called with hostname to check if it's an IP addr).
- */
- PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
- if (cp->slen >= PJ_INET_ADDRSTRLEN) {
- return 0;
- }
- pj_memcpy(tempaddr, cp->ptr, cp->slen);
- tempaddr[cp->slen] = '\0';
- #if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
- return inet_aton(tempaddr, (struct in_addr*)inp);
- #else
- inp->s_addr = inet_addr(tempaddr);
- return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
- #endif
- }
- /*
- * Convert text to IPv4/IPv6 address.
- */
- PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
- {
- char tempaddr[PJ_INET6_ADDRSTRLEN];
- PJ_ASSERT_RETURN(af == PJ_AF_INET || af == PJ_AF_INET6, PJ_EAFNOTSUP);
- PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
- /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
- * compatible with pj_inet_aton()
- */
- if (af == PJ_AF_INET) {
- ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
- }
- /* Caution:
- * this function might be called with cp->slen >= 46
- * (i.e. when called with hostname to check if it's an IP addr).
- */
- if (src->slen >= PJ_INET6_ADDRSTRLEN) {
- return PJ_ENAMETOOLONG;
- }
- pj_memcpy(tempaddr, src->ptr, src->slen);
- tempaddr[src->slen] = '\0';
- #if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
- /*
- * Implementation using inet_pton()
- */
- if (inet_pton(af, tempaddr, dst) != 1) {
- pj_status_t status = pj_get_netos_error();
- if (status == PJ_SUCCESS)
- status = PJ_EUNKNOWN;
- return status;
- }
- return PJ_SUCCESS;
- #elif defined(PJ_WIN32) || defined(PJ_WIN64) || defined(PJ_WIN32_WINCE)
- /*
- * Implementation on Windows, using WSAStringToAddress().
- * Should also work on Unicode systems.
- */
- {
- PJ_DECL_UNICODE_TEMP_BUF(wtempaddr, PJ_INET6_ADDRSTRLEN)
- pj_sockaddr sock_addr;
- int addr_len = sizeof(sock_addr);
- int rc;
- sock_addr.addr.sa_family = (pj_uint16_t)af;
- rc = WSAStringToAddress(
- PJ_STRING_TO_NATIVE(tempaddr, wtempaddr, sizeof(wtempaddr)),
- af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
- if (rc != 0) {
- /* If you get rc 130022 Invalid argument (WSAEINVAL) with IPv6,
- * check that you have IPv6 enabled (install it in the network
- * adapter).
- */
- pj_status_t status = pj_get_netos_error();
- if (status == PJ_SUCCESS)
- status = PJ_EUNKNOWN;
- return status;
- }
- if (sock_addr.addr.sa_family == PJ_AF_INET) {
- pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
- return PJ_SUCCESS;
- }
- else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
- pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
- return PJ_SUCCESS;
- }
- else {
- pj_assert(!"Shouldn't happen");
- return PJ_EBUG;
- }
- }
- #elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
- /* IPv6 support is disabled, just return error without raising assertion */
- return PJ_EIPV6NOTSUP;
- #else
- pj_assert(!"Not supported");
- return PJ_EIPV6NOTSUP;
- #endif
- }
- /*
- * Convert IPv4/IPv6 address to text.
- */
- PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
- char *dst, int size)
- {
- PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
- PJ_ASSERT_RETURN(af == PJ_AF_INET || af == PJ_AF_INET6, PJ_EAFNOTSUP);
- *dst = '\0';
- #if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
- /*
- * Implementation using inet_ntop()
- */
- if (inet_ntop(af, src, dst, size) == NULL) {
- pj_status_t status = pj_get_netos_error();
- if (status == PJ_SUCCESS)
- status = PJ_EUNKNOWN;
- return status;
- }
- return PJ_SUCCESS;
- #elif defined(PJ_WIN32) || defined(PJ_WIN64) || defined(PJ_WIN32_WINCE)
- /*
- * Implementation on Windows, using WSAAddressToString().
- * Should also work on Unicode systems.
- */
- {
- PJ_DECL_UNICODE_TEMP_BUF(wtempaddr, PJ_INET6_ADDRSTRLEN)
- pj_sockaddr sock_addr;
- DWORD addr_len, addr_str_len;
- int rc;
- pj_bzero(&sock_addr, sizeof(sock_addr));
- sock_addr.addr.sa_family = (pj_uint16_t)af;
- if (af == PJ_AF_INET) {
- if (size < PJ_INET_ADDRSTRLEN)
- return PJ_ETOOSMALL;
- pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
- addr_len = sizeof(pj_sockaddr_in);
- addr_str_len = PJ_INET_ADDRSTRLEN;
- }
- else if (af == PJ_AF_INET6) {
- if (size < PJ_INET6_ADDRSTRLEN)
- return PJ_ETOOSMALL;
- pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
- addr_len = sizeof(pj_sockaddr_in6);
- addr_str_len = PJ_INET6_ADDRSTRLEN;
- }
- else {
- pj_assert(!"Unsupported address family");
- return PJ_EAFNOTSUP;
- }
- #if PJ_NATIVE_STRING_IS_UNICODE
- rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
- NULL, wtempaddr, &addr_str_len);
- if (rc == 0) {
- pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
- }
- #else
- rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
- NULL, dst, &addr_str_len);
- #endif
- if (rc != 0) {
- pj_status_t status = pj_get_netos_error();
- if (status == PJ_SUCCESS)
- status = PJ_EUNKNOWN;
- return status;
- }
- return PJ_SUCCESS;
- }
- #elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
- /* IPv6 support is disabled, just return error without raising assertion */
- return PJ_EIPV6NOTSUP;
- #else
- pj_assert(!"Not supported");
- return PJ_EIPV6NOTSUP;
- #endif
- }
- /*
- * Get hostname.
- */
- PJ_DEF(const pj_str_t*) pj_gethostname(void)
- {
- static char buf[PJ_MAX_HOSTNAME];
- static pj_str_t hostname;
- PJ_CHECK_STACK();
- if (hostname.ptr == NULL) {
- hostname.ptr = buf;
- if (gethostname(buf, sizeof(buf)) != 0) {
- hostname.ptr[0] = '\0';
- hostname.slen = 0;
- }
- else {
- hostname.slen = strlen(buf);
- }
- }
- return &hostname;
- }
- /*
- * Create new socket/endpoint for communication and returns a descriptor.
- */
- PJ_DEF(pj_status_t) pj_sock_socket(int af,
- int type,
- int proto,
- pj_sock_t *p_sock)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(p_sock!=NULL, PJ_EINVAL);
- PjUwpSocket *s = new PjUwpSocket(af, type, proto);
-
- /* Init UDP socket here */
- if (type == pj_SOCK_DGRAM()) {
- s->InitSocket(SOCKTYPE_DATAGRAM);
- }
- *p_sock = (pj_sock_t)s;
- return PJ_SUCCESS;
- }
- /*
- * Bind socket.
- */
- PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
- const pj_sockaddr_t *addr,
- int len)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock, PJ_EINVAL);
- PJ_ASSERT_RETURN(addr && len>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- return s->Bind(addr);
- }
- /*
- * Bind socket.
- */
- PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
- pj_uint32_t addr32,
- pj_uint16_t port)
- {
- pj_sockaddr_in addr;
- PJ_CHECK_STACK();
- pj_bzero(&addr, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- addr.sin_addr.s_addr = pj_htonl(addr32);
- addr.sin_port = pj_htons(port);
- return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
- }
- /*
- * Close socket.
- */
- PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock, PJ_EINVAL);
- if (sock == PJ_INVALID_SOCKET)
- return PJ_SUCCESS;
- PjUwpSocket *s = (PjUwpSocket*)sock;
- delete s;
- return PJ_SUCCESS;
- }
- /*
- * Get remote's name.
- */
- PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
- pj_sockaddr_t *addr,
- int *namelen)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock && addr && namelen &&
- *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- pj_sockaddr_cp(addr, s->GetRemoteAddr());
- *namelen = pj_sockaddr_get_len(addr);
- return PJ_SUCCESS;
- }
- /*
- * Get socket name.
- */
- PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
- pj_sockaddr_t *addr,
- int *namelen)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock && addr && namelen &&
- *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- pj_sockaddr_cp(addr, s->GetLocalAddr());
- *namelen = pj_sockaddr_get_len(addr);
- return PJ_SUCCESS;
- }
- /*
- * Send data
- */
- PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
- const void *buf,
- pj_ssize_t *len,
- unsigned flags)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
- PJ_UNUSED_ARG(flags);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- return s->Send(buf, len);
- }
- /*
- * Send data.
- */
- PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
- const void *buf,
- pj_ssize_t *len,
- unsigned flags,
- const pj_sockaddr_t *to,
- int tolen)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
- PJ_UNUSED_ARG(flags);
- PJ_UNUSED_ARG(tolen);
-
- PjUwpSocket *s = (PjUwpSocket*)sock;
- return s->SendTo(buf, len, to);
- }
- /*
- * Receive data.
- */
- PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
- void *buf,
- pj_ssize_t *len,
- unsigned flags)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock && len && *len > 0, PJ_EINVAL);
-
- PJ_UNUSED_ARG(flags);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- return s->Recv(buf, len);
- }
- /*
- * Receive data.
- */
- PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
- void *buf,
- pj_ssize_t *len,
- unsigned flags,
- pj_sockaddr_t *from,
- int *fromlen)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock && buf && len && from && fromlen, PJ_EINVAL);
- PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
- PJ_ASSERT_RETURN(*fromlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);
- PJ_UNUSED_ARG(flags);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- pj_status_t status = s->RecvFrom(buf, len, from);
- if (status == PJ_SUCCESS)
- *fromlen = pj_sockaddr_get_len(from);
- return status;
- }
- /*
- * Get socket option.
- */
- PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
- pj_uint16_t level,
- pj_uint16_t optname,
- void *optval,
- int *optlen)
- {
- // Not supported for now.
- PJ_UNUSED_ARG(sock);
- PJ_UNUSED_ARG(level);
- PJ_UNUSED_ARG(optname);
- PJ_UNUSED_ARG(optval);
- PJ_UNUSED_ARG(optlen);
- return PJ_ENOTSUP;
- }
- /*
- * Set socket option.
- */
- PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
- pj_uint16_t level,
- pj_uint16_t optname,
- const void *optval,
- int optlen)
- {
- // Not supported for now.
- PJ_UNUSED_ARG(sock);
- PJ_UNUSED_ARG(level);
- PJ_UNUSED_ARG(optname);
- PJ_UNUSED_ARG(optval);
- PJ_UNUSED_ARG(optlen);
- return PJ_ENOTSUP;
- }
- /*
- * Set socket option.
- */
- PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd,
- const pj_sockopt_params *params)
- {
- unsigned int i = 0;
- pj_status_t retval = PJ_SUCCESS;
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(params, PJ_EINVAL);
- for (;i<params->cnt && i<PJ_MAX_SOCKOPT_PARAMS;++i) {
- pj_status_t status = pj_sock_setsockopt(sockfd,
- (pj_uint16_t)params->options[i].level,
- (pj_uint16_t)params->options[i].optname,
- params->options[i].optval,
- params->options[i].optlen);
- if (status != PJ_SUCCESS) {
- retval = status;
- PJ_PERROR(4,(THIS_FILE, status,
- "Warning: error applying sock opt %d",
- params->options[i].optname));
- }
- }
- return retval;
- }
- /*
- * Connect socket.
- */
- PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
- const pj_sockaddr_t *addr,
- int namelen)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock && addr, PJ_EINVAL);
- PJ_UNUSED_ARG(namelen);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- return s->Connect(addr);
- }
- /*
- * Shutdown socket.
- */
- #if PJ_HAS_TCP
- PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
- int how)
- {
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sock, PJ_EINVAL);
- PJ_UNUSED_ARG(how);
- return pj_sock_close(sock);
- }
- /*
- * Start listening to incoming connections.
- */
- PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
- int backlog)
- {
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(backlog);
- PJ_ASSERT_RETURN(sock, PJ_EINVAL);
- PjUwpSocket *s = (PjUwpSocket*)sock;
- return s->Listen();
- }
- /*
- * Accept incoming connections
- */
- PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
- pj_sock_t *newsock,
- pj_sockaddr_t *addr,
- int *addrlen)
- {
- pj_status_t status;
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(serverfd && newsock, PJ_EINVAL);
- PjUwpSocket *s = (PjUwpSocket*)serverfd;
- PjUwpSocket *new_uwp_sock;
- status = s->Accept(&new_uwp_sock);
- if (status != PJ_SUCCESS)
- return status;
- if (newsock == NULL)
- return PJ_ENOTFOUND;
- *newsock = (pj_sock_t)new_uwp_sock;
- if (addr)
- pj_sockaddr_cp(addr, new_uwp_sock->GetRemoteAddr());
- if (addrlen)
- *addrlen = pj_sockaddr_get_len(addr);
- return PJ_SUCCESS;
- }
- #endif /* PJ_HAS_TCP */
|