blob: 138ee867fcf5c6ab5646fee24ab81acafd71d69c [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
Benny Prijonodb04cd52009-10-15 03:48:20 +000050/* we don't support setsockopt(), these are just dummy values */
Benny Prijonof260e462007-04-30 21:03:32 +000051const 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 Prijonodb04cd52009-10-15 03:48:20 +000064/* Misc */
65const pj_uint16_t PJ_TCP_NODELAY = 0xFFFF;
66const pj_uint16_t PJ_SO_REUSEADDR = 0xFFFF;
67
Benny Prijonof260e462007-04-30 21:03:32 +000068/* ioctl() is also not supported. */
69const pj_uint16_t PJ_SO_TYPE = 0xFFFF;
70const pj_uint16_t PJ_SO_RCVBUF = 0xFFFF;
71const pj_uint16_t PJ_SO_SNDBUF = 0xFFFF;
72
Nanang Izzuddinb76154e2008-09-16 16:11:44 +000073/* IP multicast is also not supported. */
Benny Prijono513d1352008-09-27 09:35:34 +000074const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
75const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
76const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
77const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
78const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
Nanang Izzuddinb76154e2008-09-16 16:11:44 +000079
Benny Prijono8ab968f2007-07-20 08:08:30 +000080/* Flags */
81const int PJ_MSG_OOB = 0;
82const int PJ_MSG_PEEK = KSockReadPeek;
83const int PJ_MSG_DONTROUTE = 0;
Benny Prijonof260e462007-04-30 21:03:32 +000084
85/////////////////////////////////////////////////////////////////////////////
86//
87// CPjSocket implementation.
88// (declaration is in os_symbian.h)
89//
90
91CPjSocket::~CPjSocket()
92{
Benny Prijono897f9f82007-05-03 19:56:21 +000093 DestroyReader();
Benny Prijonof260e462007-04-30 21:03:32 +000094 sock_.Close();
95}
96
97
98// Create socket reader.
99CPjSocketReader *CPjSocket::CreateReader(unsigned max_len)
100{
101 pj_assert(sockReader_ == NULL);
102 return sockReader_ = CPjSocketReader::NewL(*this, max_len);
103}
104
Benny Prijono897f9f82007-05-03 19:56:21 +0000105// Delete socket reader when it's not wanted.
106void CPjSocket::DestroyReader()
107{
108 if (sockReader_) {
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000109 sockReader_->Cancel();
Benny Prijono897f9f82007-05-03 19:56:21 +0000110 delete sockReader_;
111 sockReader_ = NULL;
112 }
113}
114
Benny Prijonof260e462007-04-30 21:03:32 +0000115
116/////////////////////////////////////////////////////////////////////////////
117//
118// CPjSocketReader implementation
119// (declaration in os_symbian.h)
120//
121
122
123CPjSocketReader::CPjSocketReader(CPjSocket &sock)
124: CActive(EPriorityStandard),
125 sock_(sock), buffer_(NULL, 0), readCb_(NULL), key_(NULL)
126{
127}
128
129
130void CPjSocketReader::ConstructL(unsigned max_len)
131{
Benny Prijonod77e07b2009-06-17 13:31:13 +0000132 isDatagram_ = sock_.IsDatagram();
Benny Prijonof260e462007-04-30 21:03:32 +0000133
134 TUint8 *ptr = new TUint8[max_len];
135 buffer_.Set(ptr, 0, (TInt)max_len);
136 CActiveScheduler::Add(this);
137}
138
139CPjSocketReader *CPjSocketReader::NewL(CPjSocket &sock, unsigned max_len)
140{
141 CPjSocketReader *self = new (ELeave) CPjSocketReader(sock);
142 CleanupStack::PushL(self);
143 self->ConstructL(max_len);
144 CleanupStack::Pop(self);
145
146 return self;
147}
148
149
150CPjSocketReader::~CPjSocketReader()
151{
152 const TUint8 *data = buffer_.Ptr();
153 delete [] data;
154}
155
156void CPjSocketReader::StartRecv(void (*cb)(void *key),
157 void *key,
158 TDes8 *aDesc,
159 TUint flags)
160{
161 StartRecvFrom(cb, key, aDesc, flags, NULL);
162}
163
164void CPjSocketReader::StartRecvFrom(void (*cb)(void *key),
165 void *key,
166 TDes8 *aDesc,
167 TUint flags,
168 TSockAddr *fromAddr)
169{
170 readCb_ = cb;
171 key_ = key;
172
173 if (aDesc == NULL) aDesc = &buffer_;
174 if (fromAddr == NULL) fromAddr = &recvAddr_;
175
176 sock_.Socket().RecvFrom(*aDesc, *fromAddr, flags, iStatus);
Benny Prijono5d542642007-05-02 18:54:19 +0000177 SetActive();
Benny Prijonof260e462007-04-30 21:03:32 +0000178}
179
180void CPjSocketReader::DoCancel()
181{
182 sock_.Socket().CancelRecv();
183}
184
185void CPjSocketReader::RunL()
186{
187 void (*old_cb)(void *key) = readCb_;
188 void *old_key = key_;
Benny Prijonof260e462007-04-30 21:03:32 +0000189
190 readCb_ = NULL;
191 key_ = NULL;
192
193 if (old_cb) {
194 (*old_cb)(old_key);
195 }
196}
197
198// Append data to aDesc, up to aDesc's maximum size.
199// If socket is datagram based, buffer_ will be clared.
200void CPjSocketReader::ReadData(TDes8 &aDesc, TInetAddr *addr)
201{
202 if (isDatagram_)
203 aDesc.Zero();
204
205 if (buffer_.Length() == 0)
206 return;
207
208 TInt size_to_copy = aDesc.MaxLength() - aDesc.Length();
209 if (size_to_copy > buffer_.Length())
210 size_to_copy = buffer_.Length();
211
212 aDesc.Append(buffer_.Ptr(), size_to_copy);
213
214 if (isDatagram_)
215 buffer_.Zero();
216 else
217 buffer_.Delete(0, size_to_copy);
218
219 if (addr)
220 *addr = recvAddr_;
221}
222
223
224
225/////////////////////////////////////////////////////////////////////////////
226//
227// PJLIB's sock.h implementation
228//
229
230/*
231 * Convert 16-bit value from network byte order to host byte order.
232 */
233PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
234{
Benny Prijonob2c96822007-05-03 13:31:21 +0000235#if PJ_IS_LITTLE_ENDIAN
236 return pj_swap16(netshort);
237#else
Benny Prijonof260e462007-04-30 21:03:32 +0000238 return netshort;
Benny Prijonob2c96822007-05-03 13:31:21 +0000239#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000240}
241
242/*
243 * Convert 16-bit value from host byte order to network byte order.
244 */
245PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
246{
Benny Prijonob2c96822007-05-03 13:31:21 +0000247#if PJ_IS_LITTLE_ENDIAN
248 return pj_swap16(hostshort);
249#else
Benny Prijonof260e462007-04-30 21:03:32 +0000250 return hostshort;
Benny Prijonob2c96822007-05-03 13:31:21 +0000251#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000252}
253
254/*
255 * Convert 32-bit value from network byte order to host byte order.
256 */
257PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
258{
Benny Prijonob2c96822007-05-03 13:31:21 +0000259#if PJ_IS_LITTLE_ENDIAN
260 return pj_swap32(netlong);
261#else
Benny Prijonof260e462007-04-30 21:03:32 +0000262 return netlong;
Benny Prijonob2c96822007-05-03 13:31:21 +0000263#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000264}
265
266/*
267 * Convert 32-bit value from host byte order to network byte order.
268 */
269PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
270{
Benny Prijonob2c96822007-05-03 13:31:21 +0000271#if PJ_IS_LITTLE_ENDIAN
272 return pj_swap32(hostlong);
273#else
274 return netlong;
275#endif
Benny Prijonof260e462007-04-30 21:03:32 +0000276}
277
278/*
279 * Convert an Internet host address given in network byte order
280 * to string in standard numbers and dots notation.
281 */
282PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
283{
Benny Prijonocd700b12008-01-02 08:22:38 +0000284 static char str8[PJ_INET_ADDRSTRLEN];
285 TBuf<PJ_INET_ADDRSTRLEN> str16(0);
Benny Prijonof260e462007-04-30 21:03:32 +0000286
Benny Prijonob2c96822007-05-03 13:31:21 +0000287 /* (Symbian IP address is in host byte order) */
288 TInetAddr temp_addr((TUint32)pj_ntohl(inaddr.s_addr), (TUint)0);
Benny Prijonof260e462007-04-30 21:03:32 +0000289 temp_addr.Output(str16);
290
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000291 return pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
Benny Prijonof260e462007-04-30 21:03:32 +0000292 str8, sizeof(str8));
293}
294
295/*
296 * This function converts the Internet host address cp from the standard
297 * numbers-and-dots notation into binary data and stores it in the structure
298 * that inp points to.
299 */
300PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
301{
Benny Prijonocd700b12008-01-02 08:22:38 +0000302 enum { MAXIPLEN = PJ_INET_ADDRSTRLEN };
Benny Prijonof260e462007-04-30 21:03:32 +0000303
304 /* Initialize output with PJ_INADDR_NONE.
305 * Some apps relies on this instead of the return value
306 * (and anyway the return value is quite confusing!)
307 */
308 inp->s_addr = PJ_INADDR_NONE;
309
310 /* Caution:
311 * this function might be called with cp->slen >= 16
312 * (i.e. when called with hostname to check if it's an IP addr).
313 */
314 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
315 if (cp->slen >= 16) {
316 return 0;
317 }
318
319 char tempaddr8[MAXIPLEN];
320 pj_memcpy(tempaddr8, cp->ptr, cp->slen);
321 tempaddr8[cp->slen] = '\0';
322
323 wchar_t tempaddr16[MAXIPLEN];
324 pj_ansi_to_unicode(tempaddr8, pj_ansi_strlen(tempaddr8),
325 tempaddr16, sizeof(tempaddr16));
326
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000327 TBuf<MAXIPLEN> ip_addr((const TText*)tempaddr16);
Benny Prijonof260e462007-04-30 21:03:32 +0000328
329 TInetAddr addr;
330 addr.Init(KAfInet);
331 if (addr.Input(ip_addr) == KErrNone) {
Benny Prijonob2c96822007-05-03 13:31:21 +0000332 /* Success (Symbian IP address is in host byte order) */
333 inp->s_addr = pj_htonl(addr.Address());
Benny Prijonof260e462007-04-30 21:03:32 +0000334 return 1;
335 } else {
336 /* Error */
337 return 0;
338 }
339}
340
341/*
Benny Prijono2a78a522007-11-21 14:10:46 +0000342 * Convert text to IPv4/IPv6 address.
343 */
344PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
345{
346 char tempaddr[PJ_INET6_ADDRSTRLEN];
347
348 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
349 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
350
351 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
352 * compatible with pj_inet_aton()
353 */
354 if (af==PJ_AF_INET) {
355 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
356 }
357
358 /* Caution:
359 * this function might be called with cp->slen >= 46
360 * (i.e. when called with hostname to check if it's an IP addr).
361 */
362 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
363 return PJ_ENAMETOOLONG;
364 }
365
366 pj_memcpy(tempaddr, src->ptr, src->slen);
367 tempaddr[src->slen] = '\0';
368
369
370 wchar_t tempaddr16[PJ_INET6_ADDRSTRLEN];
371 pj_ansi_to_unicode(tempaddr, pj_ansi_strlen(tempaddr),
372 tempaddr16, sizeof(tempaddr16));
373
374 TBuf<PJ_INET6_ADDRSTRLEN> ip_addr((const TText*)tempaddr16);
375
376 TInetAddr addr;
377 addr.Init(KAfInet6);
378 if (addr.Input(ip_addr) == KErrNone) {
379 if (af==PJ_AF_INET) {
380 /* Success (Symbian IP address is in host byte order) */
381 pj_uint32_t ip = pj_htonl(addr.Address());
382 pj_memcpy(dst, &ip, 4);
383 } else if (af==PJ_AF_INET6) {
384 const TIp6Addr & ip6 = addr.Ip6Address();
385 pj_memcpy(dst, ip6.u.iAddr8, 16);
386 } else {
387 pj_assert(!"Unexpected!");
388 return PJ_EBUG;
389 }
390 return PJ_SUCCESS;
391 } else {
392 /* Error */
393 return PJ_EINVAL;
394 }
395}
396
397/*
398 * Convert IPv4/IPv6 address to text.
399 */
400PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
401 char *dst, int size)
402
403{
404 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
405
406 *dst = '\0';
407
408 if (af==PJ_AF_INET) {
409
410 TBuf<PJ_INET_ADDRSTRLEN> str16;
411 pj_in_addr inaddr;
412
Benny Prijono9db4bd62007-12-31 11:26:21 +0000413 if (size < PJ_INET_ADDRSTRLEN)
Benny Prijono2a78a522007-11-21 14:10:46 +0000414 return PJ_ETOOSMALL;
415
416 pj_memcpy(&inaddr, src, 4);
417
418 /* Symbian IP address is in host byte order */
419 TInetAddr temp_addr((TUint32)pj_ntohl(inaddr.s_addr), (TUint)0);
420 temp_addr.Output(str16);
421
422 pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
423 dst, size);
424 return PJ_SUCCESS;
425
426 } else if (af==PJ_AF_INET6) {
427 TBuf<PJ_INET6_ADDRSTRLEN> str16;
428
Benny Prijono9db4bd62007-12-31 11:26:21 +0000429 if (size < PJ_INET6_ADDRSTRLEN)
Benny Prijono2a78a522007-11-21 14:10:46 +0000430 return PJ_ETOOSMALL;
431
432 TIp6Addr ip6;
433 pj_memcpy(ip6.u.iAddr8, src, 16);
434
435 TInetAddr temp_addr(ip6, (TUint)0);
436 temp_addr.Output(str16);
437
438 pj_unicode_to_ansi((const wchar_t*)str16.PtrZ(), str16.Length(),
439 dst, size);
440 return PJ_SUCCESS;
441
442 } else {
443 pj_assert(!"Unsupport address family");
444 return PJ_EINVAL;
445 }
446
447}
448
449/*
Benny Prijonof260e462007-04-30 21:03:32 +0000450 * Get hostname.
451 */
452PJ_DEF(const pj_str_t*) pj_gethostname(void)
453{
454 static char buf[PJ_MAX_HOSTNAME];
455 static pj_str_t hostname;
456
457 PJ_CHECK_STACK();
458
459 if (hostname.ptr == NULL) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000460 RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(PJ_AF_INET);
Benny Prijonof260e462007-04-30 21:03:32 +0000461 TRequestStatus reqStatus;
462 THostName tmpName;
463
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000464 // Return empty hostname if access point is marked as down by app.
465 PJ_SYMBIAN_CHECK_CONNECTION2(&hostname);
466
Benny Prijonof260e462007-04-30 21:03:32 +0000467 resv.GetHostName(tmpName, reqStatus);
468 User::WaitForRequest(reqStatus);
469
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000470 hostname.ptr = pj_unicode_to_ansi((const wchar_t*)tmpName.Ptr(), tmpName.Length(),
Benny Prijonof260e462007-04-30 21:03:32 +0000471 buf, sizeof(buf));
472 hostname.slen = tmpName.Length();
473 }
474 return &hostname;
475}
476
477/*
Benny Prijonof260e462007-04-30 21:03:32 +0000478 * Create new socket/endpoint for communication and returns a descriptor.
479 */
480PJ_DEF(pj_status_t) pj_sock_socket(int af,
481 int type,
482 int proto,
483 pj_sock_t *p_sock)
484{
485 TInt rc;
486
487 PJ_CHECK_STACK();
488
489 /* Sanity checks. */
490 PJ_ASSERT_RETURN(p_sock!=NULL, PJ_EINVAL);
491
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000492 // Return failure if access point is marked as down by app.
493 PJ_SYMBIAN_CHECK_CONNECTION();
494
Benny Prijonof260e462007-04-30 21:03:32 +0000495 /* Set proto if none is specified. */
496 if (proto == 0) {
Benny Prijono8ab968f2007-07-20 08:08:30 +0000497 if (type == pj_SOCK_STREAM())
Benny Prijonof260e462007-04-30 21:03:32 +0000498 proto = KProtocolInetTcp;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000499 else if (type == pj_SOCK_DGRAM())
Benny Prijonof260e462007-04-30 21:03:32 +0000500 proto = KProtocolInetUdp;
501 }
502
503 /* Create Symbian RSocket */
504 RSocket rSock;
Benny Prijono7d3e12c2007-10-26 05:25:35 +0000505 if (PjSymbianOS::Instance()->Connection())
506 rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(),
507 af, type, proto,
508 *PjSymbianOS::Instance()->Connection());
509 else
510 rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(),
511 af, type, proto);
512
Benny Prijonof260e462007-04-30 21:03:32 +0000513 if (rc != KErrNone)
514 return PJ_RETURN_OS_ERROR(rc);
515
516
517 /* Wrap Symbian RSocket into PJLIB's CPjSocket, and return to caller */
Benny Prijonod77e07b2009-06-17 13:31:13 +0000518 CPjSocket *pjSock = new CPjSocket(af, type, rSock);
Benny Prijonof260e462007-04-30 21:03:32 +0000519 *p_sock = (pj_sock_t)pjSock;
520
521 return PJ_SUCCESS;
522}
523
524
525/*
526 * Bind socket.
527 */
528PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
529 const pj_sockaddr_t *addr,
530 int len)
531{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000532 pj_status_t status;
Benny Prijonof260e462007-04-30 21:03:32 +0000533 TInt rc;
534
535 PJ_CHECK_STACK();
536
537 PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
Benny Prijono80025db2007-12-02 15:36:46 +0000538 PJ_ASSERT_RETURN(addr && len>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000539
Benny Prijono62b86eb2007-12-01 08:52:57 +0000540 // Convert PJLIB's pj_sockaddr into Symbian's TInetAddr
Benny Prijonof260e462007-04-30 21:03:32 +0000541 TInetAddr inetAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000542 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, len, inetAddr);
543 if (status != PJ_SUCCESS)
544 return status;
Benny Prijonof260e462007-04-30 21:03:32 +0000545
546 // Get the RSocket instance
547 RSocket &rSock = ((CPjSocket*)sock)->Socket();
548
549 // Bind
550 rc = rSock.Bind(inetAddr);
551
552 return (rc==KErrNone) ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
553}
554
555
556/*
557 * Bind socket.
558 */
559PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
560 pj_uint32_t addr32,
561 pj_uint16_t port)
562{
563 pj_sockaddr_in addr;
564
565 PJ_CHECK_STACK();
566
Benny Prijonob2c96822007-05-03 13:31:21 +0000567 pj_bzero(&addr, sizeof(addr));
Benny Prijonof260e462007-04-30 21:03:32 +0000568 addr.sin_family = PJ_AF_INET;
569 addr.sin_addr.s_addr = pj_htonl(addr32);
570 addr.sin_port = pj_htons(port);
571
572 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
573}
574
575
576/*
577 * Close socket.
578 */
579PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
580{
581 PJ_CHECK_STACK();
582
583 PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
584
585 CPjSocket *pjSock = (CPjSocket*)sock;
586
587 // This will close the socket.
588 delete pjSock;
589
590 return PJ_SUCCESS;
591}
592
593/*
594 * Get remote's name.
595 */
596PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
597 pj_sockaddr_t *addr,
598 int *namelen)
599{
600 PJ_CHECK_STACK();
601
602 PJ_ASSERT_RETURN(sock && addr && namelen &&
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000603 *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000604
605 CPjSocket *pjSock = (CPjSocket*)sock;
606 RSocket &rSock = pjSock->Socket();
607
608 // Socket must be connected.
609 PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
610
611 TInetAddr inetAddr;
612 rSock.RemoteName(inetAddr);
613
Benny Prijono62b86eb2007-12-01 08:52:57 +0000614 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
Benny Prijonof260e462007-04-30 21:03:32 +0000615}
616
617/*
618 * Get socket name.
619 */
620PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
621 pj_sockaddr_t *addr,
622 int *namelen)
623{
624 PJ_CHECK_STACK();
625
626 PJ_ASSERT_RETURN(sock && addr && namelen &&
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000627 *namelen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000628
629 CPjSocket *pjSock = (CPjSocket*)sock;
630 RSocket &rSock = pjSock->Socket();
631
632 TInetAddr inetAddr;
633 rSock.LocalName(inetAddr);
634
Benny Prijono62b86eb2007-12-01 08:52:57 +0000635 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
Benny Prijonof260e462007-04-30 21:03:32 +0000636}
637
638/*
639 * Send data
640 */
641PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
642 const void *buf,
643 pj_ssize_t *len,
644 unsigned flags)
645{
646 PJ_CHECK_STACK();
647 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
648
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000649 // Return failure if access point is marked as down by app.
650 PJ_SYMBIAN_CHECK_CONNECTION();
651
Benny Prijonof260e462007-04-30 21:03:32 +0000652 CPjSocket *pjSock = (CPjSocket*)sock;
653 RSocket &rSock = pjSock->Socket();
654
655 // send() should only be called to connected socket
656 PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
657
658 TPtrC8 data((const TUint8*)buf, (TInt)*len);
659 TRequestStatus reqStatus;
660 TSockXfrLength sentLen;
661
662 rSock.Send(data, flags, reqStatus, sentLen);
663 User::WaitForRequest(reqStatus);
664
665 if (reqStatus.Int()==KErrNone) {
666 //*len = (TInt) sentLen.Length();
667 return PJ_SUCCESS;
668 } else
669 return PJ_RETURN_OS_ERROR(reqStatus.Int());
670}
671
672
673/*
674 * Send data.
675 */
676PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
677 const void *buf,
678 pj_ssize_t *len,
679 unsigned flags,
680 const pj_sockaddr_t *to,
681 int tolen)
682{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000683 pj_status_t status;
684
Benny Prijonof260e462007-04-30 21:03:32 +0000685 PJ_CHECK_STACK();
686 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
687
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000688 // Return failure if access point is marked as down by app.
689 PJ_SYMBIAN_CHECK_CONNECTION();
690
Benny Prijonof260e462007-04-30 21:03:32 +0000691 CPjSocket *pjSock = (CPjSocket*)sock;
692 RSocket &rSock = pjSock->Socket();
693
694 // Only supports AF_INET for now
Benny Prijono80025db2007-12-02 15:36:46 +0000695 PJ_ASSERT_RETURN(tolen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000696
697 TInetAddr inetAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000698 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)to, tolen, inetAddr);
699 if (status != PJ_SUCCESS)
700 return status;
Benny Prijonof260e462007-04-30 21:03:32 +0000701
702 TPtrC8 data((const TUint8*)buf, (TInt)*len);
703 TRequestStatus reqStatus;
704 TSockXfrLength sentLen;
705
706 rSock.SendTo(data, inetAddr, flags, reqStatus, sentLen);
707 User::WaitForRequest(reqStatus);
708
709 if (reqStatus.Int()==KErrNone) {
710 //For some reason TSockXfrLength is not returning correctly!
711 //*len = (TInt) sentLen.Length();
712 return PJ_SUCCESS;
713 } else
714 return PJ_RETURN_OS_ERROR(reqStatus.Int());
715}
716
717/*
718 * Receive data.
719 */
720PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
721 void *buf,
722 pj_ssize_t *len,
723 unsigned flags)
724{
725 PJ_CHECK_STACK();
726
727 PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
728 PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
729
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000730 // Return failure if access point is marked as down by app.
731 PJ_SYMBIAN_CHECK_CONNECTION();
732
Benny Prijonof260e462007-04-30 21:03:32 +0000733 CPjSocket *pjSock = (CPjSocket*)sock;
Benny Prijonof260e462007-04-30 21:03:32 +0000734
735 if (pjSock->Reader()) {
736 CPjSocketReader *reader = pjSock->Reader();
737
738 while (reader->IsActive() && !reader->HasData()) {
739 User::WaitForAnyRequest();
740 }
741
742 if (reader->HasData()) {
743 TPtr8 data((TUint8*)buf, (TInt)*len);
744 TInetAddr inetAddr;
745
746 reader->ReadData(data, &inetAddr);
747
748 *len = data.Length();
749 return PJ_SUCCESS;
750 }
751 }
752
753 TRequestStatus reqStatus;
754 TSockXfrLength recvLen;
755 TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
756
Benny Prijonod77e07b2009-06-17 13:31:13 +0000757 if (pjSock->IsDatagram()) {
758 pjSock->Socket().Recv(data, flags, reqStatus);
759 } else {
760 // Using static like this is not pretty, but we don't need to use
761 // the value anyway, hence doing it like this is probably most
762 // optimal.
763 static TSockXfrLength len;
764 pjSock->Socket().RecvOneOrMore(data, flags, reqStatus, len);
765 }
Benny Prijonof260e462007-04-30 21:03:32 +0000766 User::WaitForRequest(reqStatus);
767
768 if (reqStatus == KErrNone) {
769 //*len = (TInt)recvLen.Length();
770 *len = data.Length();
771 return PJ_SUCCESS;
772 } else {
773 *len = -1;
774 return PJ_RETURN_OS_ERROR(reqStatus.Int());
775 }
776}
777
778/*
779 * Receive data.
780 */
781PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
782 void *buf,
783 pj_ssize_t *len,
784 unsigned flags,
785 pj_sockaddr_t *from,
786 int *fromlen)
787{
788 PJ_CHECK_STACK();
789
790 PJ_ASSERT_RETURN(sock && buf && len && from && fromlen, PJ_EINVAL);
791 PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000792 PJ_ASSERT_RETURN(*fromlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijonof260e462007-04-30 21:03:32 +0000793
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000794 // Return failure if access point is marked as down by app.
795 PJ_SYMBIAN_CHECK_CONNECTION();
796
Benny Prijonof260e462007-04-30 21:03:32 +0000797 CPjSocket *pjSock = (CPjSocket*)sock;
798 RSocket &rSock = pjSock->Socket();
799
800 if (pjSock->Reader()) {
801 CPjSocketReader *reader = pjSock->Reader();
802
803 while (reader->IsActive() && !reader->HasData()) {
804 User::WaitForAnyRequest();
805 }
806
807 if (reader->HasData()) {
808 TPtr8 data((TUint8*)buf, (TInt)*len);
809 TInetAddr inetAddr;
810
811 reader->ReadData(data, &inetAddr);
812
813 *len = data.Length();
814
815 if (from && fromlen) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000816 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from,
817 fromlen);
818 } else {
819 return PJ_SUCCESS;
Benny Prijonof260e462007-04-30 21:03:32 +0000820 }
Benny Prijonof260e462007-04-30 21:03:32 +0000821 }
822 }
823
824 TInetAddr inetAddr;
825 TRequestStatus reqStatus;
826 TSockXfrLength recvLen;
827 TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
828
829 rSock.RecvFrom(data, inetAddr, flags, reqStatus, recvLen);
830 User::WaitForRequest(reqStatus);
831
832 if (reqStatus == KErrNone) {
833 //*len = (TInt)recvLen.Length();
834 *len = data.Length();
Benny Prijono62b86eb2007-12-01 08:52:57 +0000835 return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, fromlen);
Benny Prijonof260e462007-04-30 21:03:32 +0000836 } else {
837 *len = -1;
838 *fromlen = -1;
839 return PJ_RETURN_OS_ERROR(reqStatus.Int());
840 }
841}
842
843/*
844 * Get socket option.
845 */
846PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
847 pj_uint16_t level,
848 pj_uint16_t optname,
849 void *optval,
850 int *optlen)
851{
852 // Not supported for now.
853 PJ_UNUSED_ARG(sock);
854 PJ_UNUSED_ARG(level);
855 PJ_UNUSED_ARG(optname);
856 PJ_UNUSED_ARG(optval);
857 PJ_UNUSED_ARG(optlen);
858 return PJ_EINVALIDOP;
859}
860
861/*
862 * Set socket option.
863 */
864PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
865 pj_uint16_t level,
866 pj_uint16_t optname,
867 const void *optval,
868 int optlen)
869{
870 // Not supported for now.
871 PJ_UNUSED_ARG(sock);
872 PJ_UNUSED_ARG(level);
873 PJ_UNUSED_ARG(optname);
874 PJ_UNUSED_ARG(optval);
875 PJ_UNUSED_ARG(optlen);
876 return PJ_EINVALIDOP;
877}
878
879/*
880 * Connect socket.
881 */
882PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
883 const pj_sockaddr_t *addr,
884 int namelen)
885{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000886 pj_status_t status;
887
Benny Prijonof260e462007-04-30 21:03:32 +0000888 PJ_CHECK_STACK();
889
890 PJ_ASSERT_RETURN(sock && addr && namelen, PJ_EINVAL);
891 PJ_ASSERT_RETURN(((pj_sockaddr*)addr)->addr.sa_family == PJ_AF_INET,
892 PJ_EINVAL);
893
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000894 // Return failure if access point is marked as down by app.
895 PJ_SYMBIAN_CHECK_CONNECTION();
896
Benny Prijonof260e462007-04-30 21:03:32 +0000897 CPjSocket *pjSock = (CPjSocket*)sock;
898 RSocket &rSock = pjSock->Socket();
899
900 TInetAddr inetAddr;
901 TRequestStatus reqStatus;
902
Benny Prijono62b86eb2007-12-01 08:52:57 +0000903 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, namelen, inetAddr);
904 if (status != PJ_SUCCESS)
905 return status;
Benny Prijonof260e462007-04-30 21:03:32 +0000906
907 rSock.Connect(inetAddr, reqStatus);
908 User::WaitForRequest(reqStatus);
909
910 if (reqStatus == KErrNone) {
911 pjSock->SetConnected(true);
912 return PJ_SUCCESS;
913 } else {
914 return PJ_RETURN_OS_ERROR(reqStatus.Int());
915 }
916}
917
918
919/*
920 * Shutdown socket.
921 */
922#if PJ_HAS_TCP
923PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
924 int how)
925{
926 PJ_CHECK_STACK();
927
928 PJ_ASSERT_RETURN(sock, PJ_EINVAL);
929
930 CPjSocket *pjSock = (CPjSocket*)sock;
931 RSocket &rSock = pjSock->Socket();
932
933 RSocket::TShutdown aHow;
934 if (how == PJ_SD_RECEIVE)
935 aHow = RSocket::EStopInput;
936 else if (how == PJ_SHUT_WR)
937 aHow = RSocket::EStopOutput;
938 else
939 aHow = RSocket::ENormal;
940
941 TRequestStatus reqStatus;
942
943 rSock.Shutdown(aHow, reqStatus);
944 User::WaitForRequest(reqStatus);
945
946 if (reqStatus == KErrNone) {
947 return PJ_SUCCESS;
948 } else {
949 return PJ_RETURN_OS_ERROR(reqStatus.Int());
950 }
951}
952
953/*
954 * Start listening to incoming connections.
955 */
956PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
957 int backlog)
958{
959 PJ_CHECK_STACK();
960
961 PJ_ASSERT_RETURN(sock && backlog, PJ_EINVAL);
962
963 CPjSocket *pjSock = (CPjSocket*)sock;
964 RSocket &rSock = pjSock->Socket();
965
966 TInt rc = rSock.Listen((TUint)backlog);
967
968 if (rc == KErrNone) {
969 return PJ_SUCCESS;
970 } else {
971 return PJ_RETURN_OS_ERROR(rc);
972 }
973}
974
975/*
976 * Accept incoming connections
977 */
978PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
979 pj_sock_t *newsock,
980 pj_sockaddr_t *addr,
981 int *addrlen)
982{
983 PJ_CHECK_STACK();
984
985 PJ_ASSERT_RETURN(serverfd && newsock, PJ_EINVAL);
986
987 CPjSocket *pjSock = (CPjSocket*)serverfd;
988 RSocket &rSock = pjSock->Socket();
989
990 // Create a 'blank' socket
991 RSocket newSock;
992 newSock.Open(PjSymbianOS::Instance()->SocketServ());
993
994 // Call Accept()
995 TRequestStatus reqStatus;
996
997 rSock.Accept(newSock, reqStatus);
998 User::WaitForRequest(reqStatus);
999
1000 if (reqStatus != KErrNone) {
1001 return PJ_RETURN_OS_ERROR(reqStatus.Int());
1002 }
1003
1004 // Create PJ socket
Benny Prijonod77e07b2009-06-17 13:31:13 +00001005 CPjSocket *newPjSock = new CPjSocket(pjSock->GetAf(), pjSock->GetSockType(),
1006 newSock);
Benny Prijonof260e462007-04-30 21:03:32 +00001007 newPjSock->SetConnected(true);
1008
1009 *newsock = (pj_sock_t) newPjSock;
1010
1011 if (addr && addrlen) {
1012 return pj_sock_getpeername(*newsock, addr, addrlen);
1013 }
1014
1015 return PJ_SUCCESS;
1016}
1017#endif /* PJ_HAS_TCP */
1018
1019