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