e72bbdad79340e791b2bcef41f17efe0030eb907
[asterisk/asterisk.git] / res / pjproject / pjlib / src / pj / sock_symbian.cpp
1 /* $Id$ */
2 /* 
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19  */
20 #include <pj/sock.h>
21 #include <pj/addr_resolv.h>
22 #include <pj/assert.h>
23 #include <pj/errno.h>
24 #include <pj/os.h>
25 #include <pj/string.h>
26 #include <pj/unicode.h>
27
28 #include "os_symbian.h"
29
30
31 /*
32  * Address families.
33  */
34 const pj_uint16_t PJ_AF_UNSPEC  = KAFUnspec;
35 const pj_uint16_t PJ_AF_UNIX    = 0xFFFF;
36 const pj_uint16_t PJ_AF_INET    = KAfInet;
37 const pj_uint16_t PJ_AF_INET6   = KAfInet6;
38 const pj_uint16_t PJ_AF_PACKET  = 0xFFFF;
39 const pj_uint16_t PJ_AF_IRDA    = 0xFFFF;
40
41 /*
42  * Socket types conversion.
43  * The values here are indexed based on pj_sock_type
44  */
45 const pj_uint16_t PJ_SOCK_STREAM= KSockStream;
46 const pj_uint16_t PJ_SOCK_DGRAM = KSockDatagram;
47 const pj_uint16_t PJ_SOCK_RAW   = 0xFFFF;
48 const pj_uint16_t PJ_SOCK_RDM   = 0xFFFF;
49
50 /* we don't support setsockopt(), these are just dummy values */
51 const pj_uint16_t PJ_SOL_SOCKET = 0xFFFF;
52 const pj_uint16_t PJ_SOL_IP     = 0xFFFF;
53 const pj_uint16_t PJ_SOL_TCP    = 0xFFFF;
54 const pj_uint16_t PJ_SOL_UDP    = 0xFFFF;
55 const pj_uint16_t PJ_SOL_IPV6   = 0xFFFF;
56 const pj_uint16_t PJ_SO_NOSIGPIPE = 0xFFFF;
57
58 /* TOS */
59 const pj_uint16_t PJ_IP_TOS             = 0;
60 const pj_uint16_t PJ_IPTOS_LOWDELAY     = 0;
61 const pj_uint16_t PJ_IPTOS_THROUGHPUT   = 0;
62 const pj_uint16_t PJ_IPTOS_RELIABILITY  = 0;
63 const pj_uint16_t PJ_IPTOS_MINCOST      = 0;
64
65 /* Misc */
66 const pj_uint16_t PJ_TCP_NODELAY = 0xFFFF;
67 const pj_uint16_t PJ_SO_REUSEADDR = 0xFFFF;
68 const pj_uint16_t PJ_SO_PRIORITY = 0xFFFF;
69
70 /* ioctl() is also not supported. */
71 const pj_uint16_t PJ_SO_TYPE    = 0xFFFF;
72 const pj_uint16_t PJ_SO_RCVBUF  = 0xFFFF;
73 const pj_uint16_t PJ_SO_SNDBUF  = 0xFFFF;
74
75 /* IP multicast is also not supported. */
76 const pj_uint16_t PJ_IP_MULTICAST_IF    = 0xFFFF;
77 const pj_uint16_t PJ_IP_MULTICAST_TTL   = 0xFFFF;
78 const pj_uint16_t PJ_IP_MULTICAST_LOOP  = 0xFFFF;
79 const pj_uint16_t PJ_IP_ADD_MEMBERSHIP  = 0xFFFF;
80 const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
81
82 /* Flags */
83 const int PJ_MSG_OOB         = 0;
84 const int PJ_MSG_PEEK        = KSockReadPeek;
85 const int PJ_MSG_DONTROUTE   = 0;
86
87 /////////////////////////////////////////////////////////////////////////////
88 //
89 // CPjSocket implementation.
90 // (declaration is in os_symbian.h)
91 //
92
93 CPjSocket::~CPjSocket()
94 {
95     DestroyReader();
96     sock_.Close();
97 }
98
99
100 // Create socket reader.
101 CPjSocketReader *CPjSocket::CreateReader(unsigned max_len)
102 {
103     pj_assert(sockReader_ == NULL);
104     return sockReader_ = CPjSocketReader::NewL(*this, max_len);
105 }
106
107 // Delete socket reader when it's not wanted.
108 void CPjSocket::DestroyReader() 
109 {
110     if (sockReader_) {
111         sockReader_->Cancel();
112         delete sockReader_;
113         sockReader_ = NULL;
114     }
115 }
116
117
118 /////////////////////////////////////////////////////////////////////////////
119 //
120 // CPjSocketReader implementation
121 // (declaration in os_symbian.h)
122 //
123
124
125 CPjSocketReader::CPjSocketReader(CPjSocket &sock)
126 : CActive(EPriorityStandard), 
127   sock_(sock), buffer_(NULL, 0), readCb_(NULL), key_(NULL)
128 {
129 }
130
131
132 void CPjSocketReader::ConstructL(unsigned max_len)
133 {
134     isDatagram_ = sock_.IsDatagram();
135
136     TUint8 *ptr = new TUint8[max_len];
137     buffer_.Set(ptr, 0, (TInt)max_len);
138     CActiveScheduler::Add(this);
139 }
140
141 CPjSocketReader *CPjSocketReader::NewL(CPjSocket &sock, unsigned max_len)
142 {
143     CPjSocketReader *self = new (ELeave) CPjSocketReader(sock);
144     CleanupStack::PushL(self);
145     self->ConstructL(max_len);
146     CleanupStack::Pop(self);
147
148     return self;
149 }
150
151
152 CPjSocketReader::~CPjSocketReader()
153 {
154     const TUint8 *data = buffer_.Ptr();
155     delete [] data;
156 }
157
158 void CPjSocketReader::StartRecv(void (*cb)(void *key), 
159                                 void *key, 
160                                 TDes8 *aDesc,
161                                 TUint flags)
162 {
163     StartRecvFrom(cb, key, aDesc, flags, NULL);
164 }
165
166 void CPjSocketReader::StartRecvFrom(void (*cb)(void *key), 
167                                     void *key, 
168                                     TDes8 *aDesc,
169                                     TUint flags,
170                                     TSockAddr *fromAddr)
171 {
172     readCb_ = cb;
173     key_ = key;
174
175     if (aDesc == NULL) aDesc = &buffer_;
176     if (fromAddr == NULL) fromAddr = &recvAddr_;
177
178     sock_.Socket().RecvFrom(*aDesc, *fromAddr, flags, iStatus);
179     SetActive();
180 }
181
182 void CPjSocketReader::DoCancel()
183 {
184     sock_.Socket().CancelRecv();
185 }
186
187 void CPjSocketReader::RunL()
188 {
189     void (*old_cb)(void *key) = readCb_;
190     void *old_key = key_;
191
192     readCb_ = NULL;
193     key_ = NULL;
194
195     if (old_cb) {
196         (*old_cb)(old_key);
197     }
198 }
199
200 // Append data to aDesc, up to aDesc's maximum size.
201 // If socket is datagram based, buffer_ will be clared.
202 void CPjSocketReader::ReadData(TDes8 &aDesc, TInetAddr *addr)
203 {
204     if (isDatagram_)
205         aDesc.Zero();
206
207     if (buffer_.Length() == 0)
208         return;
209
210     TInt size_to_copy = aDesc.MaxLength() - aDesc.Length();
211     if (size_to_copy > buffer_.Length())
212         size_to_copy = buffer_.Length();
213
214     aDesc.Append(buffer_.Ptr(), size_to_copy);
215
216     if (isDatagram_)
217         buffer_.Zero();
218     else
219         buffer_.Delete(0, size_to_copy);
220
221     if (addr)
222         *addr = recvAddr_;
223 }
224
225
226
227 /////////////////////////////////////////////////////////////////////////////
228 //
229 // PJLIB's sock.h implementation
230 //
231
232 /*
233  * Convert 16-bit value from network byte order to host byte order.
234  */
235 PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
236 {
237 #if PJ_IS_LITTLE_ENDIAN
238     return pj_swap16(netshort);
239 #else
240     return netshort;
241 #endif
242 }
243
244 /*
245  * Convert 16-bit value from host byte order to network byte order.
246  */
247 PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
248 {
249 #if PJ_IS_LITTLE_ENDIAN
250     return pj_swap16(hostshort);
251 #else
252     return hostshort;
253 #endif
254 }
255
256 /*
257  * Convert 32-bit value from network byte order to host byte order.
258  */
259 PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
260 {
261 #if PJ_IS_LITTLE_ENDIAN
262     return pj_swap32(netlong);
263 #else
264     return netlong;
265 #endif
266 }
267
268 /*
269  * Convert 32-bit value from host byte order to network byte order.
270  */
271 PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
272 {
273 #if PJ_IS_LITTLE_ENDIAN
274     return pj_swap32(hostlong);
275 #else
276     return netlong;
277 #endif
278 }
279
280 /*
281  * Convert an Internet host address given in network byte order
282  * to string in standard numbers and dots notation.
283  */
284 PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
285 {
286         static char str8[PJ_INET_ADDRSTRLEN];
287     TBuf<PJ_INET_ADDRSTRLEN> str16(0);
288
289     /* (Symbian IP address is in host byte order) */
290     TInetAddr temp_addr((TUint32)pj_ntohl(inaddr.s_addr), (TUint)0);
291     temp_addr.Output(str16);
292  
293     return pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
294                               str8, sizeof(str8));
295 }
296
297 /*
298  * This function converts the Internet host address cp from the standard
299  * numbers-and-dots notation into binary data and stores it in the structure
300  * that inp points to. 
301  */
302 PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp)
303 {
304     enum { MAXIPLEN = PJ_INET_ADDRSTRLEN };
305
306     /* Initialize output with PJ_INADDR_NONE.
307      * Some apps relies on this instead of the return value
308      * (and anyway the return value is quite confusing!)
309      */
310     inp->s_addr = PJ_INADDR_NONE;
311
312     /* Caution:
313      *  this function might be called with cp->slen >= 16
314      *  (i.e. when called with hostname to check if it's an IP addr).
315      */
316     PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
317     if (cp->slen >= 16) {
318         return 0;
319     }
320
321     char tempaddr8[MAXIPLEN];
322     pj_memcpy(tempaddr8, cp->ptr, cp->slen);
323     tempaddr8[cp->slen] = '\0';
324
325     wchar_t tempaddr16[MAXIPLEN];
326     pj_ansi_to_unicode(tempaddr8, pj_ansi_strlen(tempaddr8),
327                        tempaddr16, sizeof(tempaddr16));
328
329     TBuf<MAXIPLEN> ip_addr((const TText*)tempaddr16);
330
331     TInetAddr addr;
332     addr.Init(KAfInet);
333     if (addr.Input(ip_addr) == KErrNone) {
334         /* Success (Symbian IP address is in host byte order) */
335         inp->s_addr = pj_htonl(addr.Address());
336         return 1;
337     } else {
338         /* Error */
339         return 0;
340     }
341 }
342
343 /*
344  * Convert text to IPv4/IPv6 address.
345  */
346 PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
347 {
348     char tempaddr[PJ_INET6_ADDRSTRLEN];
349
350     PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
351     PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
352
353     /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be 
354      * compatible with pj_inet_aton()
355      */
356     if (af==PJ_AF_INET) {
357         ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
358     }
359
360     /* Caution:
361      *  this function might be called with cp->slen >= 46
362      *  (i.e. when called with hostname to check if it's an IP addr).
363      */
364     if (src->slen >= PJ_INET6_ADDRSTRLEN) {
365         return PJ_ENAMETOOLONG;
366     }
367
368     pj_memcpy(tempaddr, src->ptr, src->slen);
369     tempaddr[src->slen] = '\0';
370
371
372     wchar_t tempaddr16[PJ_INET6_ADDRSTRLEN];
373     pj_ansi_to_unicode(tempaddr, pj_ansi_strlen(tempaddr),
374                        tempaddr16, sizeof(tempaddr16));
375
376     TBuf<PJ_INET6_ADDRSTRLEN> ip_addr((const TText*)tempaddr16);
377
378     TInetAddr addr;
379     addr.Init(KAfInet6);
380     if (addr.Input(ip_addr) == KErrNone) {
381         if (af==PJ_AF_INET) {
382             /* Success (Symbian IP address is in host byte order) */
383             pj_uint32_t ip = pj_htonl(addr.Address());
384             pj_memcpy(dst, &ip, 4);
385         } else if (af==PJ_AF_INET6) {
386             const TIp6Addr & ip6 = addr.Ip6Address();
387             pj_memcpy(dst, ip6.u.iAddr8, 16);
388         } else {
389             pj_assert(!"Unexpected!");
390             return PJ_EBUG;
391         }
392         return PJ_SUCCESS;
393     } else {
394         /* Error */
395         return PJ_EINVAL;
396     }
397 }
398
399 /*
400  * Convert IPv4/IPv6 address to text.
401  */
402 PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
403                                  char *dst, int size)
404
405 {
406     PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
407
408     *dst = '\0';
409
410     if (af==PJ_AF_INET) {
411
412         TBuf<PJ_INET_ADDRSTRLEN> str16;
413         pj_in_addr inaddr;
414
415         if (size < PJ_INET_ADDRSTRLEN)
416             return PJ_ETOOSMALL;
417
418         pj_memcpy(&inaddr, src, 4);
419
420         /* Symbian IP address is in host byte order */
421         TInetAddr temp_addr((TUint32)pj_ntohl(inaddr.s_addr), (TUint)0);
422         temp_addr.Output(str16);
423  
424         pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
425                            dst, size);
426         return PJ_SUCCESS;
427
428     } else if (af==PJ_AF_INET6) {
429         TBuf<PJ_INET6_ADDRSTRLEN> str16;
430
431         if (size < PJ_INET6_ADDRSTRLEN)
432             return PJ_ETOOSMALL;
433
434         TIp6Addr ip6;
435         pj_memcpy(ip6.u.iAddr8, src, 16);
436
437         TInetAddr temp_addr(ip6, (TUint)0);
438         temp_addr.Output(str16);
439  
440         pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
441                            dst, size);
442         return PJ_SUCCESS;
443
444     } else {
445         pj_assert(!"Unsupport address family");
446         return PJ_EINVAL;
447     }
448
449 }
450
451 /*
452  * Get hostname.
453  */
454 PJ_DEF(const pj_str_t*) pj_gethostname(void)
455 {
456     static char buf[PJ_MAX_HOSTNAME];
457     static pj_str_t hostname;
458
459     PJ_CHECK_STACK();
460
461     if (hostname.ptr == NULL) {
462         RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(PJ_AF_INET);
463         TRequestStatus reqStatus;
464         THostName tmpName;
465
466         // Return empty hostname if access point is marked as down by app.
467         PJ_SYMBIAN_CHECK_CONNECTION2(&hostname);
468
469         resv.GetHostName(tmpName, reqStatus);
470         User::WaitForRequest(reqStatus);
471
472         hostname.ptr = pj_unicode_to_ansi((const wchar_t*)tmpName.Ptr(), tmpName.Length(),
473                                           buf, sizeof(buf));
474         hostname.slen = tmpName.Length();
475     }
476     return &hostname;
477 }
478
479 /*
480  * Create new socket/endpoint for communication and returns a descriptor.
481  */
482 PJ_DEF(pj_status_t) pj_sock_socket(int af, 
483                                    int type, 
484                                    int proto,
485                                    pj_sock_t *p_sock)
486 {
487     TInt rc;
488
489     PJ_CHECK_STACK();
490
491     /* Sanity checks. */
492     PJ_ASSERT_RETURN(p_sock!=NULL, PJ_EINVAL);
493
494     // Return failure if access point is marked as down by app.
495     PJ_SYMBIAN_CHECK_CONNECTION();
496     
497     /* Set proto if none is specified. */
498     if (proto == 0) {
499         if (type == pj_SOCK_STREAM())
500             proto = KProtocolInetTcp;
501         else if (type == pj_SOCK_DGRAM())
502             proto = KProtocolInetUdp;
503     }
504
505     /* Create Symbian RSocket */
506     RSocket rSock;
507     if (PjSymbianOS::Instance()->Connection())
508         rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(), 
509                         af, type, proto,
510                         *PjSymbianOS::Instance()->Connection());
511     else
512         rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(), 
513                         af, type, proto);
514         
515     if (rc != KErrNone)
516         return PJ_RETURN_OS_ERROR(rc);
517
518
519     /* Wrap Symbian RSocket into PJLIB's CPjSocket, and return to caller */
520     CPjSocket *pjSock = new CPjSocket(af, type, rSock);
521     *p_sock = (pj_sock_t)pjSock;
522
523     return PJ_SUCCESS;
524 }
525
526
527 /*
528  * Bind socket.
529  */
530 PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, 
531                                   const pj_sockaddr_t *addr,
532                                   int len)
533 {
534     pj_status_t status;
535     TInt rc;
536
537     PJ_CHECK_STACK();
538
539     PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
540     PJ_ASSERT_RETURN(addr && len>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
541
542     // Convert PJLIB's pj_sockaddr into Symbian's TInetAddr
543     TInetAddr inetAddr;
544     status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, len, inetAddr);
545     if (status != PJ_SUCCESS)
546         return status;
547
548     // Get the RSocket instance
549     RSocket &rSock = ((CPjSocket*)sock)->Socket();
550
551     // Bind
552     rc = rSock.Bind(inetAddr);
553
554     return (rc==KErrNone) ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
555 }
556
557
558 /*
559  * Bind socket.
560  */
561 PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, 
562                                      pj_uint32_t addr32,
563                                      pj_uint16_t port)
564 {
565     pj_sockaddr_in addr;
566
567     PJ_CHECK_STACK();
568
569     pj_bzero(&addr, sizeof(addr));
570     addr.sin_family = PJ_AF_INET;
571     addr.sin_addr.s_addr = pj_htonl(addr32);
572     addr.sin_port = pj_htons(port);
573
574     return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
575 }
576
577
578 /*
579  * Close socket.
580  */
581 PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
582 {
583     PJ_CHECK_STACK();
584
585     PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
586
587     CPjSocket *pjSock = (CPjSocket*)sock;
588
589     // This will close the socket.
590     delete pjSock;
591
592     return PJ_SUCCESS;
593 }
594
595 /*
596  * Get remote's name.
597  */
598 PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
599                                          pj_sockaddr_t *addr,
600                                          int *namelen)
601 {
602     PJ_CHECK_STACK();
603     
604     PJ_ASSERT_RETURN(sock && addr && namelen && 
605                      *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
606
607     CPjSocket *pjSock = (CPjSocket*)sock;
608     RSocket &rSock = pjSock->Socket();
609
610     // Socket must be connected.
611     PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
612
613     TInetAddr inetAddr;
614     rSock.RemoteName(inetAddr);
615
616     return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
617 }
618
619 /*
620  * Get socket name.
621  */
622 PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
623                                          pj_sockaddr_t *addr,
624                                          int *namelen)
625 {
626     PJ_CHECK_STACK();
627     
628     PJ_ASSERT_RETURN(sock && addr && namelen && 
629                      *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
630
631     CPjSocket *pjSock = (CPjSocket*)sock;
632     RSocket &rSock = pjSock->Socket();
633
634     TInetAddr inetAddr;
635     rSock.LocalName(inetAddr);
636
637     return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
638 }
639
640 /*
641  * Send data
642  */
643 PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
644                                  const void *buf,
645                                  pj_ssize_t *len,
646                                  unsigned flags)
647 {
648     PJ_CHECK_STACK();
649     PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
650
651     // Return failure if access point is marked as down by app.
652     PJ_SYMBIAN_CHECK_CONNECTION();
653     
654     CPjSocket *pjSock = (CPjSocket*)sock;
655     RSocket &rSock = pjSock->Socket();
656
657     // send() should only be called to connected socket
658     PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
659
660     TPtrC8 data((const TUint8*)buf, (TInt)*len);
661     TRequestStatus reqStatus;
662     TSockXfrLength sentLen;
663
664     rSock.Send(data, flags, reqStatus, sentLen);
665     User::WaitForRequest(reqStatus);
666
667     if (reqStatus.Int()==KErrNone) {
668         //*len = (TInt) sentLen.Length();
669         return PJ_SUCCESS;
670     } else
671         return PJ_RETURN_OS_ERROR(reqStatus.Int());
672 }
673
674
675 /*
676  * Send data.
677  */
678 PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
679                                    const void *buf,
680                                    pj_ssize_t *len,
681                                    unsigned flags,
682                                    const pj_sockaddr_t *to,
683                                    int tolen)
684 {
685     pj_status_t status;
686     
687     PJ_CHECK_STACK();
688     PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
689
690     // Return failure if access point is marked as down by app.
691     PJ_SYMBIAN_CHECK_CONNECTION();
692     
693     CPjSocket *pjSock = (CPjSocket*)sock;
694     RSocket &rSock = pjSock->Socket();
695
696     // Only supports AF_INET for now
697     PJ_ASSERT_RETURN(tolen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
698
699     TInetAddr inetAddr;
700     status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)to, tolen, inetAddr);
701     if (status != PJ_SUCCESS)
702         return status;
703
704     TPtrC8 data((const TUint8*)buf, (TInt)*len);
705     TRequestStatus reqStatus;
706     TSockXfrLength sentLen;
707
708     rSock.SendTo(data, inetAddr, flags, reqStatus, sentLen);
709     User::WaitForRequest(reqStatus);
710
711     if (reqStatus.Int()==KErrNone) {
712         //For some reason TSockXfrLength is not returning correctly!
713         //*len = (TInt) sentLen.Length();
714         return PJ_SUCCESS;
715     } else 
716         return PJ_RETURN_OS_ERROR(reqStatus.Int());
717 }
718
719 /*
720  * Receive data.
721  */
722 PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
723                                  void *buf,
724                                  pj_ssize_t *len,
725                                  unsigned flags)
726 {
727     PJ_CHECK_STACK();
728
729     PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
730     PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
731
732     // Return failure if access point is marked as down by app.
733     PJ_SYMBIAN_CHECK_CONNECTION();
734
735     CPjSocket *pjSock = (CPjSocket*)sock;
736
737     if (pjSock->Reader()) {
738         CPjSocketReader *reader = pjSock->Reader();
739
740         while (reader->IsActive() && !reader->HasData()) {
741             User::WaitForAnyRequest();
742         }
743
744         if (reader->HasData()) {
745             TPtr8 data((TUint8*)buf, (TInt)*len);
746             TInetAddr inetAddr;
747
748             reader->ReadData(data, &inetAddr);
749
750             *len = data.Length();
751             return PJ_SUCCESS;
752         }
753     }
754
755     TRequestStatus reqStatus;
756     TSockXfrLength recvLen;
757     TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
758
759     if (pjSock->IsDatagram()) {
760         pjSock->Socket().Recv(data, flags, reqStatus);
761     } else {
762         // Using static like this is not pretty, but we don't need to use
763         // the value anyway, hence doing it like this is probably most
764         // optimal.
765         static TSockXfrLength len;
766         pjSock->Socket().RecvOneOrMore(data, flags, reqStatus, len);
767     }
768     User::WaitForRequest(reqStatus);
769
770     if (reqStatus == KErrNone) {
771         //*len = (TInt)recvLen.Length();
772         *len = data.Length();
773         return PJ_SUCCESS;
774     } else {
775         *len = -1;
776         return PJ_RETURN_OS_ERROR(reqStatus.Int());
777     }
778 }
779
780 /*
781  * Receive data.
782  */
783 PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
784                                      void *buf,
785                                      pj_ssize_t *len,
786                                      unsigned flags,
787                                      pj_sockaddr_t *from,
788                                      int *fromlen)
789 {
790     PJ_CHECK_STACK();
791
792     PJ_ASSERT_RETURN(sock && buf && len && from && fromlen, PJ_EINVAL);
793     PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
794     PJ_ASSERT_RETURN(*fromlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);
795
796     // Return failure if access point is marked as down by app.
797     PJ_SYMBIAN_CHECK_CONNECTION();
798
799     CPjSocket *pjSock = (CPjSocket*)sock;
800     RSocket &rSock = pjSock->Socket();
801
802     if (pjSock->Reader()) {
803         CPjSocketReader *reader = pjSock->Reader();
804
805         while (reader->IsActive() && !reader->HasData()) {
806             User::WaitForAnyRequest();
807         }
808
809         if (reader->HasData()) {
810             TPtr8 data((TUint8*)buf, (TInt)*len);
811             TInetAddr inetAddr;
812
813             reader->ReadData(data, &inetAddr);
814
815             *len = data.Length();
816
817             if (from && fromlen) {
818                 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, 
819                                             fromlen);
820             } else {
821                 return PJ_SUCCESS;
822             }
823         }
824     }
825
826     TInetAddr inetAddr;
827     TRequestStatus reqStatus;
828     TSockXfrLength recvLen;
829     TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
830
831     rSock.RecvFrom(data, inetAddr, flags, reqStatus, recvLen);
832     User::WaitForRequest(reqStatus);
833
834     if (reqStatus == KErrNone) {
835         //*len = (TInt)recvLen.Length();
836         *len = data.Length();
837         return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, fromlen);
838     } else {
839         *len = -1;
840         *fromlen = -1;
841         return PJ_RETURN_OS_ERROR(reqStatus.Int());
842     }
843 }
844
845 /*
846  * Get socket option.
847  */
848 PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
849                                         pj_uint16_t level,
850                                         pj_uint16_t optname,
851                                         void *optval,
852                                         int *optlen)
853 {
854     // Not supported for now.
855     PJ_UNUSED_ARG(sock);
856     PJ_UNUSED_ARG(level);
857     PJ_UNUSED_ARG(optname);
858     PJ_UNUSED_ARG(optval);
859     PJ_UNUSED_ARG(optlen);
860     return PJ_EINVALIDOP;
861 }
862
863 /*
864  * Set socket option.
865  */
866 PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
867                                         pj_uint16_t level,
868                                         pj_uint16_t optname,
869                                         const void *optval,
870                                         int optlen)
871 {
872     // Not supported for now.
873     PJ_UNUSED_ARG(sock);
874     PJ_UNUSED_ARG(level);
875     PJ_UNUSED_ARG(optname);
876     PJ_UNUSED_ARG(optval);
877     PJ_UNUSED_ARG(optlen);
878     return PJ_EINVALIDOP;
879 }
880
881 /*
882  * Connect socket.
883  */
884 PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
885                                      const pj_sockaddr_t *addr,
886                                      int namelen)
887 {
888     pj_status_t status;
889     
890     PJ_CHECK_STACK();
891
892     PJ_ASSERT_RETURN(sock && addr && namelen, PJ_EINVAL);
893     PJ_ASSERT_RETURN(((pj_sockaddr*)addr)->addr.sa_family == PJ_AF_INET, 
894                      PJ_EINVAL);
895
896     // Return failure if access point is marked as down by app.
897     PJ_SYMBIAN_CHECK_CONNECTION();
898     
899     CPjSocket *pjSock = (CPjSocket*)sock;
900     RSocket &rSock = pjSock->Socket();
901
902     TInetAddr inetAddr;
903     TRequestStatus reqStatus;
904
905     status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, namelen, inetAddr);
906     if (status != PJ_SUCCESS)
907         return status;
908
909     rSock.Connect(inetAddr, reqStatus);
910     User::WaitForRequest(reqStatus);
911
912     if (reqStatus == KErrNone) {
913         pjSock->SetConnected(true);
914         return PJ_SUCCESS;
915     } else {
916         return PJ_RETURN_OS_ERROR(reqStatus.Int());
917     }
918 }
919
920
921 /*
922  * Shutdown socket.
923  */
924 #if PJ_HAS_TCP
925 PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
926                                       int how)
927 {
928     PJ_CHECK_STACK();
929
930     PJ_ASSERT_RETURN(sock, PJ_EINVAL);
931
932     CPjSocket *pjSock = (CPjSocket*)sock;
933     RSocket &rSock = pjSock->Socket();
934
935     RSocket::TShutdown aHow;
936     if (how == PJ_SD_RECEIVE)
937         aHow = RSocket::EStopInput;
938     else if (how == PJ_SHUT_WR)
939         aHow = RSocket::EStopOutput;
940     else
941         aHow = RSocket::ENormal;
942
943     TRequestStatus reqStatus;
944
945     rSock.Shutdown(aHow, reqStatus);
946     User::WaitForRequest(reqStatus);
947
948     if (reqStatus == KErrNone) {
949         return PJ_SUCCESS;
950     } else {
951         return PJ_RETURN_OS_ERROR(reqStatus.Int());
952     }
953 }
954
955 /*
956  * Start listening to incoming connections.
957  */
958 PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
959                                     int backlog)
960 {
961     PJ_CHECK_STACK();
962
963     PJ_ASSERT_RETURN(sock && backlog, PJ_EINVAL);
964
965     CPjSocket *pjSock = (CPjSocket*)sock;
966     RSocket &rSock = pjSock->Socket();
967
968     TInt rc = rSock.Listen((TUint)backlog);
969
970     if (rc == KErrNone) {
971         return PJ_SUCCESS;
972     } else {
973         return PJ_RETURN_OS_ERROR(rc);
974     }
975 }
976
977 /*
978  * Accept incoming connections
979  */
980 PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
981                                     pj_sock_t *newsock,
982                                     pj_sockaddr_t *addr,
983                                     int *addrlen)
984 {
985     PJ_CHECK_STACK();
986
987     PJ_ASSERT_RETURN(serverfd && newsock, PJ_EINVAL);
988
989     CPjSocket *pjSock = (CPjSocket*)serverfd;
990     RSocket &rSock = pjSock->Socket();
991
992     // Create a 'blank' socket
993     RSocket newSock;
994     newSock.Open(PjSymbianOS::Instance()->SocketServ());
995
996     // Call Accept()
997     TRequestStatus reqStatus;
998
999     rSock.Accept(newSock, reqStatus);
1000     User::WaitForRequest(reqStatus);
1001
1002     if (reqStatus != KErrNone) {
1003         return PJ_RETURN_OS_ERROR(reqStatus.Int());
1004     }
1005
1006     // Create PJ socket
1007     CPjSocket *newPjSock = new CPjSocket(pjSock->GetAf(), pjSock->GetSockType(),
1008                                          newSock);
1009     newPjSock->SetConnected(true);
1010
1011     *newsock = (pj_sock_t) newPjSock;
1012
1013     if (addr && addrlen) {
1014         return pj_sock_getpeername(*newsock, addr, addrlen);
1015     }
1016
1017     return PJ_SUCCESS;
1018 }
1019 #endif  /* PJ_HAS_TCP */
1020
1021