blob: 6768cc01c4a2a2405f4172e338b0d6c2ed2f4c22 [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
235 pending_data_.accept_.op_key_ = op_key;
236 pending_data_.accept_.new_sock_ = new_sock;
237 pending_data_.accept_.local_ = local;
238 pending_data_.accept_.remote_ = remote;
239 pending_data_.accept_.addrlen_ = addrlen;
240
241 // Create blank socket
242 blank_sock_.Open(PjSymbianOS::Instance()->SocketServ());
243
244 type_ = TYPE_ACCEPT;
245 sock_->Socket().Accept(blank_sock_, iStatus);
246
Benny Prijono5d542642007-05-02 18:54:19 +0000247 SetActive();
248 return PJ_EPENDING;
Benny Prijonof260e462007-04-30 21:03:32 +0000249}
250
251
252//
253// Handle asynchronous RecvFrom() completion
254//
255void CIoqueueCallback::HandleReadCompletion()
256{
Benny Prijono5d542642007-05-02 18:54:19 +0000257 if (pending_data_.read_.addr_) {
258 PjSymbianOS::Addr2pj(aAddress_,
259 *(pj_sockaddr_in*)pending_data_.read_.addr_);
260 pending_data_.read_.addr_ = NULL;
261 }
262 if (pending_data_.read_.addrlen_) {
263 *pending_data_.read_.addrlen_ = sizeof(pj_sockaddr_in);
264 pending_data_.read_.addrlen_ = NULL;
265 }
Benny Prijonof260e462007-04-30 21:03:32 +0000266
Benny Prijono5d542642007-05-02 18:54:19 +0000267 pending_data_.read_.op_key_ = NULL;
Benny Prijonof260e462007-04-30 21:03:32 +0000268}
269
270
271//
272// Handle asynchronous Accept() completion.
273//
274CPjSocket *CIoqueueCallback::HandleAcceptCompletion()
275{
276 CPjSocket *pjNewSock = new CPjSocket(blank_sock_);
277
278 if (pending_data_.accept_.new_sock_) {
279 *pending_data_.accept_.new_sock_ = (pj_sock_t)pjNewSock;
280 pending_data_.accept_.new_sock_ = NULL;
281 }
282
283 if (pending_data_.accept_.local_) {
284 TInetAddr aAddr;
285 pj_sockaddr_in *ptr_sockaddr;
286
287 blank_sock_.LocalName(aAddr);
288 ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.local_;
289 PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
290 pending_data_.accept_.local_ = NULL;
291 }
292
293 if (pending_data_.accept_.remote_) {
294 TInetAddr aAddr;
295 pj_sockaddr_in *ptr_sockaddr;
296
297 blank_sock_.RemoteName(aAddr);
298 ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.remote_;
299 PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
300 pending_data_.accept_.remote_ = NULL;
301 }
302
303 if (pending_data_.accept_.addrlen_) {
304 *pending_data_.accept_.addrlen_ = sizeof(pj_sockaddr_in);
305 pending_data_.accept_.addrlen_ = NULL;
306 }
307
308 return pjNewSock;
309}
310
311
312//
313// Completion callback.
314//
315void CIoqueueCallback::RunL()
316{
317 Type cur_type = type_;
318
319 type_ = TYPE_NONE;
320
321 if (cur_type == TYPE_READ) {
322 //
323 // Completion of asynchronous RecvFrom()
324 //
325
326 /* Clear op_key (save it to temp variable first!) */
327 pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
328 pending_data_.read_.op_key_ = NULL;
329
330 // Handle failure condition
331 if (iStatus != KErrNone) {
332 if (cb_.on_read_complete) {
333 cb_.on_read_complete( key_, op_key,
334 -PJ_RETURN_OS_ERROR(iStatus.Int()));
335 }
336 return;
337 }
338
339 HandleReadCompletion();
340
341 /* Call callback */
342 if (cb_.on_read_complete) {
343 cb_.on_read_complete(key_, op_key, aBufferPtr_.Length());
344 }
345
346 } else if (cur_type == TYPE_ACCEPT) {
347 //
348 // Completion of asynchronous Accept()
349 //
350
351 /* Clear op_key (save it to temp variable first!) */
352 pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
353 pending_data_.read_.op_key_ = NULL;
354
355 // Handle failure condition
356 if (iStatus != KErrNone) {
357 if (pending_data_.accept_.new_sock_)
358 *pending_data_.accept_.new_sock_ = PJ_INVALID_SOCKET;
359
360 if (cb_.on_accept_complete) {
361 cb_.on_accept_complete( key_, op_key, PJ_INVALID_SOCKET,
362 -PJ_RETURN_OS_ERROR(iStatus.Int()));
363 }
364 return;
365 }
366
367 CPjSocket *pjNewSock = HandleAcceptCompletion();
368
369 // Call callback.
370 if (cb_.on_accept_complete) {
371 cb_.on_accept_complete( key_, op_key, (pj_sock_t)pjNewSock,
372 PJ_SUCCESS);
373 }
374 }
375
376 ioqueue_->eventCount++;
377}
378
379//
380// CActive's DoCancel()
381//
382void CIoqueueCallback::DoCancel()
383{
384 if (type_ == TYPE_READ)
385 sock_->Socket().CancelRecv();
386 else if (type_ == TYPE_ACCEPT)
387 sock_->Socket().CancelAccept();
388
389 type_ = TYPE_NONE;
390}
391
392//
393// Cancel operation and call callback.
394//
395void CIoqueueCallback::CancelOperation(pj_ioqueue_op_key_t *op_key,
396 pj_ssize_t bytes_status)
397{
398 Type cur_type = type_;
399
400 Cancel();
401
402 if (cur_type == TYPE_READ) {
403 if (cb_.on_read_complete)
404 cb_.on_read_complete(key_, op_key, bytes_status);
405 } else if (cur_type == TYPE_ACCEPT)
406 ;
407}
408
409
410/////////////////////////////////////////////////////////////////////////////
411/*
412 * IO Queue key structure.
413 */
414struct pj_ioqueue_key_t
415{
416 CIoqueueCallback *cbObj;
417};
418
419
420/*
421 * Return the name of the ioqueue implementation.
422 */
423PJ_DEF(const char*) pj_ioqueue_name(void)
424{
425 return "ioqueue-symbian";
426}
427
428
429/*
430 * Create a new I/O Queue framework.
431 */
432PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
433 pj_size_t max_fd,
434 pj_ioqueue_t **p_ioqueue)
435{
436 pj_ioqueue_t *ioq;
437
438 PJ_UNUSED_ARG(max_fd);
439
Benny Prijonob2c96822007-05-03 13:31:21 +0000440 ioq = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_t);
Benny Prijonof260e462007-04-30 21:03:32 +0000441 *p_ioqueue = ioq;
442 return PJ_SUCCESS;
443}
444
445
446/*
447 * Destroy the I/O queue.
448 */
449PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioq )
450{
Benny Prijonob2c96822007-05-03 13:31:21 +0000451 PJ_UNUSED_ARG(ioq);
Benny Prijonof260e462007-04-30 21:03:32 +0000452 return PJ_SUCCESS;
453}
454
455
456/*
457 * Set the lock object to be used by the I/O Queue.
458 */
459PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioq,
460 pj_lock_t *lock,
461 pj_bool_t auto_delete )
462{
463 /* Don't really need lock for now */
464 PJ_UNUSED_ARG(ioq);
465
466 if (auto_delete) {
467 pj_lock_destroy(lock);
468 }
469
470 return PJ_SUCCESS;
471}
472
473
474/*
475 * Register a socket to the I/O queue framework.
476 */
477PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
478 pj_ioqueue_t *ioq,
479 pj_sock_t sock,
480 void *user_data,
481 const pj_ioqueue_callback *cb,
482 pj_ioqueue_key_t **p_key )
483{
484 pj_ioqueue_key_t *key;
485
Benny Prijonob2c96822007-05-03 13:31:21 +0000486 key = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_key_t);
Benny Prijonof260e462007-04-30 21:03:32 +0000487 key->cbObj = CIoqueueCallback::NewL(ioq, key, sock, cb, user_data);
488
489 *p_key = key;
490 return PJ_SUCCESS;
491}
492
493/*
494 * Unregister from the I/O Queue framework.
495 */
496PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
497{
498 if (key == NULL || key->cbObj == NULL)
499 return PJ_SUCCESS;
500
501 // Cancel pending async object
502 if (key->cbObj && key->cbObj->IsActive()) {
503 key->cbObj->Cancel();
504 }
505
506 // Close socket.
507 key->cbObj->get_pj_socket()->Socket().Close();
508 delete key->cbObj->get_pj_socket();
509
510 // Delete async object.
511 if (key->cbObj) {
512 delete key->cbObj;
513 key->cbObj = NULL;
514 }
515
516 return PJ_SUCCESS;
517}
518
519
520/*
521 * Get user data associated with an ioqueue key.
522 */
523PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
524{
525 return key->cbObj->get_user_data();
526}
527
528
529/*
530 * Set or change the user data to be associated with the file descriptor or
531 * handle or socket descriptor.
532 */
533PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
534 void *user_data,
535 void **old_data)
536{
537 if (old_data)
538 *old_data = key->cbObj->get_user_data();
539 key->cbObj->set_user_data(user_data);
540
541 return PJ_SUCCESS;
542}
543
544
545/*
546 * Initialize operation key.
547 */
548PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
549 pj_size_t size )
550{
Benny Prijonob2c96822007-05-03 13:31:21 +0000551 pj_bzero(op_key, size);
Benny Prijonof260e462007-04-30 21:03:32 +0000552}
553
554
555/*
556 * Check if operation is pending on the specified operation key.
557 */
558PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
559 pj_ioqueue_op_key_t *op_key )
560{
561 return key->cbObj->get_op_key()==op_key &&
562 key->cbObj->IsActive();
563}
564
565
566/*
567 * Post completion status to the specified operation key and call the
568 * appropriate callback.
569 */
570PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
571 pj_ioqueue_op_key_t *op_key,
572 pj_ssize_t bytes_status )
573{
574 if (pj_ioqueue_is_pending(key, op_key)) {
575 key->cbObj->CancelOperation(op_key, bytes_status);
576 }
577 return PJ_SUCCESS;
578}
579
580
581#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
582/**
583 * Instruct I/O Queue to accept incoming connection on the specified
584 * listening socket.
585 */
586PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
587 pj_ioqueue_op_key_t *op_key,
588 pj_sock_t *new_sock,
589 pj_sockaddr_t *local,
590 pj_sockaddr_t *remote,
591 int *addrlen )
592{
593
594 return key->cbObj->StartAccept(op_key, new_sock, local, remote, addrlen);
595}
596
597
598/*
599 * Initiate non-blocking socket connect.
600 */
601PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
602 const pj_sockaddr_t *addr,
603 int addrlen )
604{
605 PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL);
606
607 RSocket &rSock = key->cbObj->get_pj_socket()->Socket();
608 TInetAddr inetAddr;
609 PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr);
610 TRequestStatus reqStatus;
611
612 // We don't support async connect for now.
613 PJ_TODO(IOQUEUE_SUPPORT_ASYNC_CONNECT);
614
615 rSock.Connect(inetAddr, reqStatus);
616 User::WaitForRequest(reqStatus);
617
618 if (reqStatus == KErrNone)
619 return PJ_SUCCESS;
620
621 return PJ_RETURN_OS_ERROR(reqStatus.Int());
622}
623
624
625#endif /* PJ_HAS_TCP */
626
627/*
628 * Poll the I/O Queue for completed events.
629 */
630PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioq,
631 const pj_time_val *timeout)
632{
Benny Prijonob2c96822007-05-03 13:31:21 +0000633 /* Polling is not necessary on Symbian, since all async activities
634 * are registered to active scheduler.
635 */
636 PJ_UNUSED_ARG(ioq);
637 PJ_UNUSED_ARG(timeout);
638 return 0;
Benny Prijonof260e462007-04-30 21:03:32 +0000639}
640
641
642/*
643 * Instruct the I/O Queue to read from the specified handle.
644 */
645PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
646 pj_ioqueue_op_key_t *op_key,
647 void *buffer,
648 pj_ssize_t *length,
649 pj_uint32_t flags )
650{
651 // Clear flag
652 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
653 return key->cbObj->StartRead(op_key, buffer, length, flags, NULL, NULL);
654}
655
656
657/*
658 * This function behaves similarly as #pj_ioqueue_recv(), except that it is
659 * normally called for socket, and the remote address will also be returned
660 * along with the data.
661 */
662PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
663 pj_ioqueue_op_key_t *op_key,
664 void *buffer,
665 pj_ssize_t *length,
666 pj_uint32_t flags,
667 pj_sockaddr_t *addr,
668 int *addrlen)
669{
670 if (key->cbObj->IsActive())
671 return PJ_EBUSY;
672
673 // Clear flag
674 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
675 return key->cbObj->StartRead(op_key, buffer, length, flags, addr, addrlen);
676}
677
678
679/*
680 * Instruct the I/O Queue to write to the handle.
681 */
682PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
683 pj_ioqueue_op_key_t *op_key,
684 const void *data,
685 pj_ssize_t *length,
686 pj_uint32_t flags )
687{
688 TRequestStatus reqStatus;
689 TPtrC8 aBuffer((const TUint8*)data, (TInt)*length);
690 TSockXfrLength aLen;
691
692 PJ_UNUSED_ARG(op_key);
693
694 // Forcing pending operation is not supported.
695 PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
696
697 // Clear flag
698 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
699
700 key->cbObj->get_pj_socket()->Socket().Send(aBuffer, flags, reqStatus, aLen);
701 User::WaitForRequest(reqStatus);
702
703 if (reqStatus.Int() != KErrNone)
704 return PJ_RETURN_OS_ERROR(reqStatus.Int());
705
706 //At least in UIQ Emulator, aLen.Length() reports incorrect length
707 //for UDP (some newlc.com users seem to have reported this too).
708 //*length = aLen.Length();
709 return PJ_SUCCESS;
710}
711
712
713/*
714 * Instruct the I/O Queue to write to the handle.
715 */
716PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
717 pj_ioqueue_op_key_t *op_key,
718 const void *data,
719 pj_ssize_t *length,
720 pj_uint32_t flags,
721 const pj_sockaddr_t *addr,
722 int addrlen)
723{
724 TRequestStatus reqStatus;
725 TPtrC8 aBuffer;
726 TInetAddr inetAddr;
727 TSockXfrLength aLen;
728
729 PJ_UNUSED_ARG(op_key);
730
731 // Forcing pending operation is not supported.
732 PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
733
734 // Must be pj_sockaddr_in for now.
735 PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL);
736
737 // Clear flag
738 flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
739
740 aBuffer.Set((const TUint8*)data, (TInt)*length);
741 PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr);
742 CPjSocket *pjSock = key->cbObj->get_pj_socket();
743
744 pjSock->Socket().SendTo(aBuffer, inetAddr, 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