blob: d8e3aeeb5e4173b165fdd6d486400c86b78c631d [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/ioqueue.h>
21#include <pj/assert.h>
22#include <pj/errno.h>
23#include <pj/list.h>
24#include <pj/lock.h>
25#include <pj/pool.h>
26#include <pj/string.h>
27
28#include "os_symbian.h"
29
30class CIoqueueCallback;
31
32/*
33 * IO Queue structure.
34 */
35struct pj_ioqueue_t
36{
37 int eventCount;
Benny Prijonof260e462007-04-30 21:03:32 +000038};
39
40
41/////////////////////////////////////////////////////////////////////////////
42// Class to encapsulate asynchronous socket operation.
43//
44class CIoqueueCallback : public CActive
45{
46public:
47 static CIoqueueCallback* NewL(pj_ioqueue_t *ioqueue,
48 pj_ioqueue_key_t *key,
49 pj_sock_t sock,
50 const pj_ioqueue_callback *cb,
51 void *user_data);
52
53 //
54 // Start asynchronous recv() operation
55 //
56 pj_status_t StartRead(pj_ioqueue_op_key_t *op_key,
57 void *buf, pj_ssize_t *size, unsigned flags,
58 pj_sockaddr_t *addr, int *addrlen);
59
60 //
61 // Start asynchronous accept() operation.
62 //
63 pj_status_t StartAccept(pj_ioqueue_op_key_t *op_key,
64 pj_sock_t *new_sock,
65 pj_sockaddr_t *local,
66 pj_sockaddr_t *remote,
67 int *addrlen );
68
69 //
70 // Completion callback.
71 //
72 void RunL();
73
74 //
75 // CActive's DoCancel()
76 //
77 void DoCancel();
78
79 //
80 // Cancel operation and call callback.
81 //
82 void CancelOperation(pj_ioqueue_op_key_t *op_key,
83 pj_ssize_t bytes_status);
84
85 //
86 // Accessors
87 //
88 void* get_user_data() const
89 {
90 return user_data_;
91 }
92 void set_user_data(void *user_data)
93 {
94 user_data_ = user_data;
95 }
96 pj_ioqueue_op_key_t *get_op_key() const
97 {
98 return pending_data_.common_.op_key_;
99 }
100 CPjSocket* get_pj_socket()
101 {
102 return sock_;
103 }
104
105private:
106 // Type of pending operation.
107 enum Type {
108 TYPE_NONE,
109 TYPE_READ,
110 TYPE_ACCEPT,
111 };
112
113 // Static data.
114 pj_ioqueue_t *ioqueue_;
115 pj_ioqueue_key_t *key_;
116 CPjSocket *sock_;
117 pj_ioqueue_callback cb_;
118 void *user_data_;
119
120 // Symbian data.
121 TPtr8 aBufferPtr_;
122 TInetAddr aAddress_;
123
124 // Application data.
125 Type type_;
126
127 union Pending_Data
128 {
129 struct Common
130 {
131 pj_ioqueue_op_key_t *op_key_;
132 } common_;
133
134 struct Pending_Read
135 {
136 pj_ioqueue_op_key_t *op_key_;
137 pj_sockaddr_t *addr_;
138 int *addrlen_;
139 } read_;
140
141 struct Pending_Accept
142 {
143 pj_ioqueue_op_key_t *op_key_;
144 pj_sock_t *new_sock_;
145 pj_sockaddr_t *local_;
146 pj_sockaddr_t *remote_;
147 int *addrlen_;
148 } accept_;
149 };
150
151 union Pending_Data pending_data_;
152 RSocket blank_sock_;
153
154 CIoqueueCallback(pj_ioqueue_t *ioqueue,
155 pj_ioqueue_key_t *key, pj_sock_t sock,
156 const pj_ioqueue_callback *cb, void *user_data)
157 : CActive(CActive::EPriorityStandard),
158 ioqueue_(ioqueue), key_(key), sock_((CPjSocket*)sock),
159 user_data_(user_data), aBufferPtr_(NULL, 0), type_(TYPE_NONE)
160 {
161 pj_memcpy(&cb_, cb, sizeof(*cb));
162 }
163
164
165 void ConstructL()
166 {
167 CActiveScheduler::Add(this);
168 }
169
170 void HandleReadCompletion();
171 CPjSocket *HandleAcceptCompletion();
172};
173
174
175CIoqueueCallback* CIoqueueCallback::NewL(pj_ioqueue_t *ioqueue,
176 pj_ioqueue_key_t *key,
177 pj_sock_t sock,
178 const pj_ioqueue_callback *cb,
179 void *user_data)
180{
181 CIoqueueCallback *self = new CIoqueueCallback(ioqueue, key, sock,
182 cb, user_data);
183 CleanupStack::PushL(self);
184 self->ConstructL();
185 CleanupStack::Pop(self);
186
187 return self;
188}
189
190
191//
192// Start asynchronous recv() operation
193//
194pj_status_t CIoqueueCallback::StartRead(pj_ioqueue_op_key_t *op_key,
195 void *buf, pj_ssize_t *size,
196 unsigned flags,
197 pj_sockaddr_t *addr, int *addrlen)
198{
199 PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
200 PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
201
202 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
203
204 pending_data_.read_.op_key_ = op_key;
205 pending_data_.read_.addr_ = addr;
206 pending_data_.read_.addrlen_ = addrlen;
207
208 aBufferPtr_.Set((TUint8*)buf, 0, (TInt)*size);
209
210 type_ = TYPE_READ;
211 if (addr && addrlen) {
212 sock_->Socket().RecvFrom(aBufferPtr_, aAddress_, flags, iStatus);
213 } else {
214 aAddress_.SetAddress(0);
215 aAddress_.SetPort(0);
Benny Prijonod77e07b2009-06-17 13:31:13 +0000216
217 if (sock_->IsDatagram()) {
218 sock_->Socket().Recv(aBufferPtr_, flags, iStatus);
219 } else {
220 // Using static like this is not pretty, but we don't need to use
221 // the value anyway, hence doing it like this is probably most
222 // optimal.
223 static TSockXfrLength len;
224 sock_->Socket().RecvOneOrMore(aBufferPtr_, flags, iStatus, len);
225 }
Benny Prijonof260e462007-04-30 21:03:32 +0000226 }
227
Benny Prijono5d542642007-05-02 18:54:19 +0000228 SetActive();
229 return PJ_EPENDING;
Benny Prijonof260e462007-04-30 21:03:32 +0000230}
231
232
233//
234// Start asynchronous accept() operation.
235//
236pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key,
237 pj_sock_t *new_sock,
238 pj_sockaddr_t *local,
239 pj_sockaddr_t *remote,
240 int *addrlen )
241{
242 PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
243 PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
244
Benny Prijono62b86eb2007-12-01 08:52:57 +0000245 // addrlen must be specified if local or remote is specified
246 PJ_ASSERT_RETURN((!local && !remote) ||
247 (addrlen && *addrlen), PJ_EINVAL);
248
Benny Prijonof260e462007-04-30 21:03:32 +0000249 pending_data_.accept_.op_key_ = op_key;
250 pending_data_.accept_.new_sock_ = new_sock;
251 pending_data_.accept_.local_ = local;
252 pending_data_.accept_.remote_ = remote;
253 pending_data_.accept_.addrlen_ = addrlen;
254
255 // Create blank socket
256 blank_sock_.Open(PjSymbianOS::Instance()->SocketServ());
257
258 type_ = TYPE_ACCEPT;
259 sock_->Socket().Accept(blank_sock_, iStatus);
260
Benny Prijono5d542642007-05-02 18:54:19 +0000261 SetActive();
262 return PJ_EPENDING;
Benny Prijonof260e462007-04-30 21:03:32 +0000263}
264
265
266//
267// Handle asynchronous RecvFrom() completion
268//
269void CIoqueueCallback::HandleReadCompletion()
270{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000271 if (pending_data_.read_.addr_ && pending_data_.read_.addrlen_) {
Benny Prijono5d542642007-05-02 18:54:19 +0000272 PjSymbianOS::Addr2pj(aAddress_,
Benny Prijono62b86eb2007-12-01 08:52:57 +0000273 *(pj_sockaddr*)pending_data_.read_.addr_,
274 pending_data_.read_.addrlen_);
Benny Prijono5d542642007-05-02 18:54:19 +0000275 pending_data_.read_.addr_ = NULL;
Benny Prijono5d542642007-05-02 18:54:19 +0000276 pending_data_.read_.addrlen_ = NULL;
277 }
Benny Prijonof260e462007-04-30 21:03:32 +0000278
Benny Prijono5d542642007-05-02 18:54:19 +0000279 pending_data_.read_.op_key_ = NULL;
Benny Prijonof260e462007-04-30 21:03:32 +0000280}
281
282
283//
284// Handle asynchronous Accept() completion.
285//
286CPjSocket *CIoqueueCallback::HandleAcceptCompletion()
287{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000288 CPjSocket *pjNewSock = new CPjSocket(get_pj_socket()->GetAf(),
Benny Prijonod77e07b2009-06-17 13:31:13 +0000289 get_pj_socket()->GetSockType(),
Benny Prijono62b86eb2007-12-01 08:52:57 +0000290 blank_sock_);
291 int addrlen = 0;
292
Benny Prijonof260e462007-04-30 21:03:32 +0000293 if (pending_data_.accept_.new_sock_) {
294 *pending_data_.accept_.new_sock_ = (pj_sock_t)pjNewSock;
295 pending_data_.accept_.new_sock_ = NULL;
296 }
297
298 if (pending_data_.accept_.local_) {
299 TInetAddr aAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000300 pj_sockaddr *ptr_sockaddr;
301
Benny Prijonof260e462007-04-30 21:03:32 +0000302 blank_sock_.LocalName(aAddr);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000303 ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.local_;
304 addrlen = *pending_data_.accept_.addrlen_;
305 PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen);
Benny Prijonof260e462007-04-30 21:03:32 +0000306 pending_data_.accept_.local_ = NULL;
307 }
308
309 if (pending_data_.accept_.remote_) {
310 TInetAddr aAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000311 pj_sockaddr *ptr_sockaddr;
Benny Prijonof260e462007-04-30 21:03:32 +0000312
313 blank_sock_.RemoteName(aAddr);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000314 ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.remote_;
315 addrlen = *pending_data_.accept_.addrlen_;
316 PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen);
Benny Prijonof260e462007-04-30 21:03:32 +0000317 pending_data_.accept_.remote_ = NULL;
318 }
319
320 if (pending_data_.accept_.addrlen_) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000321 if (addrlen == 0) {
322 if (pjNewSock->GetAf() == PJ_AF_INET)
323 addrlen = sizeof(pj_sockaddr_in);
324 else if (pjNewSock->GetAf() == PJ_AF_INET6)
325 addrlen = sizeof(pj_sockaddr_in6);
326 else {
327 pj_assert(!"Unsupported address family");
328 }
329 }
330 *pending_data_.accept_.addrlen_ = addrlen;
Benny Prijonof260e462007-04-30 21:03:32 +0000331 pending_data_.accept_.addrlen_ = NULL;
332 }
333
334 return pjNewSock;
335}
336
337
338//
339// Completion callback.
340//
341void CIoqueueCallback::RunL()
342{
343 Type cur_type = type_;
344
345 type_ = TYPE_NONE;
346
347 if (cur_type == TYPE_READ) {
348 //
349 // Completion of asynchronous RecvFrom()
350 //
351
352 /* Clear op_key (save it to temp variable first!) */
353 pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
354 pending_data_.read_.op_key_ = NULL;
355
356 // Handle failure condition
357 if (iStatus != KErrNone) {
358 if (cb_.on_read_complete) {
359 cb_.on_read_complete( key_, op_key,
360 -PJ_RETURN_OS_ERROR(iStatus.Int()));
361 }
362 return;
363 }
364
365 HandleReadCompletion();
366
367 /* Call callback */
368 if (cb_.on_read_complete) {
369 cb_.on_read_complete(key_, op_key, aBufferPtr_.Length());
370 }
371
372 } else if (cur_type == TYPE_ACCEPT) {
373 //
374 // Completion of asynchronous Accept()
375 //
376
377 /* Clear op_key (save it to temp variable first!) */
378 pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
379 pending_data_.read_.op_key_ = NULL;
380
381 // Handle failure condition
382 if (iStatus != KErrNone) {
383 if (pending_data_.accept_.new_sock_)
384 *pending_data_.accept_.new_sock_ = PJ_INVALID_SOCKET;
385
386 if (cb_.on_accept_complete) {
387 cb_.on_accept_complete( key_, op_key, PJ_INVALID_SOCKET,
388 -PJ_RETURN_OS_ERROR(iStatus.Int()));
389 }
390 return;
391 }
392
393 CPjSocket *pjNewSock = HandleAcceptCompletion();
394
395 // Call callback.
396 if (cb_.on_accept_complete) {
397 cb_.on_accept_complete( key_, op_key, (pj_sock_t)pjNewSock,
398 PJ_SUCCESS);
399 }
400 }
401
402 ioqueue_->eventCount++;
403}
404
405//
406// CActive's DoCancel()
407//
408void CIoqueueCallback::DoCancel()
409{
410 if (type_ == TYPE_READ)
411 sock_->Socket().CancelRecv();
412 else if (type_ == TYPE_ACCEPT)
413 sock_->Socket().CancelAccept();
414
415 type_ = TYPE_NONE;
Benny Prijono593ccc62007-06-23 01:04:16 +0000416 pending_data_.common_.op_key_ = NULL;
Benny Prijonof260e462007-04-30 21:03:32 +0000417}
418
419//
420// Cancel operation and call callback.
421//
422void CIoqueueCallback::CancelOperation(pj_ioqueue_op_key_t *op_key,
423 pj_ssize_t bytes_status)
424{
425 Type cur_type = type_;
426
Benny Prijono593ccc62007-06-23 01:04:16 +0000427 pj_assert(op_key == pending_data_.common_.op_key_);
428
Benny Prijonof260e462007-04-30 21:03:32 +0000429 Cancel();
430
431 if (cur_type == TYPE_READ) {
432 if (cb_.on_read_complete)
433 cb_.on_read_complete(key_, op_key, bytes_status);
434 } else if (cur_type == TYPE_ACCEPT)
Benny Prijono593ccc62007-06-23 01:04:16 +0000435 ;
Benny Prijonof260e462007-04-30 21:03:32 +0000436}
437
438
439/////////////////////////////////////////////////////////////////////////////
440/*
441 * IO Queue key structure.
442 */
443struct pj_ioqueue_key_t
444{
445 CIoqueueCallback *cbObj;
446};
447
448
449/*
450 * Return the name of the ioqueue implementation.
451 */
452PJ_DEF(const char*) pj_ioqueue_name(void)
453{
454 return "ioqueue-symbian";
455}
456
457
458/*
459 * Create a new I/O Queue framework.
460 */
461PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
462 pj_size_t max_fd,
463 pj_ioqueue_t **p_ioqueue)
464{
465 pj_ioqueue_t *ioq;
466
467 PJ_UNUSED_ARG(max_fd);
468
Benny Prijonob2c96822007-05-03 13:31:21 +0000469 ioq = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_t);
Benny Prijonof260e462007-04-30 21:03:32 +0000470 *p_ioqueue = ioq;
471 return PJ_SUCCESS;
472}
473
474
475/*
476 * Destroy the I/O queue.
477 */
478PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioq )
479{
Benny Prijonob2c96822007-05-03 13:31:21 +0000480 PJ_UNUSED_ARG(ioq);
Benny Prijonof260e462007-04-30 21:03:32 +0000481 return PJ_SUCCESS;
482}
483
484
485/*
486 * Set the lock object to be used by the I/O Queue.
487 */
488PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioq,
489 pj_lock_t *lock,
490 pj_bool_t auto_delete )
491{
492 /* Don't really need lock for now */
493 PJ_UNUSED_ARG(ioq);
494
495 if (auto_delete) {
496 pj_lock_destroy(lock);
497 }
498
499 return PJ_SUCCESS;
500}
501
Benny Prijonoe53a04a2008-02-14 13:34:55 +0000502PJ_DEF(pj_status_t) pj_ioqueue_set_default_concurrency(pj_ioqueue_t *ioqueue,
503 pj_bool_t allow)
504{
505 /* Not supported, just return PJ_SUCCESS silently */
506 PJ_UNUSED_ARG(ioqueue);
507 PJ_UNUSED_ARG(allow);
508 return PJ_SUCCESS;
509}
Benny Prijonof260e462007-04-30 21:03:32 +0000510
511/*
512 * Register a socket to the I/O queue framework.
513 */
514PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
515 pj_ioqueue_t *ioq,
516 pj_sock_t sock,
517 void *user_data,
518 const pj_ioqueue_callback *cb,
519 pj_ioqueue_key_t **p_key )
520{
521 pj_ioqueue_key_t *key;
522
Benny Prijonob2c96822007-05-03 13:31:21 +0000523 key = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_key_t);
Benny Prijonof260e462007-04-30 21:03:32 +0000524 key->cbObj = CIoqueueCallback::NewL(ioq, key, sock, cb, user_data);
525
526 *p_key = key;
527 return PJ_SUCCESS;
528}
529
530/*
531 * Unregister from the I/O Queue framework.
532 */
533PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
534{
535 if (key == NULL || key->cbObj == NULL)
536 return PJ_SUCCESS;
537
538 // Cancel pending async object
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000539 if (key->cbObj) {
Benny Prijonof260e462007-04-30 21:03:32 +0000540 key->cbObj->Cancel();
541 }
542
543 // Close socket.
544 key->cbObj->get_pj_socket()->Socket().Close();
545 delete key->cbObj->get_pj_socket();
546
547 // Delete async object.
548 if (key->cbObj) {
549 delete key->cbObj;
550 key->cbObj = NULL;
551 }
552
553 return PJ_SUCCESS;
554}
555
556
557/*
558 * Get user data associated with an ioqueue key.
559 */
560PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
561{
562 return key->cbObj->get_user_data();
563}
564
565
566/*
567 * Set or change the user data to be associated with the file descriptor or
568 * handle or socket descriptor.
569 */
570PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
571 void *user_data,
572 void **old_data)
573{
574 if (old_data)
575 *old_data = key->cbObj->get_user_data();
576 key->cbObj->set_user_data(user_data);
577
578 return PJ_SUCCESS;
579}
580
581
582/*
583 * Initialize operation key.
584 */
585PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
586 pj_size_t size )
587{
Benny Prijonob2c96822007-05-03 13:31:21 +0000588 pj_bzero(op_key, size);
Benny Prijonof260e462007-04-30 21:03:32 +0000589}
590
591
592/*
593 * Check if operation is pending on the specified operation key.
594 */
595PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
596 pj_ioqueue_op_key_t *op_key )
597{
598 return key->cbObj->get_op_key()==op_key &&
599 key->cbObj->IsActive();
600}
601
602
603/*
604 * Post completion status to the specified operation key and call the
605 * appropriate callback.
606 */
607PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
608 pj_ioqueue_op_key_t *op_key,
609 pj_ssize_t bytes_status )
610{
611 if (pj_ioqueue_is_pending(key, op_key)) {
612 key->cbObj->CancelOperation(op_key, bytes_status);
613 }
614 return PJ_SUCCESS;
615}
616
617
618#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
619/**
620 * Instruct I/O Queue to accept incoming connection on the specified
621 * listening socket.
622 */
623PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
624 pj_ioqueue_op_key_t *op_key,
625 pj_sock_t *new_sock,
626 pj_sockaddr_t *local,
627 pj_sockaddr_t *remote,
628 int *addrlen )
629{
630
631 return key->cbObj->StartAccept(op_key, new_sock, local, remote, addrlen);
632}
633
634
635/*
636 * Initiate non-blocking socket connect.
637 */
638PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
639 const pj_sockaddr_t *addr,
640 int addrlen )
641{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000642 pj_status_t status;
643
Benny Prijonof260e462007-04-30 21:03:32 +0000644 RSocket &rSock = key->cbObj->get_pj_socket()->Socket();
645 TInetAddr inetAddr;
Benny Prijonof260e462007-04-30 21:03:32 +0000646 TRequestStatus reqStatus;
647
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000648 // Return failure if access point is marked as down by app.
649 PJ_SYMBIAN_CHECK_CONNECTION();
650
Benny Prijono62b86eb2007-12-01 08:52:57 +0000651 // Convert address
652 status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen,
653 inetAddr);
654 if (status != PJ_SUCCESS)
655 return status;
656
Benny Prijonof260e462007-04-30 21:03:32 +0000657 // We don't support async connect for now.
658 PJ_TODO(IOQUEUE_SUPPORT_ASYNC_CONNECT);
659
660 rSock.Connect(inetAddr, reqStatus);
661 User::WaitForRequest(reqStatus);
662
663 if (reqStatus == KErrNone)
664 return PJ_SUCCESS;
665
666 return PJ_RETURN_OS_ERROR(reqStatus.Int());
667}
668
669
670#endif /* PJ_HAS_TCP */
671
672/*
673 * Poll the I/O Queue for completed events.
674 */
675PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioq,
676 const pj_time_val *timeout)
677{
Benny Prijonob2c96822007-05-03 13:31:21 +0000678 /* Polling is not necessary on Symbian, since all async activities
679 * are registered to active scheduler.
680 */
681 PJ_UNUSED_ARG(ioq);
682 PJ_UNUSED_ARG(timeout);
683 return 0;
Benny Prijonof260e462007-04-30 21:03:32 +0000684}
685
686
687/*
688 * Instruct the I/O Queue to read from the specified handle.
689 */
690PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
691 pj_ioqueue_op_key_t *op_key,
692 void *buffer,
693 pj_ssize_t *length,
694 pj_uint32_t flags )
695{
Benny Prijono897f9f82007-05-03 19:56:21 +0000696 // If socket has reader, delete it.
697 if (key->cbObj->get_pj_socket()->Reader())
698 key->cbObj->get_pj_socket()->DestroyReader();
699
Benny Prijonof260e462007-04-30 21:03:32 +0000700 // Clear flag
701 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
702 return key->cbObj->StartRead(op_key, buffer, length, flags, NULL, NULL);
703}
704
705
706/*
707 * This function behaves similarly as #pj_ioqueue_recv(), except that it is
708 * normally called for socket, and the remote address will also be returned
709 * along with the data.
710 */
711PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
712 pj_ioqueue_op_key_t *op_key,
713 void *buffer,
714 pj_ssize_t *length,
715 pj_uint32_t flags,
716 pj_sockaddr_t *addr,
717 int *addrlen)
718{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000719 CPjSocket *sock = key->cbObj->get_pj_socket();
720
721 // If address is specified, check that the length match the
722 // address family
723 if (addr || addrlen) {
724 PJ_ASSERT_RETURN(addr && addrlen && *addrlen, PJ_EINVAL);
725 if (sock->GetAf() == PJ_AF_INET) {
Benny Prijono80025db2007-12-02 15:36:46 +0000726 PJ_ASSERT_RETURN(*addrlen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000727 } else if (sock->GetAf() == PJ_AF_INET6) {
Benny Prijono80025db2007-12-02 15:36:46 +0000728 PJ_ASSERT_RETURN(*addrlen>=(int)sizeof(pj_sockaddr_in6), PJ_EINVAL);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000729 }
730 }
731
Benny Prijono897f9f82007-05-03 19:56:21 +0000732 // If socket has reader, delete it.
Benny Prijono62b86eb2007-12-01 08:52:57 +0000733 if (sock->Reader())
734 sock->DestroyReader();
Benny Prijono897f9f82007-05-03 19:56:21 +0000735
Benny Prijonof260e462007-04-30 21:03:32 +0000736 if (key->cbObj->IsActive())
737 return PJ_EBUSY;
738
739 // Clear flag
740 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
741 return key->cbObj->StartRead(op_key, buffer, length, flags, addr, addrlen);
742}
743
744
745/*
746 * Instruct the I/O Queue to write to the handle.
747 */
748PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
749 pj_ioqueue_op_key_t *op_key,
750 const void *data,
751 pj_ssize_t *length,
752 pj_uint32_t flags )
753{
754 TRequestStatus reqStatus;
755 TPtrC8 aBuffer((const TUint8*)data, (TInt)*length);
756 TSockXfrLength aLen;
757
758 PJ_UNUSED_ARG(op_key);
759
760 // Forcing pending operation is not supported.
761 PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
762
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000763 // Return failure if access point is marked as down by app.
764 PJ_SYMBIAN_CHECK_CONNECTION();
765
Benny Prijonof260e462007-04-30 21:03:32 +0000766 // Clear flag
767 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
768
769 key->cbObj->get_pj_socket()->Socket().Send(aBuffer, flags, reqStatus, aLen);
770 User::WaitForRequest(reqStatus);
771
772 if (reqStatus.Int() != KErrNone)
773 return PJ_RETURN_OS_ERROR(reqStatus.Int());
774
775 //At least in UIQ Emulator, aLen.Length() reports incorrect length
776 //for UDP (some newlc.com users seem to have reported this too).
777 //*length = aLen.Length();
778 return PJ_SUCCESS;
779}
780
781
782/*
783 * Instruct the I/O Queue to write to the handle.
784 */
785PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
786 pj_ioqueue_op_key_t *op_key,
787 const void *data,
788 pj_ssize_t *length,
789 pj_uint32_t flags,
790 const pj_sockaddr_t *addr,
791 int addrlen)
792{
793 TRequestStatus reqStatus;
794 TPtrC8 aBuffer;
795 TInetAddr inetAddr;
796 TSockXfrLength aLen;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000797 pj_status_t status;
Benny Prijonof260e462007-04-30 21:03:32 +0000798
799 PJ_UNUSED_ARG(op_key);
800
801 // Forcing pending operation is not supported.
802 PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
803
Nanang Izzuddin90b83202009-03-02 15:48:45 +0000804 // Return failure if access point is marked as down by app.
805 PJ_SYMBIAN_CHECK_CONNECTION();
806
Benny Prijono62b86eb2007-12-01 08:52:57 +0000807 // Convert address
808 status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen,
809 inetAddr);
810 if (status != PJ_SUCCESS)
811 return status;
812
Benny Prijonof260e462007-04-30 21:03:32 +0000813 // Clear flag
814 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
815
816 aBuffer.Set((const TUint8*)data, (TInt)*length);
Benny Prijonof260e462007-04-30 21:03:32 +0000817 CPjSocket *pjSock = key->cbObj->get_pj_socket();
818
819 pjSock->Socket().SendTo(aBuffer, inetAddr, flags, reqStatus, aLen);
820 User::WaitForRequest(reqStatus);
821
822 if (reqStatus.Int() != KErrNone)
823 return PJ_RETURN_OS_ERROR(reqStatus.Int());
824
825 //At least in UIQ Emulator, aLen.Length() reports incorrect length
826 //for UDP (some newlc.com users seem to have reported this too).
827 //*length = aLen.Length();
828 return PJ_SUCCESS;
829}
830
Benny Prijonoe53a04a2008-02-14 13:34:55 +0000831PJ_DEF(pj_status_t) pj_ioqueue_set_concurrency(pj_ioqueue_key_t *key,
832 pj_bool_t allow)
833{
834 /* Not supported, just return PJ_SUCCESS silently */
835 PJ_UNUSED_ARG(key);
836 PJ_UNUSED_ARG(allow);
837 return PJ_SUCCESS;
838}
839
840PJ_DEF(pj_status_t) pj_ioqueue_lock_key(pj_ioqueue_key_t *key)
841{
842 /* Not supported, just return PJ_SUCCESS silently */
843 PJ_UNUSED_ARG(key);
844 return PJ_SUCCESS;
845}
846
847PJ_DEF(pj_status_t) pj_ioqueue_unlock_key(pj_ioqueue_key_t *key)
848{
849 /* Not supported, just return PJ_SUCCESS silently */
850 PJ_UNUSED_ARG(key);
851 return PJ_SUCCESS;
852}