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