blob: 41d3e15979151ca5caacab3b5dd7f840da300518 [file] [log] [blame]
Nanang Izzuddin6c62bf42009-08-27 19:55:13 +00001/* $Id$ */
2/*
3 * Copyright (C) 2009 Teluu Inc. (http://www.teluu.com)
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/ssl_sock.h>
20#include <pj/compat/socket.h>
21#include <pj/assert.h>
22#include <pj/errno.h>
23#include <pj/pool.h>
24#include <pj/sock.h>
25#include <pj/string.h>
26
27#include "os_symbian.h"
28#include <securesocket.h>
29#include <x509cert.h>
30#include <e32des8.h>
31
32#define THIS_FILE "ssl_sock_symbian.cpp"
33
34typedef void (*CPjSSLSocket_cb)(int err, void *key);
35
36class CPjSSLSocketReader : public CActive
37{
38public:
39 static CPjSSLSocketReader *NewL(CSecureSocket &sock)
40 {
41 CPjSSLSocketReader *self = new (ELeave)
42 CPjSSLSocketReader(sock);
43 CleanupStack::PushL(self);
44 self->ConstructL();
45 CleanupStack::Pop(self);
46 return self;
47 }
48
49 ~CPjSSLSocketReader() {
50 Cancel();
51 }
52
53 /* Asynchronous read from the socket. */
54 int Read(CPjSSLSocket_cb cb, void *key, TPtr8 &data, TUint flags)
55 {
56 PJ_ASSERT_RETURN(!IsActive(), PJ_EBUSY);
57
58 cb_ = cb;
59 key_ = key;
60 sock_.RecvOneOrMore(data, iStatus, len_received_);
61 SetActive();
62
63 return PJ_EPENDING;
64 }
65
66private:
67 CSecureSocket &sock_;
68 CPjSSLSocket_cb cb_;
69 void *key_;
70 TSockXfrLength len_received_; /* not really useful? */
71
72 void DoCancel() {
73 sock_.CancelAll();
74 }
75
76 void RunL() {
77 (*cb_)(iStatus.Int(), key_);
78 }
79
80 CPjSSLSocketReader(CSecureSocket &sock) :
81 CActive(0), sock_(sock), cb_(NULL), key_(NULL)
82 {}
83
84 void ConstructL() {
85 CActiveScheduler::Add(this);
86 }
87};
88
89class CPjSSLSocket : public CActive
90{
91public:
92 enum ssl_state {
93 SSL_STATE_NULL,
94 SSL_STATE_CONNECTING,
95 SSL_STATE_HANDSHAKING,
96 SSL_STATE_ESTABLISHED
97 };
98
99 static CPjSSLSocket *NewL(const TDesC8 &ssl_proto) {
100 CPjSSLSocket *self = new (ELeave) CPjSSLSocket();
101 CleanupStack::PushL(self);
102 self->ConstructL(ssl_proto);
103 CleanupStack::Pop(self);
104 return self;
105 }
106
107 ~CPjSSLSocket() {
108 Cancel();
109 CleanupSubObjects();
110 }
111
112 int Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr,
113 const TInetAddr &rem_addr,
114 const TDesC8 &servername = TPtrC8(NULL,0));
115 int Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, TUint flags);
116 int SendSync(const TDesC8 &aDesc, TUint flags);
117
118 CPjSSLSocketReader* GetReader();
119 enum ssl_state GetState() const { return state_; }
120 const TInetAddr* GetLocalAddr() const { return &local_addr_; }
121 int GetCipher(TDes8 &cipher) const {
122 if (securesock_)
123 return securesock_->CurrentCipherSuite(cipher);
124 return KErrNotFound;
125 }
126
127private:
128 enum ssl_state state_;
129 pj_sock_t sock_;
130 CSecureSocket *securesock_;
131 bool is_connected_;
132 CPjSSLSocketReader *reader_;
133 TBuf<32> ssl_proto_;
134 TInetAddr rem_addr_;
135 TPtrC8 servername_;
136 TInetAddr local_addr_;
137 TSockXfrLength sent_len_;
138
139 CPjSSLSocket_cb cb_;
140 void *key_;
141
142 void DoCancel();
143 void RunL();
144
145 CPjSSLSocket() :
146 CActive(0), state_(SSL_STATE_NULL), sock_(PJ_INVALID_SOCKET),
147 securesock_(NULL),
148 is_connected_(false), reader_(NULL),
149 cb_(NULL), key_(NULL)
150 {}
151
152 void ConstructL(const TDesC8 &ssl_proto) {
153 ssl_proto_.Copy(ssl_proto);
154 CActiveScheduler::Add(this);
155 }
156
157 void CleanupSubObjects() {
158 delete reader_;
159 reader_ = NULL;
160 if (securesock_) {
161 securesock_->Close();
162 delete securesock_;
163 securesock_ = NULL;
164 }
165 if (sock_ != PJ_INVALID_SOCKET) {
166 delete (CPjSocket*)sock_;
167 sock_ = PJ_INVALID_SOCKET;
168 }
169 }
170};
171
172int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
173 const TInetAddr &local_addr,
174 const TInetAddr &rem_addr,
175 const TDesC8 &servername)
176{
177 pj_status_t status;
178
179 PJ_ASSERT_RETURN(state_ == SSL_STATE_NULL, PJ_EINVALIDOP);
180
181 status = pj_sock_socket(rem_addr.Family(), pj_SOCK_STREAM(), 0, &sock_);
182 if (status != PJ_SUCCESS)
183 return status;
184
185 RSocket &rSock = ((CPjSocket*)sock_)->Socket();
186
187 local_addr_ = local_addr;
188
189 if (!local_addr_.IsUnspecified()) {
190 TInt err = rSock.Bind(local_addr_);
191 if (err != KErrNone)
192 return PJ_RETURN_OS_ERROR(err);
193 }
194
195 cb_ = cb;
196 key_ = key;
197 rem_addr_ = rem_addr;
198 servername_.Set(servername);
199 state_ = SSL_STATE_CONNECTING;
200
201 rSock.Connect(rem_addr_, iStatus);
202 SetActive();
203
204 rSock.LocalName(local_addr_);
205
206 return PJ_EPENDING;
207}
208
209int CPjSSLSocket::Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc,
210 TUint flags)
211{
212 PJ_UNUSED_ARG(flags);
213
214 PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
215
216 if (IsActive())
217 return PJ_EBUSY;
218
219 cb_ = cb;
220 key_ = key;
221
222 securesock_->Send(aDesc, iStatus, sent_len_);
223 SetActive();
224
225 return PJ_EPENDING;
226}
227
228int CPjSSLSocket::SendSync(const TDesC8 &aDesc, TUint flags)
229{
230 PJ_UNUSED_ARG(flags);
231
232 PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
233
234 TRequestStatus reqStatus;
235 securesock_->Send(aDesc, reqStatus, sent_len_);
236 User::WaitForRequest(reqStatus);
237
238 return PJ_RETURN_OS_ERROR(reqStatus.Int());
239}
240
241CPjSSLSocketReader* CPjSSLSocket::GetReader()
242{
243 PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, NULL);
244
245 if (reader_)
246 return reader_;
247
248 TRAPD(err, reader_ = CPjSSLSocketReader::NewL(*securesock_));
249 if (err != KErrNone)
250 return NULL;
251
252 return reader_;
253}
254
255void CPjSSLSocket::DoCancel()
256{
257 /* Operation to be cancelled depends on current state */
258 switch (state_) {
259 case SSL_STATE_CONNECTING:
260 {
261 RSocket &rSock = ((CPjSocket*)sock_)->Socket();
262 rSock.CancelConnect();
263
264 CleanupSubObjects();
265
266 state_ = SSL_STATE_NULL;
267 }
268 break;
269 case SSL_STATE_HANDSHAKING:
270 {
271 securesock_->CancelHandshake();
272 securesock_->Close();
273
274 CleanupSubObjects();
275
276 state_ = SSL_STATE_NULL;
277 }
278 break;
279 case SSL_STATE_ESTABLISHED:
280 securesock_->CancelSend();
281 break;
282 default:
283 break;
284 }
285}
286
287void CPjSSLSocket::RunL()
288{
289 switch (state_) {
290 case SSL_STATE_CONNECTING:
291 if (iStatus != KErrNone) {
292 CleanupSubObjects();
293 state_ = SSL_STATE_NULL;
294 /* Dispatch connect failure notification */
295 if (cb_) (*cb_)(iStatus.Int(), key_);
296 } else {
297 RSocket &rSock = ((CPjSocket*)sock_)->Socket();
298
299 /* Get local addr */
300 rSock.LocalName(local_addr_);
301
302 /* Prepare and start handshake */
303 securesock_ = CSecureSocket::NewL(rSock, ssl_proto_);
304 securesock_->SetDialogMode(EDialogModeAttended);
305 if (servername_.Length() > 0)
306 securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
307 servername_);
308 securesock_->FlushSessionCache();
309 securesock_->StartClientHandshake(iStatus);
310 SetActive();
311 state_ = SSL_STATE_HANDSHAKING;
312 }
313 break;
314 case SSL_STATE_HANDSHAKING:
315 if (iStatus == KErrNone) {
316 state_ = SSL_STATE_ESTABLISHED;
317 } else {
318 state_ = SSL_STATE_NULL;
319 CleanupSubObjects();
320 }
321 /* Dispatch connect status notification */
322 if (cb_) (*cb_)(iStatus.Int(), key_);
323 break;
324 case SSL_STATE_ESTABLISHED:
325 /* Dispatch data sent notification */
326 if (cb_) (*cb_)(iStatus.Int(), key_);
327 break;
328 default:
329 pj_assert(0);
330 break;
331 }
332}
333
334typedef void (*CPjTimer_cb)(void *user_data);
335
336class CPjTimer : public CActive
337{
338public:
339 CPjTimer(const pj_time_val *delay, CPjTimer_cb cb, void *user_data) :
340 CActive(0), cb_(cb), user_data_(user_data)
341 {
342 CActiveScheduler::Add(this);
343
344 rtimer_.CreateLocal();
345 pj_int32_t interval = PJ_TIME_VAL_MSEC(*delay) * 1000;
346 if (interval < 0) {
347 interval = 0;
348 }
349 rtimer_.After(iStatus, interval);
350 SetActive();
351 }
352
353 ~CPjTimer() { Cancel(); }
354
355private:
356 RTimer rtimer_;
357 CPjTimer_cb cb_;
358 void *user_data_;
359
360 void RunL() { if (cb_) (*cb_)(user_data_); }
361 void DoCancel() { rtimer_.Cancel(); }
362};
363
364/*
365 * Structure of recv/read state.
366 */
367typedef struct read_state_t {
368 TPtr8 *read_buf;
369 TPtr8 *orig_buf;
370 pj_uint32_t flags;
371} read_state_t;
372
373/*
374 * Structure of send/write data.
375 */
376typedef struct write_data_t {
377 pj_size_t len;
378 pj_ioqueue_op_key_t *key;
379 pj_size_t data_len;
380 char data[1];
381} write_data_t;
382
383/*
384 * Structure of send/write state.
385 */
386typedef struct write_state_t {
387 char *buf;
388 pj_size_t max_len;
389 char *start;
390 pj_size_t len;
391 write_data_t *current_data;
392 TPtrC8 send_ptr;
393} write_state_t;
394
395/*
396 * Secure socket structure definition.
397 */
398struct pj_ssl_sock_t
399{
400 pj_ssl_sock_cb cb;
401 void *user_data;
402
403 pj_bool_t established;
404 write_state_t write_state;
405 read_state_t read_state;
406 CPjTimer *connect_timer;
407
408 CPjSSLSocket *sock;
409 int sock_af;
410 int sock_type;
411 pj_sockaddr local_addr;
412 pj_sockaddr rem_addr;
413
414 pj_ssl_sock_proto proto;
415 pj_time_val timeout;
416 pj_str_t ciphers;
417 pj_str_t servername;
418};
419
420
421/*
422 * Create SSL socket instance.
423 */
424PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
425 const pj_ssl_sock_param *param,
426 pj_ssl_sock_t **p_ssock)
427{
428 pj_ssl_sock_t *ssock;
429
430 PJ_ASSERT_RETURN(param->async_cnt == 1, PJ_EINVAL);
431 PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
432
433 /* Allocate secure socket */
434 ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
435
436 /* Allocate write buffer */
437 ssock->write_state.buf = (char*)pj_pool_alloc(pool,
438 param->send_buffer_size);
439 ssock->write_state.max_len = param->send_buffer_size;
440 ssock->write_state.start = ssock->write_state.buf;
441
442 /* Init secure socket */
443 ssock->sock_af = param->sock_af;
444 ssock->sock_type = param->sock_type;
445 ssock->cb = param->cb;
446 ssock->user_data = param->user_data;
447 pj_strdup_with_null(pool, &ssock->ciphers, &param->ciphers);
448 pj_strdup_with_null(pool, &ssock->servername, &param->servername);
449
450 /* Finally */
451 *p_ssock = ssock;
452
453 return PJ_SUCCESS;
454}
455
456/*
457 * Set SSL socket credential.
458 */
459PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
460 pj_ssl_sock_t *ssock,
461 pj_pool_t *pool,
462 const pj_ssl_cert_t *cert)
463{
464 PJ_UNUSED_ARG(ssock);
465 PJ_UNUSED_ARG(pool);
466 PJ_UNUSED_ARG(cert);
467 return PJ_ENOTSUP;
468}
469
470/*
471 * Close the SSL socket.
472 */
473PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
474{
475 PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
476
477 delete ssock->connect_timer;
478 ssock->connect_timer = NULL;
479
480 delete ssock->sock;
481 ssock->sock = NULL;
482
483 delete ssock->read_state.read_buf;
484 delete ssock->read_state.orig_buf;
485 ssock->read_state.read_buf = NULL;
486 ssock->read_state.orig_buf = NULL;
487
488 return PJ_SUCCESS;
489}
490
491
492/*
493 * Associate arbitrary data with the SSL socket.
494 */
495PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data (pj_ssl_sock_t *ssock,
496 void *user_data)
497{
498 PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
499
500 ssock->user_data = user_data;
501
502 return PJ_SUCCESS;
503}
504
505
506/*
507 * Retrieve the user data previously associated with this SSL
508 * socket.
509 */
510PJ_DEF(void*) pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
511{
512 PJ_ASSERT_RETURN(ssock, NULL);
513
514 return ssock->user_data;
515}
516
517
518/*
519 * Retrieve the local address and port used by specified SSL socket.
520 */
521PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
522 pj_ssl_sock_info *info)
523{
524 const char *cipher_names[0x1B] = {
525 "TLS_RSA_WITH_NULL_MD5",
526 "TLS_RSA_WITH_NULL_SHA",
527 "TLS_RSA_EXPORT_WITH_RC4_40_MD5",
528 "TLS_RSA_WITH_RC4_128_MD5",
529 "TLS_RSA_WITH_RC4_128_SHA",
530 "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
531 "TLS_RSA_WITH_IDEA_CBC_SHA",
532 "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
533 "TLS_RSA_WITH_DES_CBC_SHA",
534 "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
535 "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
536 "TLS_DH_DSS_WITH_DES_CBC_SHA",
537 "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",
538 "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
539 "TLS_DH_RSA_WITH_DES_CBC_SHA",
540 "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",
541 "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
542 "TLS_DHE_DSS_WITH_DES_CBC_SHA",
543 "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
544 "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
545 "TLS_DHE_RSA_WITH_DES_CBC_SHA",
546 "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
547 "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
548 "TLS_DH_anon_WITH_RC4_128_MD5",
549 "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
550 "TLS_DH_anon_WITH_DES_CBC_SHA",
551 "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"
552 };
553
554 PJ_ASSERT_RETURN(ssock && info, PJ_EINVAL);
555
556 pj_bzero(info, sizeof(*info));
557
558 info->established = ssock->established;
559
560 /* Local address */
561 if (ssock->sock) {
562 const TInetAddr* local_addr_ = ssock->sock->GetLocalAddr();
563 int addrlen = sizeof(pj_sockaddr);
564 pj_status_t status;
565
566 status = PjSymbianOS::Addr2pj(*local_addr_, info->local_addr, &addrlen);
567 if (status != PJ_SUCCESS)
568 return status;
569 } else {
570 pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
571 }
572
573 /* Remote address */
574 pj_sockaddr_cp((pj_sockaddr_t*)&info->remote_addr,
575 (pj_sockaddr_t*)&ssock->rem_addr);
576
577 /* Cipher suite */
578 if (info->established) {
579 TBuf8<8> cipher;
580 if (ssock->sock->GetCipher(cipher) == KErrNone) {
581 TLex8 lex(cipher);
582 TUint cipher_code = cipher[1];
583 if (cipher_code>=1 && cipher_code<=0x1B)
584 info->cipher = pj_str((char*)cipher_names[cipher_code-1]);
585 }
586 }
587
588 /* Protocol */
589 info->proto = ssock->proto;
590
591 return PJ_SUCCESS;
592}
593
594
595/*
596 * Starts read operation on this SSL socket.
597 */
598PJ_DEF(pj_status_t) pj_ssl_sock_start_read (pj_ssl_sock_t *ssock,
599 pj_pool_t *pool,
600 unsigned buff_size,
601 pj_uint32_t flags)
602{
603 PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
604 PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
605
606 /* Reading is already started */
607 if (ssock->read_state.orig_buf) {
608 return PJ_SUCCESS;
609 }
610
611 void *readbuf[1];
612 readbuf[0] = pj_pool_alloc(pool, buff_size);
613 return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
614}
615
616static void read_cb(int err, void *key)
617{
618 pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
619 pj_status_t status;
620
621 status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
622
623 /* Check connection status */
624 if (err == KErrEof || !PjSymbianOS::Instance()->IsConnectionUp() ||
625 !ssock->established)
626 {
627 status = PJ_EEOF;
628 }
629
630 /* Notify data arrival */
631 if (ssock->cb.on_data_read) {
632 pj_size_t remainder = 0;
633 char *data = (char*)ssock->read_state.orig_buf->Ptr();
634 pj_size_t data_len = ssock->read_state.read_buf->Length() +
635 ssock->read_state.read_buf->Ptr() -
636 ssock->read_state.orig_buf->Ptr();
637
638 if (data_len > 0) {
639 /* Notify received data */
640 pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, data, data_len,
641 status, &remainder);
642 if (!ret) {
643 /* We've been destroyed */
644 return;
645 }
646
647 /* Calculate available data for next READ operation */
648 if (remainder > 0) {
649 pj_size_t data_maxlen = ssock->read_state.orig_buf->MaxLength();
650
651 /* There is some data left unconsumed by application, we give
652 * smaller buffer for next READ operation.
653 */
654 ssock->read_state.read_buf->Set((TUint8*)data+remainder, 0,
655 data_maxlen - remainder);
656 } else {
657 /* Give all buffer for next READ operation.
658 */
659 ssock->read_state.read_buf->Set(*ssock->read_state.orig_buf);
660 }
661 }
662 }
663
664 if (status == PJ_SUCCESS) {
665 /* Perform the "next" READ operation */
666 CPjSSLSocketReader *reader = ssock->sock->GetReader();
667 ssock->read_state.read_buf->SetLength(0);
668 status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf,
669 ssock->read_state.flags);
670 if (status != PJ_EPENDING) {
671 /* Notify error */
672 (*ssock->cb.on_data_read)(ssock, NULL, 0, status, NULL);
673 }
674 }
675
676 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
677 /* Connection closed or something goes wrong */
678 delete ssock->read_state.read_buf;
679 delete ssock->read_state.orig_buf;
680 ssock->read_state.read_buf = NULL;
681 ssock->read_state.orig_buf = NULL;
682 ssock->established = PJ_FALSE;
683 }
684}
685
686/*
687 * Same as #pj_ssl_sock_start_read(), except that the application
688 * supplies the buffers for the read operation so that the acive socket
689 * does not have to allocate the buffers.
690 */
691PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
692 pj_pool_t *pool,
693 unsigned buff_size,
694 void *readbuf[],
695 pj_uint32_t flags)
696{
697 PJ_ASSERT_RETURN(ssock && buff_size && readbuf, PJ_EINVAL);
698 PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
699
700 /* Return failure if access point is marked as down by app. */
701 PJ_SYMBIAN_CHECK_CONNECTION();
702
703 /* Reading is already started */
704 if (ssock->read_state.orig_buf) {
705 return PJ_SUCCESS;
706 }
707
708 PJ_UNUSED_ARG(pool);
709
710 /* Get reader instance */
711 CPjSSLSocketReader *reader = ssock->sock->GetReader();
712 if (!reader)
713 return PJ_ENOMEM;
714
715 /* We manage two buffer pointers here:
716 * 1. orig_buf keeps the orginal buffer address (and its max length).
717 * 2. read_buf provides buffer for READ operation, mind that there may be
718 * some remainder data left by application.
719 */
720 ssock->read_state.read_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
721 ssock->read_state.orig_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
722 ssock->read_state.flags = flags;
723
724 pj_status_t status;
725 status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf,
726 ssock->read_state.flags);
727
728 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
729 delete ssock->read_state.read_buf;
730 delete ssock->read_state.orig_buf;
731 ssock->read_state.read_buf = NULL;
732 ssock->read_state.orig_buf = NULL;
733
734 return status;
735 }
736
737 return PJ_SUCCESS;
738}
739
740/*
741 * Same as pj_ssl_sock_start_read(), except that this function is used
742 * only for datagram sockets, and it will trigger \a on_data_recvfrom()
743 * callback instead.
744 */
745PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
746 pj_pool_t *pool,
747 unsigned buff_size,
748 pj_uint32_t flags)
749{
750 PJ_UNUSED_ARG(ssock);
751 PJ_UNUSED_ARG(pool);
752 PJ_UNUSED_ARG(buff_size);
753 PJ_UNUSED_ARG(flags);
754 return PJ_ENOTSUP;
755}
756
757/*
758 * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
759 * operation takes the buffer from the argument rather than creating
760 * new ones.
761 */
762PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
763 pj_pool_t *pool,
764 unsigned buff_size,
765 void *readbuf[],
766 pj_uint32_t flags)
767{
768 PJ_UNUSED_ARG(ssock);
769 PJ_UNUSED_ARG(pool);
770 PJ_UNUSED_ARG(buff_size);
771 PJ_UNUSED_ARG(readbuf);
772 PJ_UNUSED_ARG(flags);
773 return PJ_ENOTSUP;
774}
775
776static void send_cb(int err, void *key)
777{
778 pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
779 write_state_t *st = &ssock->write_state;
780
781 /* Check connection status */
782 if (err != KErrNone || !PjSymbianOS::Instance()->IsConnectionUp() ||
783 !ssock->established)
784 {
785 ssock->established = PJ_FALSE;
786 return;
787 }
788
789 /* Remove sent data from buffer */
790 st->start += st->current_data->len;
791 st->len -= st->current_data->len;
792
793 /* Reset current outstanding send */
794 st->current_data = NULL;
795
796 /* Let's check if there is pending data to send */
797 if (st->len) {
798 write_data_t *wdata = (write_data_t*)st->start;
799 pj_status_t status;
800
801 st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
802 st->current_data = wdata;
803 status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, 0);
804 if (status != PJ_EPENDING) {
805 ssock->established = PJ_FALSE;
806 st->len = 0;
807 return;
808 }
809 }
810}
811
812/*
813 * Send data using the socket.
814 */
815PJ_DEF(pj_status_t) pj_ssl_sock_send (pj_ssl_sock_t *ssock,
816 pj_ioqueue_op_key_t *send_key,
817 const void *data,
818 pj_ssize_t *size,
819 unsigned flags)
820{
821 PJ_CHECK_STACK();
822 PJ_ASSERT_RETURN(ssock && data && size, PJ_EINVAL);
823 PJ_ASSERT_RETURN(ssock->write_state.max_len == 0 ||
824 ssock->write_state.max_len >= (pj_size_t)*size,
825 PJ_ETOOSMALL);
826
827 /* Check connection status */
828 if (!PjSymbianOS::Instance()->IsConnectionUp() || !ssock->established)
829 {
830 ssock->established = PJ_FALSE;
831 return PJ_ECANCELLED;
832 }
833
834 write_state_t *st = &ssock->write_state;
835
836 /* Synchronous mode */
837 if (st->max_len == 0) {
838 st->send_ptr.Set((TUint8*)data, (TInt)*size);
839 return ssock->sock->SendSync(st->send_ptr, flags);
840 }
841
842 /* CSecureSocket only allows one outstanding send operation, so
843 * we use buffering mechanism to allow application to perform send
844 * operations at any time.
845 */
846
847 pj_size_t avail_len = st->max_len - st->len;
848 pj_size_t needed_len = *size + sizeof(write_data_t) - 1;
849
850 /* Align needed_len to be multiplication of 4 */
851 needed_len = ((needed_len + 3) >> 2) << 2;
852
853 /* Block until there is buffer slot available! */
854 while (needed_len >= avail_len) {
855 pj_symbianos_poll(-1, -1);
856 avail_len = st->max_len - st->len;
857 }
858
859 /* Ok, make sure the new data will not get wrapped */
860 if (st->start + st->len + needed_len > st->buf + st->max_len) {
861 /* Align buffer left */
862 pj_memmove(st->buf, st->start, st->len);
863 st->start = st->buf;
864 }
865
866 /* Push back the send data into the buffer */
867 write_data_t *wdata = (write_data_t*)(st->start + st->len);
868
869 wdata->len = needed_len;
870 wdata->key = send_key;
871 wdata->data_len = (pj_size_t)*size;
872 pj_memcpy(wdata->data, data, *size);
873 st->len += needed_len;
874
875 /* If no outstanding send, send it */
876 if (st->current_data == NULL) {
877 pj_status_t status;
878
879 wdata = (write_data_t*)st->start;
880 st->current_data = wdata;
881 st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
882 status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, flags);
883
884 if (status != PJ_EPENDING) {
885 *size = -status;
886 return status;
887 }
888 }
889
890 return PJ_SUCCESS;
891}
892
893/*
894 * Send datagram using the socket.
895 */
896PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
897 pj_ioqueue_op_key_t *send_key,
898 const void *data,
899 pj_ssize_t *size,
900 unsigned flags,
901 const pj_sockaddr_t *addr,
902 int addr_len)
903{
904 PJ_UNUSED_ARG(ssock);
905 PJ_UNUSED_ARG(send_key);
906 PJ_UNUSED_ARG(data);
907 PJ_UNUSED_ARG(size);
908 PJ_UNUSED_ARG(flags);
909 PJ_UNUSED_ARG(addr);
910 PJ_UNUSED_ARG(addr_len);
911 return PJ_ENOTSUP;
912}
913
914/*
915 * Starts asynchronous socket accept() operations on this SSL socket.
916 */
917PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
918 pj_pool_t *pool,
919 const pj_sockaddr_t *local_addr,
920 int addr_len)
921{
922 PJ_UNUSED_ARG(ssock);
923 PJ_UNUSED_ARG(pool);
924 PJ_UNUSED_ARG(local_addr);
925 PJ_UNUSED_ARG(addr_len);
926
927 return PJ_ENOTSUP;
928}
929
930static void connect_cb(int err, void *key)
931{
932 pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
933 pj_status_t status;
934
935 if (ssock->connect_timer) {
936 delete ssock->connect_timer;
937 ssock->connect_timer = NULL;
938 }
939
940 status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
941 if (status == PJ_SUCCESS) {
942 ssock->established = PJ_TRUE;
943 } else {
944 delete ssock->sock;
945 ssock->sock = NULL;
946 }
947
948 if (ssock->cb.on_connect_complete) {
949 pj_bool_t ret = (*ssock->cb.on_connect_complete)(ssock, status);
950 if (!ret) {
951 /* We've been destroyed */
952 return;
953 }
954 }
955}
956
957static void connect_timer_cb(void *key)
958{
959 connect_cb(KErrTimedOut, key);
960}
961
962/*
963 * Starts asynchronous socket connect() operation and SSL/TLS handshaking
964 * for this socket. Once the connection is done (either successfully or not),
965 * the \a on_connect_complete() callback will be called.
966 */
967PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
968 pj_pool_t *pool,
969 const pj_sockaddr_t *localaddr,
970 const pj_sockaddr_t *remaddr,
971 int addr_len)
972{
973 CPjSSLSocket *sock = NULL;
974 pj_status_t status;
975
976 PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
977 PJ_EINVAL);
978
979 /* Check connection status */
980 PJ_SYMBIAN_CHECK_CONNECTION();
981
982 if (ssock->sock != NULL) {
983 CPjSSLSocket::ssl_state state = ssock->sock->GetState();
984 switch (state) {
985 case CPjSSLSocket::SSL_STATE_ESTABLISHED:
986 return PJ_SUCCESS;
987 default:
988 return PJ_EPENDING;
989 }
990 }
991
992 /* Set SSL protocol */
993 TPtrC8 proto;
994
995 if (ssock->proto == PJ_SSL_SOCK_PROTO_DEFAULT)
996 ssock->proto = PJ_SSL_SOCK_PROTO_TLS1;
997
998 /* CSecureSocket only support TLS1.0 and SSL3.0 */
999 switch(ssock->proto) {
1000 case PJ_SSL_SOCK_PROTO_TLS1:
1001 proto.Set((const TUint8*)"TLS1.0", 6);
1002 break;
1003 case PJ_SSL_SOCK_PROTO_SSL3:
1004 proto.Set((const TUint8*)"SSL3.0", 6);
1005 break;
1006 default:
1007 return PJ_ENOTSUP;
1008 }
1009
1010 /* Prepare addresses */
1011 TInetAddr localaddr_, remaddr_;
1012 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)localaddr, addr_len,
1013 localaddr_);
1014 if (status != PJ_SUCCESS)
1015 return status;
1016
1017 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)remaddr, addr_len,
1018 remaddr_);
1019 if (status != PJ_SUCCESS)
1020 return status;
1021
1022 pj_sockaddr_cp((pj_sockaddr_t*)&ssock->rem_addr, remaddr);
1023
1024 /* Init SSL engine */
1025 TRAPD(err, sock = CPjSSLSocket::NewL(proto));
1026 if (err != KErrNone)
1027 return PJ_ENOMEM;
1028
1029 if (ssock->timeout.sec != 0 || ssock->timeout.msec != 0) {
1030 ssock->connect_timer = new CPjTimer(&ssock->timeout,
1031 &connect_timer_cb, ssock);
1032 }
1033
1034 /* Convert server name to Symbian descriptor */
1035 TPtrC8 servername_((TUint8*)ssock->servername.ptr,
1036 ssock->servername.slen);
1037
1038 /* Try to connect */
1039 status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
1040 servername_);
1041 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
1042 delete sock;
1043 return status;
1044 }
1045
1046 ssock->sock = sock;
1047 return status;
1048}
1049