blob: 60621724c7c51829231ac6b43165ddc50fb1f689 [file] [log] [blame]
Benny Prijonof260e462007-04-30 21:03:32 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonof260e462007-04-30 21:03:32 +00005 *
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 */
Benny Prijono2a78a522007-11-21 14:10:46 +000034const pj_uint16_t PJ_AF_UNSPEC = KAFUnspec;
Benny Prijonof260e462007-04-30 21:03:32 +000035const pj_uint16_t PJ_AF_UNIX = 0xFFFF;
36const pj_uint16_t PJ_AF_INET = KAfInet;
37const pj_uint16_t PJ_AF_INET6 = KAfInet6;
38const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
39const 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 */
45const pj_uint16_t PJ_SOCK_STREAM= KSockStream;
46const pj_uint16_t PJ_SOCK_DGRAM = KSockDatagram;
47const pj_uint16_t PJ_SOCK_RAW = 0xFFFF;
48const pj_uint16_t PJ_SOCK_RDM = 0xFFFF;
49
50/* setsockop() is not really supported. */
51const pj_uint16_t PJ_SOL_SOCKET = 0xFFFF;
52const pj_uint16_t PJ_SOL_IP = 0xFFFF;
53const pj_uint16_t PJ_SOL_TCP = 0xFFFF;
54const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
55const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
56
Benny Prijono8ab968f2007-07-20 08:08:30 +000057/* TOS */
58const pj_uint16_t PJ_IP_TOS = 0;
59const pj_uint16_t PJ_IPTOS_LOWDELAY = 0;
60const pj_uint16_t PJ_IPTOS_THROUGHPUT = 0;
61const pj_uint16_t PJ_IPTOS_RELIABILITY = 0;
62const pj_uint16_t PJ_IPTOS_MINCOST = 0;
63
Benny Prijonof260e462007-04-30 21:03:32 +000064/* ioctl() is also not supported. */
65const pj_uint16_t PJ_SO_TYPE = 0xFFFF;
66const pj_uint16_t PJ_SO_RCVBUF = 0xFFFF;
67const pj_uint16_t PJ_SO_SNDBUF = 0xFFFF;
68
Nanang Izzuddinb76154e2008-09-16 16:11:44 +000069/* IP multicast is also not supported. */
Benny Prijono513d1352008-09-27 09:35:34 +000070const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
71const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
72const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
73const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
74const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
Nanang Izzuddinb76154e2008-09-16 16:11:44 +000075
Benny Prijono8ab968f2007-07-20 08:08:30 +000076/* Flags */
77const int PJ_MSG_OOB = 0;
78const int PJ_MSG_PEEK = KSockReadPeek;
79const int PJ_MSG_DONTROUTE = 0;
Benny Prijonof260e462007-04-30 21:03:32 +000080
81/////////////////////////////////////////////////////////////////////////////
82//
83// CPjSocket implementation.
84// (declaration is in os_symbian.h)
85//
86
87CPjSocket::~CPjSocket()
88{
Benny Prijono897f9f82007-05-03 19:56:21 +000089 DestroyReader();
Benny Prijonof260e462007-04-30 21:03:32 +000090 sock_.Close();
91}
92
93
94// Create socket reader.
95CPjSocketReader *CPjSocket::CreateReader(unsigned max_len)
96{
97 pj_assert(sockReader_ == NULL);
98 return sockReader_ = CPjSocketReader::NewL(*this, max_len);
99}
100
Benny Prijono897f9f82007-05-03 19:56:21 +0000101// Delete socket reader when it's not wanted.
102void CPjSocket::DestroyReader()
103{
104 if (sockReader_) {
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000105 sockReader_->Cancel();
Benny Prijono897f9f82007-05-03 19:56:21 +0000106 delete sockReader_;
107 sockReader_ = NULL;
108 }
109}
110
Benny Prijonof260e462007-04-30 21:03:32 +0000111
112/////////////////////////////////////////////////////////////////////////////
113//
114// CPjSocketReader implementation
115// (declaration in os_symbian.h)
116//
117
118
119CPjSocketReader::CPjSocketReader(CPjSocket &sock)
120: CActive(EPriorityStandard),
121 sock_(sock), buffer_(NULL, 0), readCb_(NULL), key_(NULL)
122{
123}
124
125
126void CPjSocketReader::ConstructL(unsigned max_len)
127{
Benny Prijonod77e07b2009-06-17 13:31:13 +0000128 isDatagram_ = sock_.IsDatagram();
Benny Prijonof260e462007-04-30 21:03:32 +0000129
130 TUint8 *ptr = new TUint8[max_len];
131 buffer_.Set(ptr, 0, (TInt)max_len);
132 CActiveScheduler::Add(this);
133}
134
135CPjSocketReader *CPjSocketReader::NewL(CPjSocket &sock, unsigned max_len)
136{
137 CPjSocketReader *self = new (ELeave) CPjSocketReader(sock);
138 CleanupStack::PushL(self);
139 self->ConstructL(max_len);
140 CleanupStack::Pop(self);
141
142 return self;
143}
144
145
146CPjSocketReader::~CPjSocketReader()
147{
148 const TUint8 *data = buffer_.Ptr();
149 delete [] data;
150}
151
152void CPjSocketReader::StartRecv(void (*cb)(void *key),
153 void *key,
154 TDes8 *aDesc,
155 TUint flags)
156{
157 StartRecvFrom(cb, key, aDesc, flags, NULL);
158}
159
160void CPjSocketReader::StartRecvFrom(void (*cb)(void *key),
161 void *key,
162 TDes8 *aDesc,
163 TUint flags,
164 TSockAddr *fromAddr)
165{
166 readCb_ = cb;
167 key_ = key;
168
169 if (aDesc == NULL) aDesc = &buffer_;
170 if (fromAddr == NULL) fromAddr = &recvAddr_;
171
172 sock_.Socket().RecvFrom(*aDesc, *fromAddr, flags, iStatus);
Benny Prijono5d542642007-05-02 18:54:19 +0000173 SetActive();
Benny Prijonof260e462007-04-30 21:03:32 +0000174}
175
176void CPjSocketReader::DoCancel()
177{
178 sock_.Socket().CancelRecv();
179}
180
181void CPjSocketReader::RunL()
182{
183 void (*old_cb)(void *key) = readCb_;
184 void *old_key = key_;
Benny Prijonof260e462007-04-30 21:03:32 +0000185
186 readCb_ = NULL;
187 key_ = NULL;
188
189 if (old_cb) {
190 (*old_cb)(old_key);
191 }
192}
193
194// Append data to aDesc, up to aDesc's maximum size.
195// If socket is datagram based, buffer_ will be clared.
196void CPjSocketReader::ReadData(TDes8 &aDesc, TInetAddr *addr)
197{
198 if (isDatagram_)
199 aDesc.Zero();
200
201 if (buffer_.Length() == 0)
202 return;
203
204 TInt size_to_copy = aDesc.MaxLength() - aDesc.Length();
205 if (size_to_copy > buffer_.Length())
206 size_to_copy = buffer_.Length();
207
208 aDesc.Append(buffer_.Ptr(), size_to_copy);
209
210 if (isDatagram_)
211 buffer_.Zero();
212 else
213 buffer_.Delete(0, size_to_copy);
214
215 if (addr)
216 *addr = recvAddr_;
217}
218
219
220
221/////////////////////////////////////////////////////////////////////////////
222//
223// PJLIB's sock.h implementation
224//
225
226/*
227 * Convert 16-bit value from network byte order to host byte order.
228 */
229PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
230{
Benny Prijonob2c96822007-05-03 13:31:21 +0000231#if PJ_IS_LITTLE_ENDIAN
232 return pj_swap16(netshort);
233#else
Benny Prijonof260e462007-04-30 21:03:32 +0000234 return netshort;
Benny Prijonob2c96822007-05-03 13:31:21 +0000235#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000236}
237
238/*
239 * Convert 16-bit value from host byte order to network byte order.
240 */
241PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
242{
Benny Prijonob2c96822007-05-03 13:31:21 +0000243#if PJ_IS_LITTLE_ENDIAN
244 return pj_swap16(hostshort);
245#else
Benny Prijonof260e462007-04-30 21:03:32 +0000246 return hostshort;
Benny Prijonob2c96822007-05-03 13:31:21 +0000247#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000248}
249
250/*
251 * Convert 32-bit value from network byte order to host byte order.
252 */
253PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
254{
Benny Prijonob2c96822007-05-03 13:31:21 +0000255#if PJ_IS_LITTLE_ENDIAN
256 return pj_swap32(netlong);
257#else
Benny Prijonof260e462007-04-30 21:03:32 +0000258 return netlong;
Benny Prijonob2c96822007-05-03 13:31:21 +0000259#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000260}
261
262/*
263 * Convert 32-bit value from host byte order to network byte order.
264 */
265PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
266{
Benny Prijonob2c96822007-05-03 13:31:21 +0000267#if PJ_IS_LITTLE_ENDIAN
268 return pj_swap32(hostlong);
269#else
270 return netlong;
271#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000272}
273
274/*
275 * Convert an Internet host address given in network byte order
276 * to string in standard numbers and dots notation.
277 */
278PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
279{
Benny Prijonocd700b12008-01-02 08:22:38 +0000280 static char str8[PJ_INET_ADDRSTRLEN];
281 TBuf<PJ_INET_ADDRSTRLEN> str16(0);
Benny Prijonof260e462007-04-30 21:03:32 +0000282
Benny Prijonob2c96822007-05-03 13:31:21 +0000283 /* (Symbian IP address is in host byte order) */
284 TInetAddr temp_addr((TUint32)pj_ntohl(inaddr.s_addr), (TUint)0);
Benny Prijonof260e462007-04-30 21:03:32 +0000285 temp_addr.Output(str16);
286
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000287 return pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
Benny Prijonof260e462007-04-30 21:03:32 +0000288 str8, sizeof(str8));
289}
290
291/*
292 * This function converts the Internet host address cp from the standard
293 * numbers-and-dots notation into binary data and stores it in the structure
294 * that inp points to.
295 */
296PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
297{
Benny Prijonocd700b12008-01-02 08:22:38 +0000298 enum { MAXIPLEN = PJ_INET_ADDRSTRLEN };
Benny Prijonof260e462007-04-30 21:03:32 +0000299
300 /* Initialize output with PJ_INADDR_NONE.
301 * Some apps relies on this instead of the return value
302 * (and anyway the return value is quite confusing!)
303 */
304 inp->s_addr = PJ_INADDR_NONE;
305
306 /* Caution:
307 * this function might be called with cp->slen >= 16
308 * (i.e. when called with hostname to check if it's an IP addr).
309 */
310 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
311 if (cp->slen >= 16) {
312 return 0;
313 }
314
315 char tempaddr8[MAXIPLEN];
316 pj_memcpy(tempaddr8, cp->ptr, cp->slen);
317 tempaddr8[cp->slen] = '\0';
318
319 wchar_t tempaddr16[MAXIPLEN];
320 pj_ansi_to_unicode(tempaddr8, pj_ansi_strlen(tempaddr8),
321 tempaddr16, sizeof(tempaddr16));
322
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000323 TBuf<MAXIPLEN> ip_addr((const TText*)tempaddr16);
Benny Prijonof260e462007-04-30 21:03:32 +0000324
325 TInetAddr addr;
326 addr.Init(KAfInet);
327 if (addr.Input(ip_addr) == KErrNone) {
Benny Prijonob2c96822007-05-03 13:31:21 +0000328 /* Success (Symbian IP address is in host byte order) */
329 inp->s_addr = pj_htonl(addr.Address());
Benny Prijonof260e462007-04-30 21:03:32 +0000330 return 1;
331 } else {
332 /* Error */
333 return 0;
334 }
335}
336
337/*
Benny Prijono2a78a522007-11-21 14:10:46 +0000338 * Convert text to IPv4/IPv6 address.
339 */
340PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
341{
342 char tempaddr[PJ_INET6_ADDRSTRLEN];
343
344 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
345 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
346
347 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
348 * compatible with pj_inet_aton()
349 */
350 if (af==PJ_AF_INET) {
351 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
352 }
353
354 /* Caution:
355 * this function might be called with cp->slen >= 46
356 * (i.e. when called with hostname to check if it's an IP addr).
357 */
358 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
359 return PJ_ENAMETOOLONG;
360 }
361
362 pj_memcpy(tempaddr, src->ptr, src->slen);
363 tempaddr[src->slen] = '\0';
364
365
366 wchar_t tempaddr16[PJ_INET6_ADDRSTRLEN];
367 pj_ansi_to_unicode(tempaddr, pj_ansi_strlen(tempaddr),
368 tempaddr16, sizeof(tempaddr16));
369
370 TBuf<PJ_INET6_ADDRSTRLEN> ip_addr((const TText*)tempaddr16);
371
372 TInetAddr addr;
373 addr.Init(KAfInet6);
374 if (addr.Input(ip_addr) == KErrNone) {
375 if (af==PJ_AF_INET) {
376 /* Success (Symbian IP address is in host byte order) */
377 pj_uint32_t ip = pj_htonl(addr.Address());
378 pj_memcpy(dst, &ip, 4);
379 } else if (af==PJ_AF_INET6) {
380 const TIp6Addr & ip6 = addr.Ip6Address();
381 pj_memcpy(dst, ip6.u.iAddr8, 16);
382 } else {
383 pj_assert(!"Unexpected!");
384 return PJ_EBUG;
385 }
386 return PJ_SUCCESS;
387 } else {
388 /* Error */
389 return PJ_EINVAL;
390 }
391}
392
393/*
394 * Convert IPv4/IPv6 address to text.
395 */
396PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
397 char *dst, int size)
398
399{
400 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
401
402 *dst = '\0';
403
404 if (af==PJ_AF_INET) {
405
406 TBuf<PJ_INET_ADDRSTRLEN> str16;
407 pj_in_addr inaddr;
408
Benny Prijono9db4bd62007-12-31 11:26:21 +0000409 if (size < PJ_INET_ADDRSTRLEN)
Benny Prijono2a78a522007-11-21 14:10:46 +0000410 return PJ_ETOOSMALL;
411
412 pj_memcpy(&inaddr, src, 4);
413
414 /* Symbian IP address is in host byte order */
415 TInetAddr temp_addr((TUint32)pj_ntohl(inaddr.s_addr), (TUint)0);
416 temp_addr.Output(str16);
417
418 pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
419 dst, size);
420 return PJ_SUCCESS;
421
422 } else if (af==PJ_AF_INET6) {
423 TBuf<PJ_INET6_ADDRSTRLEN> str16;
424
Benny Prijono9db4bd62007-12-31 11:26:21 +0000425 if (size < PJ_INET6_ADDRSTRLEN)
Benny Prijono2a78a522007-11-21 14:10:46 +0000426 return PJ_ETOOSMALL;
427
428 TIp6Addr ip6;
429 pj_memcpy(ip6.u.iAddr8, src, 16);
430
431 TInetAddr temp_addr(ip6, (TUint)0);
432 temp_addr.Output(str16);
433
434 pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
435 dst, size);
436 return PJ_SUCCESS;
437
438 } else {
439 pj_assert(!"Unsupport address family");
440 return PJ_EINVAL;
441 }
442
443}
444
445/*
Benny Prijonof260e462007-04-30 21:03:32 +0000446 * Get hostname.
447 */
448PJ_DEF(const pj_str_t*) pj_gethostname(void)
449{
450 static char buf[PJ_MAX_HOSTNAME];
451 static pj_str_t hostname;
452
453 PJ_CHECK_STACK();
454
455 if (hostname.ptr == NULL) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000456 RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(PJ_AF_INET);
Benny Prijonof260e462007-04-30 21:03:32 +0000457 TRequestStatus reqStatus;
458 THostName tmpName;
459
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000460 // Return empty hostname if access point is marked as down by app.
461 PJ_SYMBIAN_CHECK_CONNECTION2(&hostname);
462
Benny Prijonof260e462007-04-30 21:03:32 +0000463 resv.GetHostName(tmpName, reqStatus);
464 User::WaitForRequest(reqStatus);
465
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000466 hostname.ptr = pj_unicode_to_ansi((const wchar_t*)tmpName.Ptr(), tmpName.Length(),
Benny Prijonof260e462007-04-30 21:03:32 +0000467 buf, sizeof(buf));
468 hostname.slen = tmpName.Length();
469 }
470 return &hostname;
471}
472
473/*
Benny Prijonof260e462007-04-30 21:03:32 +0000474 * Create new socket/endpoint for communication and returns a descriptor.
475 */
476PJ_DEF(pj_status_t) pj_sock_socket(int af,
477 int type,
478 int proto,
479 pj_sock_t *p_sock)
480{
481 TInt rc;
482
483 PJ_CHECK_STACK();
484
485 /* Sanity checks. */
486 PJ_ASSERT_RETURN(p_sock!=NULL, PJ_EINVAL);
487
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000488 // Return failure if access point is marked as down by app.
489 PJ_SYMBIAN_CHECK_CONNECTION();
490
Benny Prijonof260e462007-04-30 21:03:32 +0000491 /* Set proto if none is specified. */
492 if (proto == 0) {
Benny Prijono8ab968f2007-07-20 08:08:30 +0000493 if (type == pj_SOCK_STREAM())
Benny Prijonof260e462007-04-30 21:03:32 +0000494 proto = KProtocolInetTcp;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000495 else if (type == pj_SOCK_DGRAM())
Benny Prijonof260e462007-04-30 21:03:32 +0000496 proto = KProtocolInetUdp;
497 }
498
499 /* Create Symbian RSocket */
500 RSocket rSock;
Benny Prijono7d3e12c2007-10-26 05:25:35 +0000501 if (PjSymbianOS::Instance()->Connection())
502 rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(),
503 af, type, proto,
504 *PjSymbianOS::Instance()->Connection());
505 else
506 rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(),
507 af, type, proto);
508
Benny Prijonof260e462007-04-30 21:03:32 +0000509 if (rc != KErrNone)
510 return PJ_RETURN_OS_ERROR(rc);
511
512
513 /* Wrap Symbian RSocket into PJLIB's CPjSocket, and return to caller */
Benny Prijonod77e07b2009-06-17 13:31:13 +0000514 CPjSocket *pjSock = new CPjSocket(af, type, rSock);
Benny Prijonof260e462007-04-30 21:03:32 +0000515 *p_sock = (pj_sock_t)pjSock;
516
517 return PJ_SUCCESS;
518}
519
520
521/*
522 * Bind socket.
523 */
524PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
525 const pj_sockaddr_t *addr,
526 int len)
527{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000528 pj_status_t status;
Benny Prijonof260e462007-04-30 21:03:32 +0000529 TInt rc;
530
531 PJ_CHECK_STACK();
532
533 PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
Benny Prijono80025db2007-12-02 15:36:46 +0000534 PJ_ASSERT_RETURN(addr && len>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000535
Benny Prijono62b86eb2007-12-01 08:52:57 +0000536 // Convert PJLIB's pj_sockaddr into Symbian's TInetAddr
Benny Prijonof260e462007-04-30 21:03:32 +0000537 TInetAddr inetAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000538 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, len, inetAddr);
539 if (status != PJ_SUCCESS)
540 return status;
Benny Prijonof260e462007-04-30 21:03:32 +0000541
542 // Get the RSocket instance
543 RSocket &rSock = ((CPjSocket*)sock)->Socket();
544
545 // Bind
546 rc = rSock.Bind(inetAddr);
547
548 return (rc==KErrNone) ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
549}
550
551
552/*
553 * Bind socket.
554 */
555PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
556 pj_uint32_t addr32,
557 pj_uint16_t port)
558{
559 pj_sockaddr_in addr;
560
561 PJ_CHECK_STACK();
562
Benny Prijonob2c96822007-05-03 13:31:21 +0000563 pj_bzero(&addr, sizeof(addr));
Benny Prijonof260e462007-04-30 21:03:32 +0000564 addr.sin_family = PJ_AF_INET;
565 addr.sin_addr.s_addr = pj_htonl(addr32);
566 addr.sin_port = pj_htons(port);
567
568 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
569}
570
571
572/*
573 * Close socket.
574 */
575PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
576{
577 PJ_CHECK_STACK();
578
579 PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
580
581 CPjSocket *pjSock = (CPjSocket*)sock;
582
583 // This will close the socket.
584 delete pjSock;
585
586 return PJ_SUCCESS;
587}
588
589/*
590 * Get remote's name.
591 */
592PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
593 pj_sockaddr_t *addr,
594 int *namelen)
595{
596 PJ_CHECK_STACK();
597
598 PJ_ASSERT_RETURN(sock && addr && namelen &&
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000599 *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000600
601 CPjSocket *pjSock = (CPjSocket*)sock;
602 RSocket &rSock = pjSock->Socket();
603
604 // Socket must be connected.
605 PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
606
607 TInetAddr inetAddr;
608 rSock.RemoteName(inetAddr);
609
Benny Prijono62b86eb2007-12-01 08:52:57 +0000610 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
Benny Prijonof260e462007-04-30 21:03:32 +0000611}
612
613/*
614 * Get socket name.
615 */
616PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
617 pj_sockaddr_t *addr,
618 int *namelen)
619{
620 PJ_CHECK_STACK();
621
622 PJ_ASSERT_RETURN(sock && addr && namelen &&
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000623 *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000624
625 CPjSocket *pjSock = (CPjSocket*)sock;
626 RSocket &rSock = pjSock->Socket();
627
628 TInetAddr inetAddr;
629 rSock.LocalName(inetAddr);
630
Benny Prijono62b86eb2007-12-01 08:52:57 +0000631 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
Benny Prijonof260e462007-04-30 21:03:32 +0000632}
633
634/*
635 * Send data
636 */
637PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
638 const void *buf,
639 pj_ssize_t *len,
640 unsigned flags)
641{
642 PJ_CHECK_STACK();
643 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
644
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000645 // Return failure if access point is marked as down by app.
646 PJ_SYMBIAN_CHECK_CONNECTION();
647
Benny Prijonof260e462007-04-30 21:03:32 +0000648 CPjSocket *pjSock = (CPjSocket*)sock;
649 RSocket &rSock = pjSock->Socket();
650
651 // send() should only be called to connected socket
652 PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
653
654 TPtrC8 data((const TUint8*)buf, (TInt)*len);
655 TRequestStatus reqStatus;
656 TSockXfrLength sentLen;
657
658 rSock.Send(data, flags, reqStatus, sentLen);
659 User::WaitForRequest(reqStatus);
660
661 if (reqStatus.Int()==KErrNone) {
662 //*len = (TInt) sentLen.Length();
663 return PJ_SUCCESS;
664 } else
665 return PJ_RETURN_OS_ERROR(reqStatus.Int());
666}
667
668
669/*
670 * Send data.
671 */
672PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
673 const void *buf,
674 pj_ssize_t *len,
675 unsigned flags,
676 const pj_sockaddr_t *to,
677 int tolen)
678{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000679 pj_status_t status;
680
Benny Prijonof260e462007-04-30 21:03:32 +0000681 PJ_CHECK_STACK();
682 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
683
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000684 // Return failure if access point is marked as down by app.
685 PJ_SYMBIAN_CHECK_CONNECTION();
686
Benny Prijonof260e462007-04-30 21:03:32 +0000687 CPjSocket *pjSock = (CPjSocket*)sock;
688 RSocket &rSock = pjSock->Socket();
689
690 // Only supports AF_INET for now
Benny Prijono80025db2007-12-02 15:36:46 +0000691 PJ_ASSERT_RETURN(tolen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000692
693 TInetAddr inetAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000694 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)to, tolen, inetAddr);
695 if (status != PJ_SUCCESS)
696 return status;
Benny Prijonof260e462007-04-30 21:03:32 +0000697
698 TPtrC8 data((const TUint8*)buf, (TInt)*len);
699 TRequestStatus reqStatus;
700 TSockXfrLength sentLen;
701
702 rSock.SendTo(data, inetAddr, flags, reqStatus, sentLen);
703 User::WaitForRequest(reqStatus);
704
705 if (reqStatus.Int()==KErrNone) {
706 //For some reason TSockXfrLength is not returning correctly!
707 //*len = (TInt) sentLen.Length();
708 return PJ_SUCCESS;
709 } else
710 return PJ_RETURN_OS_ERROR(reqStatus.Int());
711}
712
713/*
714 * Receive data.
715 */
716PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
717 void *buf,
718 pj_ssize_t *len,
719 unsigned flags)
720{
721 PJ_CHECK_STACK();
722
723 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
724 PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
725
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000726 // Return failure if access point is marked as down by app.
727 PJ_SYMBIAN_CHECK_CONNECTION();
728
Benny Prijonof260e462007-04-30 21:03:32 +0000729 CPjSocket *pjSock = (CPjSocket*)sock;
Benny Prijonof260e462007-04-30 21:03:32 +0000730
731 if (pjSock->Reader()) {
732 CPjSocketReader *reader = pjSock->Reader();
733
734 while (reader->IsActive() && !reader->HasData()) {
735 User::WaitForAnyRequest();
736 }
737
738 if (reader->HasData()) {
739 TPtr8 data((TUint8*)buf, (TInt)*len);
740 TInetAddr inetAddr;
741
742 reader->ReadData(data, &inetAddr);
743
744 *len = data.Length();
745 return PJ_SUCCESS;
746 }
747 }
748
749 TRequestStatus reqStatus;
750 TSockXfrLength recvLen;
751 TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
752
Benny Prijonod77e07b2009-06-17 13:31:13 +0000753 if (pjSock->IsDatagram()) {
754 pjSock->Socket().Recv(data, flags, reqStatus);
755 } else {
756 // Using static like this is not pretty, but we don't need to use
757 // the value anyway, hence doing it like this is probably most
758 // optimal.
759 static TSockXfrLength len;
760 pjSock->Socket().RecvOneOrMore(data, flags, reqStatus, len);
761 }
Benny Prijonof260e462007-04-30 21:03:32 +0000762 User::WaitForRequest(reqStatus);
763
764 if (reqStatus == KErrNone) {
765 //*len = (TInt)recvLen.Length();
766 *len = data.Length();
767 return PJ_SUCCESS;
768 } else {
769 *len = -1;
770 return PJ_RETURN_OS_ERROR(reqStatus.Int());
771 }
772}
773
774/*
775 * Receive data.
776 */
777PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
778 void *buf,
779 pj_ssize_t *len,
780 unsigned flags,
781 pj_sockaddr_t *from,
782 int *fromlen)
783{
784 PJ_CHECK_STACK();
785
786 PJ_ASSERT_RETURN(sock && buf && len && from && fromlen, PJ_EINVAL);
787 PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000788 PJ_ASSERT_RETURN(*fromlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000789
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000790 // Return failure if access point is marked as down by app.
791 PJ_SYMBIAN_CHECK_CONNECTION();
792
Benny Prijonof260e462007-04-30 21:03:32 +0000793 CPjSocket *pjSock = (CPjSocket*)sock;
794 RSocket &rSock = pjSock->Socket();
795
796 if (pjSock->Reader()) {
797 CPjSocketReader *reader = pjSock->Reader();
798
799 while (reader->IsActive() && !reader->HasData()) {
800 User::WaitForAnyRequest();
801 }
802
803 if (reader->HasData()) {
804 TPtr8 data((TUint8*)buf, (TInt)*len);
805 TInetAddr inetAddr;
806
807 reader->ReadData(data, &inetAddr);
808
809 *len = data.Length();
810
811 if (from && fromlen) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000812 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from,
813 fromlen);
814 } else {
815 return PJ_SUCCESS;
Benny Prijonof260e462007-04-30 21:03:32 +0000816 }
Benny Prijonof260e462007-04-30 21:03:32 +0000817 }
818 }
819
820 TInetAddr inetAddr;
821 TRequestStatus reqStatus;
822 TSockXfrLength recvLen;
823 TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
824
825 rSock.RecvFrom(data, inetAddr, flags, reqStatus, recvLen);
826 User::WaitForRequest(reqStatus);
827
828 if (reqStatus == KErrNone) {
829 //*len = (TInt)recvLen.Length();
830 *len = data.Length();
Benny Prijono62b86eb2007-12-01 08:52:57 +0000831 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, fromlen);
Benny Prijonof260e462007-04-30 21:03:32 +0000832 } else {
833 *len = -1;
834 *fromlen = -1;
835 return PJ_RETURN_OS_ERROR(reqStatus.Int());
836 }
837}
838
839/*
840 * Get socket option.
841 */
842PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
843 pj_uint16_t level,
844 pj_uint16_t optname,
845 void *optval,
846 int *optlen)
847{
848 // Not supported for now.
849 PJ_UNUSED_ARG(sock);
850 PJ_UNUSED_ARG(level);
851 PJ_UNUSED_ARG(optname);
852 PJ_UNUSED_ARG(optval);
853 PJ_UNUSED_ARG(optlen);
854 return PJ_EINVALIDOP;
855}
856
857/*
858 * Set socket option.
859 */
860PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
861 pj_uint16_t level,
862 pj_uint16_t optname,
863 const void *optval,
864 int optlen)
865{
866 // Not supported for now.
867 PJ_UNUSED_ARG(sock);
868 PJ_UNUSED_ARG(level);
869 PJ_UNUSED_ARG(optname);
870 PJ_UNUSED_ARG(optval);
871 PJ_UNUSED_ARG(optlen);
872 return PJ_EINVALIDOP;
873}
874
875/*
876 * Connect socket.
877 */
878PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
879 const pj_sockaddr_t *addr,
880 int namelen)
881{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000882 pj_status_t status;
883
Benny Prijonof260e462007-04-30 21:03:32 +0000884 PJ_CHECK_STACK();
885
886 PJ_ASSERT_RETURN(sock && addr && namelen, PJ_EINVAL);
887 PJ_ASSERT_RETURN(((pj_sockaddr*)addr)->addr.sa_family == PJ_AF_INET,
888 PJ_EINVAL);
889
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000890 // Return failure if access point is marked as down by app.
891 PJ_SYMBIAN_CHECK_CONNECTION();
892
Benny Prijonof260e462007-04-30 21:03:32 +0000893 CPjSocket *pjSock = (CPjSocket*)sock;
894 RSocket &rSock = pjSock->Socket();
895
896 TInetAddr inetAddr;
897 TRequestStatus reqStatus;
898
Benny Prijono62b86eb2007-12-01 08:52:57 +0000899 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, namelen, inetAddr);
900 if (status != PJ_SUCCESS)
901 return status;
Benny Prijonof260e462007-04-30 21:03:32 +0000902
903 rSock.Connect(inetAddr, reqStatus);
904 User::WaitForRequest(reqStatus);
905
906 if (reqStatus == KErrNone) {
907 pjSock->SetConnected(true);
908 return PJ_SUCCESS;
909 } else {
910 return PJ_RETURN_OS_ERROR(reqStatus.Int());
911 }
912}
913
914
915/*
916 * Shutdown socket.
917 */
918#if PJ_HAS_TCP
919PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
920 int how)
921{
922 PJ_CHECK_STACK();
923
924 PJ_ASSERT_RETURN(sock, PJ_EINVAL);
925
926 CPjSocket *pjSock = (CPjSocket*)sock;
927 RSocket &rSock = pjSock->Socket();
928
929 RSocket::TShutdown aHow;
930 if (how == PJ_SD_RECEIVE)
931 aHow = RSocket::EStopInput;
932 else if (how == PJ_SHUT_WR)
933 aHow = RSocket::EStopOutput;
934 else
935 aHow = RSocket::ENormal;
936
937 TRequestStatus reqStatus;
938
939 rSock.Shutdown(aHow, reqStatus);
940 User::WaitForRequest(reqStatus);
941
942 if (reqStatus == KErrNone) {
943 return PJ_SUCCESS;
944 } else {
945 return PJ_RETURN_OS_ERROR(reqStatus.Int());
946 }
947}
948
949/*
950 * Start listening to incoming connections.
951 */
952PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
953 int backlog)
954{
955 PJ_CHECK_STACK();
956
957 PJ_ASSERT_RETURN(sock && backlog, PJ_EINVAL);
958
959 CPjSocket *pjSock = (CPjSocket*)sock;
960 RSocket &rSock = pjSock->Socket();
961
962 TInt rc = rSock.Listen((TUint)backlog);
963
964 if (rc == KErrNone) {
965 return PJ_SUCCESS;
966 } else {
967 return PJ_RETURN_OS_ERROR(rc);
968 }
969}
970
971/*
972 * Accept incoming connections
973 */
974PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
975 pj_sock_t *newsock,
976 pj_sockaddr_t *addr,
977 int *addrlen)
978{
979 PJ_CHECK_STACK();
980
981 PJ_ASSERT_RETURN(serverfd && newsock, PJ_EINVAL);
982
983 CPjSocket *pjSock = (CPjSocket*)serverfd;
984 RSocket &rSock = pjSock->Socket();
985
986 // Create a 'blank' socket
987 RSocket newSock;
988 newSock.Open(PjSymbianOS::Instance()->SocketServ());
989
990 // Call Accept()
991 TRequestStatus reqStatus;
992
993 rSock.Accept(newSock, reqStatus);
994 User::WaitForRequest(reqStatus);
995
996 if (reqStatus != KErrNone) {
997 return PJ_RETURN_OS_ERROR(reqStatus.Int());
998 }
999
1000 // Create PJ socket
Benny Prijonod77e07b2009-06-17 13:31:13 +00001001 CPjSocket *newPjSock = new CPjSocket(pjSock->GetAf(), pjSock->GetSockType(),
1002 newSock);
Benny Prijonof260e462007-04-30 21:03:32 +00001003 newPjSock->SetConnected(true);
1004
1005 *newsock = (pj_sock_t) newPjSock;
1006
1007 if (addr && addrlen) {
1008 return pj_sock_getpeername(*newsock, addr, addrlen);
1009 }
1010
1011 return PJ_SUCCESS;
1012}
1013#endif /* PJ_HAS_TCP */
1014
1015