blob: 71d7de7f80a324fba565d4b6b90cbc7c0e01e426 [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/ioqueue.h>
20#include <pj/assert.h>
21#include <pj/errno.h>
22#include <pj/list.h>
23#include <pj/lock.h>
24#include <pj/pool.h>
25#include <pj/string.h>
26
27#include "os_symbian.h"
28
29class CIoqueueCallback;
30
31/*
32 * IO Queue structure.
33 */
34struct pj_ioqueue_t
35{
36 int eventCount;
Benny Prijonof260e462007-04-30 21:03:32 +000037};
38
39
40/////////////////////////////////////////////////////////////////////////////
41// Class to encapsulate asynchronous socket operation.
42//
43class CIoqueueCallback : public CActive
44{
45public:
46 static CIoqueueCallback* NewL(pj_ioqueue_t *ioqueue,
47 pj_ioqueue_key_t *key,
48 pj_sock_t sock,
49 const pj_ioqueue_callback *cb,
50 void *user_data);
51
52 //
53 // Start asynchronous recv() operation
54 //
55 pj_status_t StartRead(pj_ioqueue_op_key_t *op_key,
56 void *buf, pj_ssize_t *size, unsigned flags,
57 pj_sockaddr_t *addr, int *addrlen);
58
59 //
60 // Start asynchronous accept() operation.
61 //
62 pj_status_t StartAccept(pj_ioqueue_op_key_t *op_key,
63 pj_sock_t *new_sock,
64 pj_sockaddr_t *local,
65 pj_sockaddr_t *remote,
66 int *addrlen );
67
68 //
69 // Completion callback.
70 //
71 void RunL();
72
73 //
74 // CActive's DoCancel()
75 //
76 void DoCancel();
77
78 //
79 // Cancel operation and call callback.
80 //
81 void CancelOperation(pj_ioqueue_op_key_t *op_key,
82 pj_ssize_t bytes_status);
83
84 //
85 // Accessors
86 //
87 void* get_user_data() const
88 {
89 return user_data_;
90 }
91 void set_user_data(void *user_data)
92 {
93 user_data_ = user_data;
94 }
95 pj_ioqueue_op_key_t *get_op_key() const
96 {
97 return pending_data_.common_.op_key_;
98 }
99 CPjSocket* get_pj_socket()
100 {
101 return sock_;
102 }
103
104private:
105 // Type of pending operation.
106 enum Type {
107 TYPE_NONE,
108 TYPE_READ,
109 TYPE_ACCEPT,
110 };
111
112 // Static data.
113 pj_ioqueue_t *ioqueue_;
114 pj_ioqueue_key_t *key_;
115 CPjSocket *sock_;
116 pj_ioqueue_callback cb_;
117 void *user_data_;
118
119 // Symbian data.
120 TPtr8 aBufferPtr_;
121 TInetAddr aAddress_;
122
123 // Application data.
124 Type type_;
125
126 union Pending_Data
127 {
128 struct Common
129 {
130 pj_ioqueue_op_key_t *op_key_;
131 } common_;
132
133 struct Pending_Read
134 {
135 pj_ioqueue_op_key_t *op_key_;
136 pj_sockaddr_t *addr_;
137 int *addrlen_;
138 } read_;
139
140 struct Pending_Accept
141 {
142 pj_ioqueue_op_key_t *op_key_;
143 pj_sock_t *new_sock_;
144 pj_sockaddr_t *local_;
145 pj_sockaddr_t *remote_;
146 int *addrlen_;
147 } accept_;
148 };
149
150 union Pending_Data pending_data_;
151 RSocket blank_sock_;
152
153 CIoqueueCallback(pj_ioqueue_t *ioqueue,
154 pj_ioqueue_key_t *key, pj_sock_t sock,
155 const pj_ioqueue_callback *cb, void *user_data)
156 : CActive(CActive::EPriorityStandard),
157 ioqueue_(ioqueue), key_(key), sock_((CPjSocket*)sock),
158 user_data_(user_data), aBufferPtr_(NULL, 0), type_(TYPE_NONE)
159 {
160 pj_memcpy(&cb_, cb, sizeof(*cb));
161 }
162
163
164 void ConstructL()
165 {
166 CActiveScheduler::Add(this);
167 }
168
169 void HandleReadCompletion();
170 CPjSocket *HandleAcceptCompletion();
171};
172
173
174CIoqueueCallback* CIoqueueCallback::NewL(pj_ioqueue_t *ioqueue,
175 pj_ioqueue_key_t *key,
176 pj_sock_t sock,
177 const pj_ioqueue_callback *cb,
178 void *user_data)
179{
180 CIoqueueCallback *self = new CIoqueueCallback(ioqueue, key, sock,
181 cb, user_data);
182 CleanupStack::PushL(self);
183 self->ConstructL();
184 CleanupStack::Pop(self);
185
186 return self;
187}
188
189
190//
191// Start asynchronous recv() operation
192//
193pj_status_t CIoqueueCallback::StartRead(pj_ioqueue_op_key_t *op_key,
194 void *buf, pj_ssize_t *size,
195 unsigned flags,
196 pj_sockaddr_t *addr, int *addrlen)
197{
198 PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
199 PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
200
201 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
202
203 pending_data_.read_.op_key_ = op_key;
204 pending_data_.read_.addr_ = addr;
205 pending_data_.read_.addrlen_ = addrlen;
206
207 aBufferPtr_.Set((TUint8*)buf, 0, (TInt)*size);
208
209 type_ = TYPE_READ;
210 if (addr && addrlen) {
211 sock_->Socket().RecvFrom(aBufferPtr_, aAddress_, flags, iStatus);
212 } else {
213 aAddress_.SetAddress(0);
214 aAddress_.SetPort(0);
215 sock_->Socket().Recv(aBufferPtr_, flags, iStatus);
216 }
217
Benny Prijono5d542642007-05-02 18:54:19 +0000218 SetActive();
219 return PJ_EPENDING;
Benny Prijonof260e462007-04-30 21:03:32 +0000220}
221
222
223//
224// Start asynchronous accept() operation.
225//
226pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key,
227 pj_sock_t *new_sock,
228 pj_sockaddr_t *local,
229 pj_sockaddr_t *remote,
230 int *addrlen )
231{
232 PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
233 PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
234
Benny Prijono62b86eb2007-12-01 08:52:57 +0000235 // addrlen must be specified if local or remote is specified
236 PJ_ASSERT_RETURN((!local && !remote) ||
237 (addrlen && *addrlen), PJ_EINVAL);
238
Benny Prijonof260e462007-04-30 21:03:32 +0000239 pending_data_.accept_.op_key_ = op_key;
240 pending_data_.accept_.new_sock_ = new_sock;
241 pending_data_.accept_.local_ = local;
242 pending_data_.accept_.remote_ = remote;
243 pending_data_.accept_.addrlen_ = addrlen;
244
245 // Create blank socket
246 blank_sock_.Open(PjSymbianOS::Instance()->SocketServ());
247
248 type_ = TYPE_ACCEPT;
249 sock_->Socket().Accept(blank_sock_, iStatus);
250
Benny Prijono5d542642007-05-02 18:54:19 +0000251 SetActive();
252 return PJ_EPENDING;
Benny Prijonof260e462007-04-30 21:03:32 +0000253}
254
255
256//
257// Handle asynchronous RecvFrom() completion
258//
259void CIoqueueCallback::HandleReadCompletion()
260{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000261 if (pending_data_.read_.addr_ && pending_data_.read_.addrlen_) {
Benny Prijono5d542642007-05-02 18:54:19 +0000262 PjSymbianOS::Addr2pj(aAddress_,
Benny Prijono62b86eb2007-12-01 08:52:57 +0000263 *(pj_sockaddr*)pending_data_.read_.addr_,
264 pending_data_.read_.addrlen_);
Benny Prijono5d542642007-05-02 18:54:19 +0000265 pending_data_.read_.addr_ = NULL;
Benny Prijono5d542642007-05-02 18:54:19 +0000266 pending_data_.read_.addrlen_ = NULL;
267 }
Benny Prijonof260e462007-04-30 21:03:32 +0000268
Benny Prijono5d542642007-05-02 18:54:19 +0000269 pending_data_.read_.op_key_ = NULL;
Benny Prijonof260e462007-04-30 21:03:32 +0000270}
271
272
273//
274// Handle asynchronous Accept() completion.
275//
276CPjSocket *CIoqueueCallback::HandleAcceptCompletion()
277{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000278 CPjSocket *pjNewSock = new CPjSocket(get_pj_socket()->GetAf(),
279 blank_sock_);
280 int addrlen = 0;
281
Benny Prijonof260e462007-04-30 21:03:32 +0000282 if (pending_data_.accept_.new_sock_) {
283 *pending_data_.accept_.new_sock_ = (pj_sock_t)pjNewSock;
284 pending_data_.accept_.new_sock_ = NULL;
285 }
286
287 if (pending_data_.accept_.local_) {
288 TInetAddr aAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000289 pj_sockaddr *ptr_sockaddr;
290
Benny Prijonof260e462007-04-30 21:03:32 +0000291 blank_sock_.LocalName(aAddr);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000292 ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.local_;
293 addrlen = *pending_data_.accept_.addrlen_;
294 PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen);
Benny Prijonof260e462007-04-30 21:03:32 +0000295 pending_data_.accept_.local_ = NULL;
296 }
297
298 if (pending_data_.accept_.remote_) {
299 TInetAddr aAddr;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000300 pj_sockaddr *ptr_sockaddr;
Benny Prijonof260e462007-04-30 21:03:32 +0000301
302 blank_sock_.RemoteName(aAddr);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000303 ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.remote_;
304 addrlen = *pending_data_.accept_.addrlen_;
305 PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen);
Benny Prijonof260e462007-04-30 21:03:32 +0000306 pending_data_.accept_.remote_ = NULL;
307 }
308
309 if (pending_data_.accept_.addrlen_) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000310 if (addrlen == 0) {
311 if (pjNewSock->GetAf() == PJ_AF_INET)
312 addrlen = sizeof(pj_sockaddr_in);
313 else if (pjNewSock->GetAf() == PJ_AF_INET6)
314 addrlen = sizeof(pj_sockaddr_in6);
315 else {
316 pj_assert(!"Unsupported address family");
317 }
318 }
319 *pending_data_.accept_.addrlen_ = addrlen;
Benny Prijonof260e462007-04-30 21:03:32 +0000320 pending_data_.accept_.addrlen_ = NULL;
321 }
322
323 return pjNewSock;
324}
325
326
327//
328// Completion callback.
329//
330void CIoqueueCallback::RunL()
331{
332 Type cur_type = type_;
333
334 type_ = TYPE_NONE;
335
336 if (cur_type == TYPE_READ) {
337 //
338 // Completion of asynchronous RecvFrom()
339 //
340
341 /* Clear op_key (save it to temp variable first!) */
342 pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
343 pending_data_.read_.op_key_ = NULL;
344
345 // Handle failure condition
346 if (iStatus != KErrNone) {
347 if (cb_.on_read_complete) {
348 cb_.on_read_complete( key_, op_key,
349 -PJ_RETURN_OS_ERROR(iStatus.Int()));
350 }
351 return;
352 }
353
354 HandleReadCompletion();
355
356 /* Call callback */
357 if (cb_.on_read_complete) {
358 cb_.on_read_complete(key_, op_key, aBufferPtr_.Length());
359 }
360
361 } else if (cur_type == TYPE_ACCEPT) {
362 //
363 // Completion of asynchronous Accept()
364 //
365
366 /* Clear op_key (save it to temp variable first!) */
367 pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
368 pending_data_.read_.op_key_ = NULL;
369
370 // Handle failure condition
371 if (iStatus != KErrNone) {
372 if (pending_data_.accept_.new_sock_)
373 *pending_data_.accept_.new_sock_ = PJ_INVALID_SOCKET;
374
375 if (cb_.on_accept_complete) {
376 cb_.on_accept_complete( key_, op_key, PJ_INVALID_SOCKET,
377 -PJ_RETURN_OS_ERROR(iStatus.Int()));
378 }
379 return;
380 }
381
382 CPjSocket *pjNewSock = HandleAcceptCompletion();
383
384 // Call callback.
385 if (cb_.on_accept_complete) {
386 cb_.on_accept_complete( key_, op_key, (pj_sock_t)pjNewSock,
387 PJ_SUCCESS);
388 }
389 }
390
391 ioqueue_->eventCount++;
392}
393
394//
395// CActive's DoCancel()
396//
397void CIoqueueCallback::DoCancel()
398{
399 if (type_ == TYPE_READ)
400 sock_->Socket().CancelRecv();
401 else if (type_ == TYPE_ACCEPT)
402 sock_->Socket().CancelAccept();
403
404 type_ = TYPE_NONE;
Benny Prijono593ccc62007-06-23 01:04:16 +0000405 pending_data_.common_.op_key_ = NULL;
Benny Prijonof260e462007-04-30 21:03:32 +0000406}
407
408//
409// Cancel operation and call callback.
410//
411void CIoqueueCallback::CancelOperation(pj_ioqueue_op_key_t *op_key,
412 pj_ssize_t bytes_status)
413{
414 Type cur_type = type_;
415
Benny Prijono593ccc62007-06-23 01:04:16 +0000416 pj_assert(op_key == pending_data_.common_.op_key_);
417
Benny Prijonof260e462007-04-30 21:03:32 +0000418 Cancel();
419
420 if (cur_type == TYPE_READ) {
421 if (cb_.on_read_complete)
422 cb_.on_read_complete(key_, op_key, bytes_status);
423 } else if (cur_type == TYPE_ACCEPT)
Benny Prijono593ccc62007-06-23 01:04:16 +0000424 ;
Benny Prijonof260e462007-04-30 21:03:32 +0000425}
426
427
428/////////////////////////////////////////////////////////////////////////////
429/*
430 * IO Queue key structure.
431 */
432struct pj_ioqueue_key_t
433{
434 CIoqueueCallback *cbObj;
435};
436
437
438/*
439 * Return the name of the ioqueue implementation.
440 */
441PJ_DEF(const char*) pj_ioqueue_name(void)
442{
443 return "ioqueue-symbian";
444}
445
446
447/*
448 * Create a new I/O Queue framework.
449 */
450PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
451 pj_size_t max_fd,
452 pj_ioqueue_t **p_ioqueue)
453{
454 pj_ioqueue_t *ioq;
455
456 PJ_UNUSED_ARG(max_fd);
457
Benny Prijonob2c96822007-05-03 13:31:21 +0000458 ioq = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_t);
Benny Prijonof260e462007-04-30 21:03:32 +0000459 *p_ioqueue = ioq;
460 return PJ_SUCCESS;
461}
462
463
464/*
465 * Destroy the I/O queue.
466 */
467PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioq )
468{
Benny Prijonob2c96822007-05-03 13:31:21 +0000469 PJ_UNUSED_ARG(ioq);
Benny Prijonof260e462007-04-30 21:03:32 +0000470 return PJ_SUCCESS;
471}
472
473
474/*
475 * Set the lock object to be used by the I/O Queue.
476 */
477PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioq,
478 pj_lock_t *lock,
479 pj_bool_t auto_delete )
480{
481 /* Don't really need lock for now */
482 PJ_UNUSED_ARG(ioq);
483
484 if (auto_delete) {
485 pj_lock_destroy(lock);
486 }
487
488 return PJ_SUCCESS;
489}
490
491
492/*
493 * Register a socket to the I/O queue framework.
494 */
495PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
496 pj_ioqueue_t *ioq,
497 pj_sock_t sock,
498 void *user_data,
499 const pj_ioqueue_callback *cb,
500 pj_ioqueue_key_t **p_key )
501{
502 pj_ioqueue_key_t *key;
503
Benny Prijonob2c96822007-05-03 13:31:21 +0000504 key = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_key_t);
Benny Prijonof260e462007-04-30 21:03:32 +0000505 key->cbObj = CIoqueueCallback::NewL(ioq, key, sock, cb, user_data);
506
507 *p_key = key;
508 return PJ_SUCCESS;
509}
510
511/*
512 * Unregister from the I/O Queue framework.
513 */
514PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
515{
516 if (key == NULL || key->cbObj == NULL)
517 return PJ_SUCCESS;
518
519 // Cancel pending async object
520 if (key->cbObj && key->cbObj->IsActive()) {
521 key->cbObj->Cancel();
522 }
523
524 // Close socket.
525 key->cbObj->get_pj_socket()->Socket().Close();
526 delete key->cbObj->get_pj_socket();
527
528 // Delete async object.
529 if (key->cbObj) {
530 delete key->cbObj;
531 key->cbObj = NULL;
532 }
533
534 return PJ_SUCCESS;
535}
536
537
538/*
539 * Get user data associated with an ioqueue key.
540 */
541PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
542{
543 return key->cbObj->get_user_data();
544}
545
546
547/*
548 * Set or change the user data to be associated with the file descriptor or
549 * handle or socket descriptor.
550 */
551PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
552 void *user_data,
553 void **old_data)
554{
555 if (old_data)
556 *old_data = key->cbObj->get_user_data();
557 key->cbObj->set_user_data(user_data);
558
559 return PJ_SUCCESS;
560}
561
562
563/*
564 * Initialize operation key.
565 */
566PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
567 pj_size_t size )
568{
Benny Prijonob2c96822007-05-03 13:31:21 +0000569 pj_bzero(op_key, size);
Benny Prijonof260e462007-04-30 21:03:32 +0000570}
571
572
573/*
574 * Check if operation is pending on the specified operation key.
575 */
576PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
577 pj_ioqueue_op_key_t *op_key )
578{
579 return key->cbObj->get_op_key()==op_key &&
580 key->cbObj->IsActive();
581}
582
583
584/*
585 * Post completion status to the specified operation key and call the
586 * appropriate callback.
587 */
588PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
589 pj_ioqueue_op_key_t *op_key,
590 pj_ssize_t bytes_status )
591{
592 if (pj_ioqueue_is_pending(key, op_key)) {
593 key->cbObj->CancelOperation(op_key, bytes_status);
594 }
595 return PJ_SUCCESS;
596}
597
598
599#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
600/**
601 * Instruct I/O Queue to accept incoming connection on the specified
602 * listening socket.
603 */
604PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
605 pj_ioqueue_op_key_t *op_key,
606 pj_sock_t *new_sock,
607 pj_sockaddr_t *local,
608 pj_sockaddr_t *remote,
609 int *addrlen )
610{
611
612 return key->cbObj->StartAccept(op_key, new_sock, local, remote, addrlen);
613}
614
615
616/*
617 * Initiate non-blocking socket connect.
618 */
619PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
620 const pj_sockaddr_t *addr,
621 int addrlen )
622{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000623 pj_status_t status;
624
Benny Prijonof260e462007-04-30 21:03:32 +0000625 RSocket &rSock = key->cbObj->get_pj_socket()->Socket();
626 TInetAddr inetAddr;
Benny Prijonof260e462007-04-30 21:03:32 +0000627 TRequestStatus reqStatus;
628
Benny Prijono62b86eb2007-12-01 08:52:57 +0000629 // Convert address
630 status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen,
631 inetAddr);
632 if (status != PJ_SUCCESS)
633 return status;
634
Benny Prijonof260e462007-04-30 21:03:32 +0000635 // We don't support async connect for now.
636 PJ_TODO(IOQUEUE_SUPPORT_ASYNC_CONNECT);
637
638 rSock.Connect(inetAddr, reqStatus);
639 User::WaitForRequest(reqStatus);
640
641 if (reqStatus == KErrNone)
642 return PJ_SUCCESS;
643
644 return PJ_RETURN_OS_ERROR(reqStatus.Int());
645}
646
647
648#endif /* PJ_HAS_TCP */
649
650/*
651 * Poll the I/O Queue for completed events.
652 */
653PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioq,
654 const pj_time_val *timeout)
655{
Benny Prijonob2c96822007-05-03 13:31:21 +0000656 /* Polling is not necessary on Symbian, since all async activities
657 * are registered to active scheduler.
658 */
659 PJ_UNUSED_ARG(ioq);
660 PJ_UNUSED_ARG(timeout);
661 return 0;
Benny Prijonof260e462007-04-30 21:03:32 +0000662}
663
664
665/*
666 * Instruct the I/O Queue to read from the specified handle.
667 */
668PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
669 pj_ioqueue_op_key_t *op_key,
670 void *buffer,
671 pj_ssize_t *length,
672 pj_uint32_t flags )
673{
Benny Prijono897f9f82007-05-03 19:56:21 +0000674 // If socket has reader, delete it.
675 if (key->cbObj->get_pj_socket()->Reader())
676 key->cbObj->get_pj_socket()->DestroyReader();
677
Benny Prijonof260e462007-04-30 21:03:32 +0000678 // Clear flag
679 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
680 return key->cbObj->StartRead(op_key, buffer, length, flags, NULL, NULL);
681}
682
683
684/*
685 * This function behaves similarly as #pj_ioqueue_recv(), except that it is
686 * normally called for socket, and the remote address will also be returned
687 * along with the data.
688 */
689PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
690 pj_ioqueue_op_key_t *op_key,
691 void *buffer,
692 pj_ssize_t *length,
693 pj_uint32_t flags,
694 pj_sockaddr_t *addr,
695 int *addrlen)
696{
Benny Prijono62b86eb2007-12-01 08:52:57 +0000697 CPjSocket *sock = key->cbObj->get_pj_socket();
698
699 // If address is specified, check that the length match the
700 // address family
701 if (addr || addrlen) {
702 PJ_ASSERT_RETURN(addr && addrlen && *addrlen, PJ_EINVAL);
703 if (sock->GetAf() == PJ_AF_INET) {
Benny Prijono80025db2007-12-02 15:36:46 +0000704 PJ_ASSERT_RETURN(*addrlen>=(int)sizeof(pj_sockaddr_in), PJ_EINVAL);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000705 } else if (sock->GetAf() == PJ_AF_INET6) {
Benny Prijono80025db2007-12-02 15:36:46 +0000706 PJ_ASSERT_RETURN(*addrlen>=(int)sizeof(pj_sockaddr_in6), PJ_EINVAL);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000707 }
708 }
709
Benny Prijono897f9f82007-05-03 19:56:21 +0000710 // If socket has reader, delete it.
Benny Prijono62b86eb2007-12-01 08:52:57 +0000711 if (sock->Reader())
712 sock->DestroyReader();
Benny Prijono897f9f82007-05-03 19:56:21 +0000713
Benny Prijonof260e462007-04-30 21:03:32 +0000714 if (key->cbObj->IsActive())
715 return PJ_EBUSY;
716
717 // Clear flag
718 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
719 return key->cbObj->StartRead(op_key, buffer, length, flags, addr, addrlen);
720}
721
722
723/*
724 * Instruct the I/O Queue to write to the handle.
725 */
726PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
727 pj_ioqueue_op_key_t *op_key,
728 const void *data,
729 pj_ssize_t *length,
730 pj_uint32_t flags )
731{
732 TRequestStatus reqStatus;
733 TPtrC8 aBuffer((const TUint8*)data, (TInt)*length);
734 TSockXfrLength aLen;
735
736 PJ_UNUSED_ARG(op_key);
737
738 // Forcing pending operation is not supported.
739 PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
740
741 // Clear flag
742 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
743
744 key->cbObj->get_pj_socket()->Socket().Send(aBuffer, flags, reqStatus, aLen);
745 User::WaitForRequest(reqStatus);
746
747 if (reqStatus.Int() != KErrNone)
748 return PJ_RETURN_OS_ERROR(reqStatus.Int());
749
750 //At least in UIQ Emulator, aLen.Length() reports incorrect length
751 //for UDP (some newlc.com users seem to have reported this too).
752 //*length = aLen.Length();
753 return PJ_SUCCESS;
754}
755
756
757/*
758 * Instruct the I/O Queue to write to the handle.
759 */
760PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
761 pj_ioqueue_op_key_t *op_key,
762 const void *data,
763 pj_ssize_t *length,
764 pj_uint32_t flags,
765 const pj_sockaddr_t *addr,
766 int addrlen)
767{
768 TRequestStatus reqStatus;
769 TPtrC8 aBuffer;
770 TInetAddr inetAddr;
771 TSockXfrLength aLen;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000772 pj_status_t status;
Benny Prijonof260e462007-04-30 21:03:32 +0000773
774 PJ_UNUSED_ARG(op_key);
775
776 // Forcing pending operation is not supported.
777 PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
778
Benny Prijono62b86eb2007-12-01 08:52:57 +0000779 // Convert address
780 status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen,
781 inetAddr);
782 if (status != PJ_SUCCESS)
783 return status;
784
Benny Prijonof260e462007-04-30 21:03:32 +0000785 // Clear flag
786 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
787
788 aBuffer.Set((const TUint8*)data, (TInt)*length);
Benny Prijonof260e462007-04-30 21:03:32 +0000789 CPjSocket *pjSock = key->cbObj->get_pj_socket();
790
791 pjSock->Socket().SendTo(aBuffer, inetAddr, flags, reqStatus, aLen);
792 User::WaitForRequest(reqStatus);
793
794 if (reqStatus.Int() != KErrNone)
795 return PJ_RETURN_OS_ERROR(reqStatus.Int());
796
797 //At least in UIQ Emulator, aLen.Length() reports incorrect length
798 //for UDP (some newlc.com users seem to have reported this too).
799 //*length = aLen.Length();
800 return PJ_SUCCESS;
801}
802