~ubuntu-branches/ubuntu/wily/sflphone/wily-proposed

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjlib/src/pj/ssl_sock_symbian.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: ssl_sock_symbian.cpp 3999 2012-03-30 07:10:13Z bennylp $ */
 
2
/* 
 
3
 * Copyright (C) 2009-2011 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/math.h>
 
24
#include <pj/pool.h>
 
25
#include <pj/sock.h>
 
26
#include <pj/string.h>
 
27
 
 
28
#include "os_symbian.h"
 
29
#include <securesocket.h>
 
30
#include <x509cert.h>
 
31
#include <e32des8.h>
 
32
 
 
33
#define THIS_FILE "ssl_sock_symbian.cpp"
 
34
 
 
35
 
 
36
/* Cipher name structure */
 
37
typedef struct cipher_name_t {
 
38
    pj_ssl_cipher    cipher;
 
39
    const char      *name;
 
40
} cipher_name_t;
 
41
 
 
42
/* Cipher name constants */
 
43
static cipher_name_t cipher_names[] =
 
44
{
 
45
    {PJ_TLS_NULL_WITH_NULL_NULL,               "NULL"},
 
46
 
 
47
    /* TLS/SSLv3 */
 
48
    {PJ_TLS_RSA_WITH_NULL_MD5,                 "TLS_RSA_WITH_NULL_MD5"},
 
49
    {PJ_TLS_RSA_WITH_NULL_SHA,                 "TLS_RSA_WITH_NULL_SHA"},
 
50
    {PJ_TLS_RSA_WITH_NULL_SHA256,              "TLS_RSA_WITH_NULL_SHA256"},
 
51
    {PJ_TLS_RSA_WITH_RC4_128_MD5,              "TLS_RSA_WITH_RC4_128_MD5"},
 
52
    {PJ_TLS_RSA_WITH_RC4_128_SHA,              "TLS_RSA_WITH_RC4_128_SHA"},
 
53
    {PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA,         "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
 
54
    {PJ_TLS_RSA_WITH_AES_128_CBC_SHA,          "TLS_RSA_WITH_AES_128_CBC_SHA"},
 
55
    {PJ_TLS_RSA_WITH_AES_256_CBC_SHA,          "TLS_RSA_WITH_AES_256_CBC_SHA"},
 
56
    {PJ_TLS_RSA_WITH_AES_128_CBC_SHA256,       "TLS_RSA_WITH_AES_128_CBC_SHA256"},
 
57
    {PJ_TLS_RSA_WITH_AES_256_CBC_SHA256,       "TLS_RSA_WITH_AES_256_CBC_SHA256"},
 
58
    {PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,      "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
 
59
    {PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,      "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
 
60
    {PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,     "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
 
61
    {PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,     "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
 
62
    {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA,       "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
 
63
    {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA,       "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
 
64
    {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA,      "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
 
65
    {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,      "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
 
66
    {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA,       "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
 
67
    {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA,       "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
 
68
    {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA,      "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
 
69
    {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,      "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
 
70
    {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256,    "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
 
71
    {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256,    "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
 
72
    {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,   "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
 
73
    {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,   "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
 
74
    {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256,    "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
 
75
    {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256,    "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
 
76
    {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,   "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
 
77
    {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,   "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
 
78
    {PJ_TLS_DH_anon_WITH_RC4_128_MD5,          "TLS_DH_anon_WITH_RC4_128_MD5"},
 
79
    {PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,     "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
 
80
    {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA,      "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
 
81
    {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA,      "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
 
82
    {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256,   "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
 
83
    {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256,   "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
 
84
 
 
85
    /* TLS (deprecated) */
 
86
    {PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5,        "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
 
87
    {PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,    "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
 
88
    {PJ_TLS_RSA_WITH_IDEA_CBC_SHA,             "TLS_RSA_WITH_IDEA_CBC_SHA"},
 
89
    {PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,     "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
 
90
    {PJ_TLS_RSA_WITH_DES_CBC_SHA,              "TLS_RSA_WITH_DES_CBC_SHA"},
 
91
    {PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,  "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
 
92
    {PJ_TLS_DH_DSS_WITH_DES_CBC_SHA,           "TLS_DH_DSS_WITH_DES_CBC_SHA"},
 
93
    {PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,  "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
 
94
    {PJ_TLS_DH_RSA_WITH_DES_CBC_SHA,           "TLS_DH_RSA_WITH_DES_CBC_SHA"},
 
95
    {PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
 
96
    {PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA,          "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
 
97
    {PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
 
98
    {PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA,          "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
 
99
    {PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5,    "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
 
100
    {PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
 
101
    {PJ_TLS_DH_anon_WITH_DES_CBC_SHA,          "TLS_DH_anon_WITH_DES_CBC_SHA"},
 
102
 
 
103
    /* SSLv3 */
 
104
    {PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA,        "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
 
105
    {PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
 
106
    {PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA,     "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
 
107
 
 
108
    /* SSLv2 */
 
109
    {PJ_SSL_CK_RC4_128_WITH_MD5,               "SSL_CK_RC4_128_WITH_MD5"},
 
110
    {PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5,      "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
 
111
    {PJ_SSL_CK_RC2_128_CBC_WITH_MD5,           "SSL_CK_RC2_128_CBC_WITH_MD5"},
 
112
    {PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5,  "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
 
113
    {PJ_SSL_CK_IDEA_128_CBC_WITH_MD5,          "SSL_CK_IDEA_128_CBC_WITH_MD5"},
 
114
    {PJ_SSL_CK_DES_64_CBC_WITH_MD5,            "SSL_CK_DES_64_CBC_WITH_MD5"},
 
115
    {PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5,      "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
 
116
};
 
117
 
 
118
 
 
119
/* Get cipher name string */
 
120
static const char* get_cipher_name(pj_ssl_cipher cipher)
 
121
{
 
122
    unsigned i, n;
 
123
 
 
124
    n = PJ_ARRAY_SIZE(cipher_names);
 
125
    for (i = 0; i < n; ++i) {
 
126
       if (cipher == cipher_names[i].cipher)
 
127
           return cipher_names[i].name;
 
128
    }
 
129
 
 
130
    return "CIPHER_UNKNOWN";
 
131
}
 
132
 
 
133
typedef void (*CPjSSLSocket_cb)(int err, void *key);
 
134
 
 
135
class CPjSSLSocketReader : public CActive
 
136
{
 
137
public:
 
138
    static CPjSSLSocketReader *NewL(CSecureSocket &sock) 
 
139
    {
 
140
        CPjSSLSocketReader *self = new (ELeave) 
 
141
                                   CPjSSLSocketReader(sock);
 
142
        CleanupStack::PushL(self);
 
143
        self->ConstructL();
 
144
        CleanupStack::Pop(self);
 
145
        return self;
 
146
    }
 
147
 
 
148
    ~CPjSSLSocketReader() {
 
149
        Cancel();
 
150
    }
 
151
 
 
152
    /* Asynchronous read from the socket. */
 
153
    int Read(CPjSSLSocket_cb cb, void *key, TPtr8 &data, TUint flags)
 
154
    {
 
155
        PJ_ASSERT_RETURN(!IsActive(), PJ_EBUSY);
 
156
        
 
157
        cb_ = cb;
 
158
        key_ = key;
 
159
        sock_.RecvOneOrMore(data, iStatus, len_received_);
 
160
        SetActive();
 
161
        
 
162
        return PJ_EPENDING;
 
163
    }
 
164
 
 
165
private:
 
166
    CSecureSocket       &sock_;
 
167
    CPjSSLSocket_cb      cb_;
 
168
    void                *key_;
 
169
    TSockXfrLength       len_received_; /* not really useful? */
 
170
 
 
171
    void DoCancel() {
 
172
        sock_.CancelAll();
 
173
    }
 
174
    
 
175
    void RunL() {
 
176
        (*cb_)(iStatus.Int(), key_);
 
177
    }
 
178
 
 
179
    CPjSSLSocketReader(CSecureSocket &sock) : 
 
180
        CActive(0), sock_(sock), cb_(NULL), key_(NULL) 
 
181
    {}
 
182
    
 
183
    void ConstructL() {
 
184
        CActiveScheduler::Add(this);
 
185
    }
 
186
};
 
187
 
 
188
class CPjSSLSocket : public CActive
 
189
{
 
190
public:
 
191
    enum ssl_state {
 
192
        SSL_STATE_NULL,
 
193
        SSL_STATE_CONNECTING,
 
194
        SSL_STATE_HANDSHAKING,
 
195
        SSL_STATE_ESTABLISHED
 
196
    };
 
197
    
 
198
    static CPjSSLSocket *NewL(const TDesC8 &ssl_proto,
 
199
                              pj_qos_type qos_type,
 
200
                              const pj_qos_params &qos_params) 
 
201
    {
 
202
        CPjSSLSocket *self = new (ELeave) CPjSSLSocket(qos_type, qos_params);
 
203
        CleanupStack::PushL(self);
 
204
        self->ConstructL(ssl_proto);
 
205
        CleanupStack::Pop(self);
 
206
        return self;
 
207
    }
 
208
 
 
209
    ~CPjSSLSocket() {
 
210
        Cancel();
 
211
        CleanupSubObjects();
 
212
    }
 
213
 
 
214
    int Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr, 
 
215
                const TInetAddr &rem_addr, 
 
216
                const TDesC8 &servername = TPtrC8(NULL,0),
 
217
                const TDesC8 &ciphers = TPtrC8(NULL,0));
 
218
    int Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, TUint flags);
 
219
    int SendSync(const TDesC8 &aDesc, TUint flags);
 
220
 
 
221
    CPjSSLSocketReader* GetReader();
 
222
    enum ssl_state GetState() const { return state_; }
 
223
    const TInetAddr* GetLocalAddr() const { return &local_addr_; }
 
224
    int GetCipher(TDes8 &cipher) const {
 
225
        if (securesock_)
 
226
            return securesock_->CurrentCipherSuite(cipher);
 
227
        return KErrNotFound;
 
228
    }
 
229
    const CX509Certificate *GetPeerCert() {
 
230
        if (securesock_)
 
231
            return securesock_->ServerCert();
 
232
        return NULL;
 
233
    }
 
234
 
 
235
private:
 
236
    enum ssl_state       state_;
 
237
    pj_sock_t            sock_;
 
238
    CSecureSocket       *securesock_;
 
239
    bool                 is_connected_;
 
240
    
 
241
    pj_qos_type          qos_type_;
 
242
    pj_qos_params        qos_params_;
 
243
                              
 
244
    CPjSSLSocketReader  *reader_;
 
245
    TBuf<32>             ssl_proto_;
 
246
    TInetAddr            rem_addr_;
 
247
    TPtrC8               servername_;
 
248
    TPtrC8               ciphers_;
 
249
    TInetAddr            local_addr_;
 
250
    TSockXfrLength       sent_len_;
 
251
 
 
252
    CPjSSLSocket_cb      cb_;
 
253
    void                *key_;
 
254
    
 
255
    void DoCancel();
 
256
    void RunL();
 
257
 
 
258
    CPjSSLSocket(pj_qos_type qos_type, const pj_qos_params &qos_params) :
 
259
        CActive(0), state_(SSL_STATE_NULL), sock_(PJ_INVALID_SOCKET), 
 
260
        securesock_(NULL), is_connected_(false),
 
261
        qos_type_(qos_type), qos_params_(qos_params),
 
262
        reader_(NULL),  cb_(NULL), key_(NULL)
 
263
    {}
 
264
    
 
265
    void ConstructL(const TDesC8 &ssl_proto) {
 
266
        ssl_proto_.Copy(ssl_proto);
 
267
        CActiveScheduler::Add(this);
 
268
    }
 
269
 
 
270
    void CleanupSubObjects() {
 
271
        delete reader_;
 
272
        reader_ = NULL;
 
273
        if (securesock_) {
 
274
            if (state_ == SSL_STATE_ESTABLISHED)
 
275
                securesock_->Close();
 
276
            delete securesock_;
 
277
            securesock_ = NULL;
 
278
        }
 
279
        if (sock_ != PJ_INVALID_SOCKET) {
 
280
            pj_sock_close(sock_);
 
281
            sock_ = PJ_INVALID_SOCKET;
 
282
        }           
 
283
    }
 
284
};
 
285
 
 
286
int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key, 
 
287
                          const TInetAddr &local_addr, 
 
288
                          const TInetAddr &rem_addr,
 
289
                          const TDesC8 &servername,
 
290
                          const TDesC8 &ciphers)
 
291
{
 
292
    pj_status_t status;
 
293
    
 
294
    PJ_ASSERT_RETURN(state_ == SSL_STATE_NULL, PJ_EINVALIDOP);
 
295
    
 
296
    status = pj_sock_socket(rem_addr.Family(), pj_SOCK_STREAM(), 0, &sock_);
 
297
    if (status != PJ_SUCCESS)
 
298
        return status;
 
299
 
 
300
    // Apply QoS
 
301
    status = pj_sock_apply_qos2(sock_, qos_type_, &qos_params_, 
 
302
                                2,  THIS_FILE, NULL);
 
303
    
 
304
    RSocket &rSock = ((CPjSocket*)sock_)->Socket();
 
305
 
 
306
    local_addr_ = local_addr;
 
307
    
 
308
    if (!local_addr_.IsUnspecified()) {
 
309
        TInt err = rSock.Bind(local_addr_);
 
310
        if (err != KErrNone)
 
311
            return PJ_RETURN_OS_ERROR(err);
 
312
    }
 
313
    
 
314
    cb_ = cb;
 
315
    key_ = key;
 
316
    rem_addr_ = rem_addr;
 
317
    
 
318
    /* Note: the following members only keep the pointer, not the data */
 
319
    servername_.Set(servername);
 
320
    ciphers_.Set(ciphers);
 
321
 
 
322
    rSock.Connect(rem_addr_, iStatus);
 
323
    SetActive();
 
324
    state_ = SSL_STATE_CONNECTING;
 
325
    
 
326
    rSock.LocalName(local_addr_);
 
327
 
 
328
    return PJ_EPENDING;
 
329
}
 
330
 
 
331
int CPjSSLSocket::Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, 
 
332
                       TUint flags)
 
333
{
 
334
    PJ_UNUSED_ARG(flags);
 
335
 
 
336
    PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
 
337
    
 
338
    if (IsActive())
 
339
        return PJ_EBUSY;
 
340
    
 
341
    cb_ = cb;
 
342
    key_ = key;
 
343
    
 
344
    securesock_->Send(aDesc, iStatus, sent_len_);
 
345
    SetActive();
 
346
    
 
347
    return PJ_EPENDING;
 
348
}
 
349
 
 
350
int CPjSSLSocket::SendSync(const TDesC8 &aDesc, TUint flags)
 
351
{
 
352
    PJ_UNUSED_ARG(flags);
 
353
 
 
354
    PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
 
355
    
 
356
    TRequestStatus reqStatus;
 
357
    securesock_->Send(aDesc, reqStatus, sent_len_);
 
358
    User::WaitForRequest(reqStatus);
 
359
    
 
360
    return PJ_RETURN_OS_ERROR(reqStatus.Int());
 
361
}
 
362
 
 
363
CPjSSLSocketReader* CPjSSLSocket::GetReader()
 
364
{
 
365
    PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, NULL);
 
366
    
 
367
    if (reader_)
 
368
        return reader_;
 
369
    
 
370
    TRAPD(err,  reader_ = CPjSSLSocketReader::NewL(*securesock_));
 
371
    if (err != KErrNone)
 
372
        return NULL;
 
373
    
 
374
    return reader_;
 
375
}
 
376
 
 
377
void CPjSSLSocket::DoCancel()
 
378
{
 
379
    /* Operation to be cancelled depends on current state */
 
380
    switch (state_) {
 
381
    case SSL_STATE_CONNECTING:
 
382
        {
 
383
            RSocket &rSock = ((CPjSocket*)sock_)->Socket();
 
384
 
 
385
            rSock.CancelConnect();
 
386
            CleanupSubObjects();
 
387
            state_ = SSL_STATE_NULL;
 
388
        }
 
389
        break;
 
390
    case SSL_STATE_HANDSHAKING:
 
391
        {
 
392
            securesock_->CancelHandshake();
 
393
            CleanupSubObjects();
 
394
            state_ = SSL_STATE_NULL;
 
395
        }
 
396
        break;
 
397
    case SSL_STATE_ESTABLISHED:
 
398
        securesock_->CancelSend();
 
399
        break;
 
400
    default:
 
401
        break;
 
402
    }
 
403
}
 
404
 
 
405
void CPjSSLSocket::RunL()
 
406
{
 
407
    switch (state_) {
 
408
    case SSL_STATE_CONNECTING:
 
409
        if (iStatus != KErrNone) {
 
410
            CleanupSubObjects();
 
411
            state_ = SSL_STATE_NULL;
 
412
            /* Dispatch connect failure notification */
 
413
            if (cb_) (*cb_)(iStatus.Int(), key_);
 
414
        } else {
 
415
            RSocket &rSock = ((CPjSocket*)sock_)->Socket();
 
416
 
 
417
            /* Get local addr */
 
418
            rSock.LocalName(local_addr_);
 
419
            
 
420
            /* Prepare and start handshake */
 
421
            securesock_ = CSecureSocket::NewL(rSock, ssl_proto_);
 
422
            securesock_->SetDialogMode(EDialogModeAttended);
 
423
            if (servername_.Length() > 0)
 
424
                securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
 
425
                                    servername_);
 
426
            if (ciphers_.Length() > 0)
 
427
                securesock_->SetAvailableCipherSuites(ciphers_);
 
428
 
 
429
            // FlushSessionCache() seems to also fire signals to all 
 
430
            // completed AOs (something like CActiveScheduler::RunIfReady())
 
431
            // which may cause problem, e.g: we've experienced that when 
 
432
            // SSL timeout is set to 1s, the SSL timeout timer fires up
 
433
            // at this point and securesock_ instance gets deleted here!
 
434
            // So be careful using this. And we don't think we need it here.
 
435
            //securesock_->FlushSessionCache();
 
436
 
 
437
            securesock_->StartClientHandshake(iStatus);
 
438
            SetActive();
 
439
            state_ = SSL_STATE_HANDSHAKING;
 
440
        }
 
441
        break;
 
442
    case SSL_STATE_HANDSHAKING:
 
443
        if (iStatus == KErrNone) {
 
444
            state_ = SSL_STATE_ESTABLISHED;
 
445
        } else {
 
446
            state_ = SSL_STATE_NULL;
 
447
            CleanupSubObjects();
 
448
        }
 
449
        /* Dispatch connect status notification */
 
450
        if (cb_) (*cb_)(iStatus.Int(), key_);
 
451
        break;
 
452
    case SSL_STATE_ESTABLISHED:
 
453
        /* Dispatch data sent notification */
 
454
        if (cb_) (*cb_)(iStatus.Int(), key_);
 
455
        break;
 
456
    default:
 
457
        pj_assert(0);
 
458
        break;
 
459
    }
 
460
}
 
461
 
 
462
typedef void (*CPjTimer_cb)(void *user_data);
 
463
 
 
464
class CPjTimer : public CActive 
 
465
{
 
466
public:
 
467
    CPjTimer(const pj_time_val *delay, CPjTimer_cb cb, void *user_data) : 
 
468
        CActive(0), cb_(cb), user_data_(user_data)
 
469
    {
 
470
        CActiveScheduler::Add(this);
 
471
 
 
472
        rtimer_.CreateLocal();
 
473
        pj_int32_t interval = PJ_TIME_VAL_MSEC(*delay) * 1000;
 
474
        if (interval < 0) {
 
475
            interval = 0;
 
476
        }
 
477
        rtimer_.After(iStatus, interval);
 
478
        SetActive();
 
479
    }
 
480
    
 
481
    ~CPjTimer() { Cancel(); }
 
482
    
 
483
private:        
 
484
    RTimer               rtimer_;
 
485
    CPjTimer_cb          cb_;
 
486
    void                *user_data_;
 
487
    
 
488
    void RunL() { if (cb_) (*cb_)(user_data_); }
 
489
    void DoCancel() { rtimer_.Cancel(); }
 
490
};
 
491
 
 
492
/*
 
493
 * Structure of recv/read state.
 
494
 */
 
495
typedef struct read_state_t {
 
496
    TPtr8               *read_buf;
 
497
    TPtr8               *orig_buf;
 
498
    pj_uint32_t          flags;    
 
499
} read_state_t;
 
500
 
 
501
/*
 
502
 * Structure of send/write data.
 
503
 */
 
504
typedef struct write_data_t {
 
505
    pj_size_t            len;
 
506
    pj_ioqueue_op_key_t *key;
 
507
    pj_size_t            data_len;
 
508
    char                 data[1];
 
509
} write_data_t;
 
510
 
 
511
/*
 
512
 * Structure of send/write state.
 
513
 */
 
514
typedef struct write_state_t {
 
515
    char                *buf;
 
516
    pj_size_t            max_len;    
 
517
    char                *start;
 
518
    pj_size_t            len;
 
519
    write_data_t        *current_data;
 
520
    TPtrC8               send_ptr;
 
521
} write_state_t;
 
522
 
 
523
/*
 
524
 * Secure socket structure definition.
 
525
 */
 
526
struct pj_ssl_sock_t
 
527
{
 
528
    pj_pool_t           *pool;
 
529
    pj_ssl_sock_cb       cb;
 
530
    void                *user_data;
 
531
    
 
532
    pj_bool_t            established;
 
533
    write_state_t        write_state;
 
534
    read_state_t         read_state;
 
535
    CPjTimer            *connect_timer;
 
536
 
 
537
    CPjSSLSocket        *sock;
 
538
    int                  sock_af;
 
539
    int                  sock_type;
 
540
    pj_sockaddr          local_addr;
 
541
    pj_sockaddr          rem_addr;
 
542
 
 
543
    /* QoS settings */
 
544
    pj_qos_type          qos_type;
 
545
    pj_qos_params        qos_params;
 
546
    pj_bool_t            qos_ignore_error;
 
547
 
 
548
 
 
549
    pj_ssl_sock_proto    proto;
 
550
    pj_time_val          timeout;
 
551
    pj_str_t             servername;
 
552
    pj_str_t             ciphers;
 
553
    pj_ssl_cert_info     remote_cert_info;
 
554
};
 
555
 
 
556
 
 
557
static pj_str_t get_cert_name(char *buf, unsigned buf_len,
 
558
                              const CX500DistinguishedName &name)
 
559
{
 
560
    TInt i;
 
561
    TUint8 *p;
 
562
    TInt l = buf_len;
 
563
    
 
564
    p = (TUint8*)buf;
 
565
    for(i = 0; i < name.Count(); ++i) {
 
566
        const CX520AttributeTypeAndValue &attr = name.Element(i);
 
567
 
 
568
        /* Print element separator */
 
569
        *p++ = '/';
 
570
        if (0 == --l) break;
 
571
 
 
572
        /* Print the type. */
 
573
        TPtr8 type(p, l);
 
574
        type.Copy(attr.Type());
 
575
        p += type.Length();
 
576
        l -= type.Length();
 
577
        if (0 >= --l) break;
 
578
 
 
579
        /* Print equal sign */
 
580
        *p++ = '=';
 
581
        if (0 == --l) break;
 
582
        
 
583
        /* Print the value. Let's just get the raw data here */
 
584
        TPtr8 value(p, l);
 
585
        value.Copy(attr.EncodedValue().Mid(2));
 
586
        p += value.Length();
 
587
        l -= value.Length();
 
588
        if (0 >= --l) break;
 
589
    }
 
590
    
 
591
    pj_str_t src;
 
592
    pj_strset(&src, buf, buf_len - l);
 
593
    
 
594
    return src;
 
595
}
 
596
                            
 
597
/* Get certificate info from CX509Certificate.
 
598
 */
 
599
static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci,
 
600
                          const CX509Certificate *x)
 
601
{
 
602
    enum { tmp_buf_len = 512 };
 
603
    char *tmp_buf;
 
604
    unsigned len;
 
605
    
 
606
    pj_assert(pool && ci && x);
 
607
    
 
608
    /* Init */
 
609
    tmp_buf = new char[tmp_buf_len];
 
610
    pj_bzero(ci, sizeof(*ci));
 
611
    
 
612
    /* Version */
 
613
    ci->version = x->Version();
 
614
    
 
615
    /* Serial number */
 
616
    len = x->SerialNumber().Length();
 
617
    if (len > sizeof(ci->serial_no)) 
 
618
        len = sizeof(ci->serial_no);
 
619
    pj_memcpy(ci->serial_no + sizeof(ci->serial_no) - len, 
 
620
              x->SerialNumber().Ptr(), len);
 
621
    
 
622
    /* Subject */
 
623
    {
 
624
        HBufC *subject = NULL;
 
625
        TRAPD(err, subject = x->SubjectL());
 
626
        if (err == KErrNone) {
 
627
            TPtr16 ptr16(subject->Des());
 
628
            len = ptr16.Length();
 
629
            TPtr8 ptr8((TUint8*)pj_pool_alloc(pool, len), len);
 
630
            ptr8.Copy(ptr16);
 
631
            pj_strset(&ci->subject.cn, (char*)ptr8.Ptr(), ptr8.Length());
 
632
        }
 
633
        pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
 
634
                                     x->SubjectName());
 
635
        pj_strdup(pool, &ci->subject.info, &tmp);
 
636
    }
 
637
 
 
638
    /* Issuer */
 
639
    {
 
640
        HBufC *issuer = NULL;
 
641
        TRAPD(err, issuer = x->IssuerL());
 
642
        if (err == KErrNone) {
 
643
            TPtr16 ptr16(issuer->Des());
 
644
            len = ptr16.Length();
 
645
            TPtr8 ptr8((TUint8*)pj_pool_alloc(pool, len), len);
 
646
            ptr8.Copy(ptr16);
 
647
            pj_strset(&ci->issuer.cn, (char*)ptr8.Ptr(), ptr8.Length());
 
648
        }
 
649
        pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
 
650
                                     x->IssuerName());
 
651
        pj_strdup(pool, &ci->issuer.info, &tmp);
 
652
    }
 
653
    
 
654
    /* Validity */
 
655
    const CValidityPeriod &valid_period = x->ValidityPeriod();
 
656
    TTime base_time(TDateTime(1970, EJanuary, 0, 0, 0, 0, 0));
 
657
    TTimeIntervalSeconds tmp_sec;
 
658
    valid_period.Start().SecondsFrom(base_time, tmp_sec);
 
659
    ci->validity.start.sec = tmp_sec.Int(); 
 
660
    valid_period.Finish().SecondsFrom(base_time, tmp_sec);
 
661
    ci->validity.end.sec = tmp_sec.Int();
 
662
    
 
663
    /* Deinit */
 
664
    delete [] tmp_buf;
 
665
}
 
666
 
 
667
 
 
668
/* Update certificates info. This function should be called after handshake
 
669
 * or renegotiation successfully completed.
 
670
 */
 
671
static void update_certs_info(pj_ssl_sock_t *ssock)
 
672
{
 
673
    const CX509Certificate *x;
 
674
 
 
675
    pj_assert(ssock && ssock->sock &&
 
676
              ssock->sock->GetState() == CPjSSLSocket::SSL_STATE_ESTABLISHED);
 
677
        
 
678
    /* Active remote certificate */
 
679
    x = ssock->sock->GetPeerCert();
 
680
    if (x) {
 
681
        get_cert_info(ssock->pool, &ssock->remote_cert_info, x);
 
682
    } else {
 
683
        pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
 
684
    }
 
685
}
 
686
 
 
687
 
 
688
/* Available ciphers */
 
689
static unsigned ciphers_num_ = 0;
 
690
static struct ciphers_t
 
691
{
 
692
    pj_ssl_cipher    id;
 
693
    const char      *name;
 
694
} ciphers_[64];
 
695
 
 
696
/*
 
697
 * Get cipher list supported by SSL/TLS backend.
 
698
 */
 
699
PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
 
700
                                                  unsigned *cipher_num)
 
701
{
 
702
    unsigned i;
 
703
 
 
704
    PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
 
705
    
 
706
    if (ciphers_num_ == 0) {
 
707
        RSocket sock;
 
708
        CSecureSocket *secure_sock;
 
709
        TPtrC16 proto(_L16("TLS1.0"));
 
710
 
 
711
        secure_sock = CSecureSocket::NewL(sock, proto);
 
712
        if (secure_sock) {
 
713
            TBuf8<128> ciphers_buf(0);
 
714
            secure_sock->AvailableCipherSuites(ciphers_buf);
 
715
            
 
716
            ciphers_num_ = ciphers_buf.Length() / 2;
 
717
            if (ciphers_num_ > PJ_ARRAY_SIZE(ciphers_))
 
718
                ciphers_num_ = PJ_ARRAY_SIZE(ciphers_);
 
719
            for (i = 0; i < ciphers_num_; ++i) {
 
720
                ciphers_[i].id = (pj_ssl_cipher)(ciphers_buf[i*2]*10 + 
 
721
                                                 ciphers_buf[i*2+1]);
 
722
                ciphers_[i].name = get_cipher_name(ciphers_[i].id);
 
723
            }
 
724
        }
 
725
        
 
726
        delete secure_sock;
 
727
    }
 
728
    
 
729
    if (ciphers_num_ == 0) {
 
730
        *cipher_num = 0;
 
731
        return PJ_ENOTFOUND;
 
732
    }
 
733
    
 
734
    *cipher_num = PJ_MIN(*cipher_num, ciphers_num_);
 
735
    for (i = 0; i < *cipher_num; ++i)
 
736
        ciphers[i] = ciphers_[i].id;
 
737
    
 
738
    return PJ_SUCCESS;
 
739
}
 
740
 
 
741
 
 
742
/* Get cipher name string */
 
743
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
 
744
{
 
745
    unsigned i;
 
746
 
 
747
    if (ciphers_num_ == 0) {
 
748
        pj_ssl_cipher c[1];
 
749
        i = 0;
 
750
        pj_ssl_cipher_get_availables(c, &i);
 
751
    }
 
752
        
 
753
    for (i = 0; i < ciphers_num_; ++i) {
 
754
        if (cipher == ciphers_[i].id)
 
755
            return ciphers_[i].name;
 
756
    }
 
757
 
 
758
    return NULL;
 
759
}
 
760
 
 
761
 
 
762
/* Check if the specified cipher is supported by SSL/TLS backend. */
 
763
PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
 
764
{
 
765
    unsigned i;
 
766
 
 
767
    if (ciphers_num_ == 0) {
 
768
        pj_ssl_cipher c[1];
 
769
        i = 0;
 
770
        pj_ssl_cipher_get_availables(c, &i);
 
771
    }
 
772
        
 
773
    for (i = 0; i < ciphers_num_; ++i) {
 
774
        if (cipher == ciphers_[i].id)
 
775
            return PJ_TRUE;
 
776
    }
 
777
 
 
778
    return PJ_FALSE;
 
779
}
 
780
 
 
781
 
 
782
/*
 
783
 * Create SSL socket instance. 
 
784
 */
 
785
PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
 
786
                                        const pj_ssl_sock_param *param,
 
787
                                        pj_ssl_sock_t **p_ssock)
 
788
{
 
789
    pj_ssl_sock_t *ssock;
 
790
 
 
791
    PJ_ASSERT_RETURN(param->async_cnt == 1, PJ_EINVAL);
 
792
    PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
 
793
 
 
794
    /* Allocate secure socket */
 
795
    ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
 
796
    
 
797
    /* Allocate write buffer */
 
798
    ssock->write_state.buf = (char*)pj_pool_alloc(pool, 
 
799
                                                  param->send_buffer_size);
 
800
    ssock->write_state.max_len = param->send_buffer_size;
 
801
    ssock->write_state.start = ssock->write_state.buf;
 
802
    
 
803
    /* Init secure socket */
 
804
    ssock->pool = pool;
 
805
    ssock->sock_af = param->sock_af;
 
806
    ssock->sock_type = param->sock_type;
 
807
    ssock->cb = param->cb;
 
808
    ssock->user_data = param->user_data;
 
809
    ssock->timeout = param->timeout;
 
810
    if (param->ciphers_num > 0) {
 
811
        /* Cipher list in Symbian is represented as array of two-octets. */
 
812
        ssock->ciphers.slen = param->ciphers_num*2;
 
813
        ssock->ciphers.ptr  = (char*)pj_pool_alloc(pool, ssock->ciphers.slen);
 
814
        pj_uint8_t *c = (pj_uint8_t*)ssock->ciphers.ptr;
 
815
        for (unsigned i = 0; i < param->ciphers_num; ++i) {
 
816
            *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF00) >> 8;
 
817
            *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF);
 
818
        }
 
819
    }
 
820
    pj_strdup_with_null(pool, &ssock->servername, &param->server_name);
 
821
 
 
822
    ssock->qos_type = param->qos_type;
 
823
    ssock->qos_ignore_error = param->qos_ignore_error;
 
824
    pj_memcpy(&ssock->qos_params, &param->qos_params,
 
825
              sizeof(param->qos_params));
 
826
 
 
827
    /* Finally */
 
828
    *p_ssock = ssock;
 
829
 
 
830
    return PJ_SUCCESS;
 
831
}
 
832
 
 
833
 
 
834
PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files(pj_pool_t *pool,
 
835
                                                const pj_str_t *CA_file,
 
836
                                                const pj_str_t *cert_file,
 
837
                                                const pj_str_t *privkey_file,
 
838
                                                const pj_str_t *privkey_pass,
 
839
                                                pj_ssl_cert_t **p_cert)
 
840
{
 
841
    PJ_UNUSED_ARG(pool);
 
842
    PJ_UNUSED_ARG(CA_file);
 
843
    PJ_UNUSED_ARG(cert_file);
 
844
    PJ_UNUSED_ARG(privkey_file);
 
845
    PJ_UNUSED_ARG(privkey_pass);
 
846
    PJ_UNUSED_ARG(p_cert);
 
847
    return PJ_ENOTSUP;
 
848
}
 
849
 
 
850
/*
 
851
 * Set SSL socket credential.
 
852
 */
 
853
PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
 
854
                                            pj_ssl_sock_t *ssock,
 
855
                                            pj_pool_t *pool,
 
856
                                            const pj_ssl_cert_t *cert)
 
857
{
 
858
    PJ_UNUSED_ARG(ssock);
 
859
    PJ_UNUSED_ARG(pool);
 
860
    PJ_UNUSED_ARG(cert);
 
861
    return PJ_ENOTSUP;
 
862
}
 
863
 
 
864
/*
 
865
 * Close the SSL socket.
 
866
 */
 
867
PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
 
868
{
 
869
    PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
 
870
    
 
871
    delete ssock->connect_timer;
 
872
    ssock->connect_timer = NULL;
 
873
    
 
874
    delete ssock->sock;
 
875
    ssock->sock = NULL;
 
876
 
 
877
    delete ssock->read_state.read_buf;
 
878
    delete ssock->read_state.orig_buf;
 
879
    ssock->read_state.read_buf = NULL;
 
880
    ssock->read_state.orig_buf = NULL;
 
881
    
 
882
    return PJ_SUCCESS;
 
883
}
 
884
 
 
885
 
 
886
/*
 
887
 * Associate arbitrary data with the SSL socket.
 
888
 */
 
889
PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data (pj_ssl_sock_t *ssock,
 
890
                                               void *user_data)
 
891
{
 
892
    PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
 
893
    
 
894
    ssock->user_data = user_data;
 
895
    
 
896
    return PJ_SUCCESS;
 
897
}
 
898
                                               
 
899
 
 
900
/*
 
901
 * Retrieve the user data previously associated with this SSL
 
902
 * socket.
 
903
 */
 
904
PJ_DEF(void*) pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
 
905
{
 
906
    PJ_ASSERT_RETURN(ssock, NULL);
 
907
    
 
908
    return ssock->user_data;
 
909
}
 
910
 
 
911
 
 
912
/*
 
913
 * Retrieve the local address and port used by specified SSL socket.
 
914
 */
 
915
PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
 
916
                                          pj_ssl_sock_info *info)
 
917
{
 
918
    PJ_ASSERT_RETURN(ssock && info, PJ_EINVAL);
 
919
    
 
920
    pj_bzero(info, sizeof(*info));
 
921
    
 
922
    info->established = ssock->established;
 
923
    
 
924
    /* Local address */
 
925
    if (ssock->sock) {
 
926
        const TInetAddr* local_addr_ = ssock->sock->GetLocalAddr();
 
927
        int addrlen = sizeof(pj_sockaddr);
 
928
        pj_status_t status;
 
929
        
 
930
        status = PjSymbianOS::Addr2pj(*local_addr_, info->local_addr, &addrlen);
 
931
        if (status != PJ_SUCCESS)
 
932
            return status;
 
933
    } else {
 
934
        pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
 
935
    }
 
936
 
 
937
    if (info->established) {
 
938
        /* Cipher suite */
 
939
        TBuf8<4> cipher;
 
940
        if (ssock->sock->GetCipher(cipher) == KErrNone) {
 
941
            info->cipher = (pj_ssl_cipher)cipher[1]; 
 
942
        }
 
943
 
 
944
        /* Remote address */
 
945
        pj_sockaddr_cp((pj_sockaddr_t*)&info->remote_addr, 
 
946
                       (pj_sockaddr_t*)&ssock->rem_addr);
 
947
        
 
948
        /* Certificates info */
 
949
        info->remote_cert_info = &ssock->remote_cert_info;
 
950
    }
 
951
 
 
952
    /* Protocol */
 
953
    info->proto = ssock->proto;
 
954
    
 
955
    return PJ_SUCCESS;
 
956
}
 
957
 
 
958
 
 
959
/*
 
960
 * Starts read operation on this SSL socket.
 
961
 */
 
962
PJ_DEF(pj_status_t) pj_ssl_sock_start_read (pj_ssl_sock_t *ssock,
 
963
                                            pj_pool_t *pool,
 
964
                                            unsigned buff_size,
 
965
                                            pj_uint32_t flags)
 
966
{
 
967
    PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
 
968
    PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
 
969
 
 
970
    /* Reading is already started */
 
971
    if (ssock->read_state.orig_buf) {
 
972
        return PJ_SUCCESS;
 
973
    }
 
974
 
 
975
    void *readbuf[1];
 
976
    readbuf[0] = pj_pool_alloc(pool, buff_size);
 
977
    return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
 
978
}
 
979
 
 
980
static void read_cb(int err, void *key)
 
981
{
 
982
    pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
 
983
    pj_status_t status;
 
984
 
 
985
    status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
 
986
 
 
987
    /* Check connection status */
 
988
    if (err == KErrEof || !PjSymbianOS::Instance()->IsConnectionUp() ||
 
989
        !ssock->established) 
 
990
    {
 
991
        status = PJ_EEOF;
 
992
    }
 
993
    
 
994
    /* Notify data arrival */
 
995
    if (ssock->cb.on_data_read) {
 
996
        pj_size_t remainder = 0;
 
997
        char *data = (char*)ssock->read_state.orig_buf->Ptr();
 
998
        pj_size_t data_len = ssock->read_state.read_buf->Length() + 
 
999
                             ssock->read_state.read_buf->Ptr() -
 
1000
                             ssock->read_state.orig_buf->Ptr();
 
1001
        
 
1002
        if (data_len > 0) {
 
1003
            /* Notify received data */
 
1004
            pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, data, data_len, 
 
1005
                                                      status, &remainder);
 
1006
            if (!ret) {
 
1007
                /* We've been destroyed */
 
1008
                return;
 
1009
            }
 
1010
            
 
1011
            /* Calculate available data for next READ operation */
 
1012
            if (remainder > 0) {
 
1013
                pj_size_t data_maxlen = ssock->read_state.orig_buf->MaxLength();
 
1014
                
 
1015
                /* There is some data left unconsumed by application, we give
 
1016
                 * smaller buffer for next READ operation.
 
1017
                 */
 
1018
                ssock->read_state.read_buf->Set((TUint8*)data+remainder, 0, 
 
1019
                                                data_maxlen - remainder);
 
1020
            } else {
 
1021
                /* Give all buffer for next READ operation. 
 
1022
                 */
 
1023
                ssock->read_state.read_buf->Set(*ssock->read_state.orig_buf);
 
1024
            }
 
1025
        }
 
1026
    }
 
1027
 
 
1028
    if (status == PJ_SUCCESS) {
 
1029
        /* Perform the "next" READ operation */
 
1030
        CPjSSLSocketReader *reader = ssock->sock->GetReader(); 
 
1031
        ssock->read_state.read_buf->SetLength(0);
 
1032
        status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf, 
 
1033
                              ssock->read_state.flags);
 
1034
    }
 
1035
    
 
1036
    /* Connection closed or something goes wrong */
 
1037
    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
 
1038
        /* Notify error */
 
1039
        if (ssock->cb.on_data_read) {
 
1040
            pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, NULL, 0, 
 
1041
                                                      status, NULL);
 
1042
            if (!ret) {
 
1043
                /* We've been destroyed */
 
1044
                return;
 
1045
            }
 
1046
        }
 
1047
        
 
1048
        delete ssock->read_state.read_buf;
 
1049
        delete ssock->read_state.orig_buf;
 
1050
        ssock->read_state.read_buf = NULL;
 
1051
        ssock->read_state.orig_buf = NULL;
 
1052
        ssock->established = PJ_FALSE;
 
1053
    }
 
1054
}
 
1055
 
 
1056
/*
 
1057
 * Same as #pj_ssl_sock_start_read(), except that the application
 
1058
 * supplies the buffers for the read operation so that the acive socket
 
1059
 * does not have to allocate the buffers.
 
1060
 */
 
1061
PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
 
1062
                                             pj_pool_t *pool,
 
1063
                                             unsigned buff_size,
 
1064
                                             void *readbuf[],
 
1065
                                             pj_uint32_t flags)
 
1066
{
 
1067
    PJ_ASSERT_RETURN(ssock && buff_size && readbuf, PJ_EINVAL);
 
1068
    PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
 
1069
    
 
1070
    /* Return failure if access point is marked as down by app. */
 
1071
    PJ_SYMBIAN_CHECK_CONNECTION();
 
1072
    
 
1073
    /* Reading is already started */
 
1074
    if (ssock->read_state.orig_buf) {
 
1075
        return PJ_SUCCESS;
 
1076
    }
 
1077
    
 
1078
    PJ_UNUSED_ARG(pool);
 
1079
 
 
1080
    /* Get reader instance */
 
1081
    CPjSSLSocketReader *reader = ssock->sock->GetReader();
 
1082
    if (!reader)
 
1083
        return PJ_ENOMEM;
 
1084
    
 
1085
    /* We manage two buffer pointers here:
 
1086
     * 1. orig_buf keeps the orginal buffer address (and its max length).
 
1087
     * 2. read_buf provides buffer for READ operation, mind that there may be
 
1088
     *    some remainder data left by application.
 
1089
     */
 
1090
    ssock->read_state.read_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
 
1091
    ssock->read_state.orig_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
 
1092
    ssock->read_state.flags = flags;
 
1093
    
 
1094
    pj_status_t status;
 
1095
    status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf, 
 
1096
                          ssock->read_state.flags);
 
1097
    
 
1098
    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
 
1099
        delete ssock->read_state.read_buf;
 
1100
        delete ssock->read_state.orig_buf;
 
1101
        ssock->read_state.read_buf = NULL;
 
1102
        ssock->read_state.orig_buf = NULL;
 
1103
        
 
1104
        return status;
 
1105
    }
 
1106
    
 
1107
    return PJ_SUCCESS;
 
1108
}
 
1109
 
 
1110
/*
 
1111
 * Same as pj_ssl_sock_start_read(), except that this function is used
 
1112
 * only for datagram sockets, and it will trigger \a on_data_recvfrom()
 
1113
 * callback instead.
 
1114
 */
 
1115
PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
 
1116
                                                pj_pool_t *pool,
 
1117
                                                unsigned buff_size,
 
1118
                                                pj_uint32_t flags)
 
1119
{
 
1120
    PJ_UNUSED_ARG(ssock);
 
1121
    PJ_UNUSED_ARG(pool);
 
1122
    PJ_UNUSED_ARG(buff_size);
 
1123
    PJ_UNUSED_ARG(flags);
 
1124
    return PJ_ENOTSUP;
 
1125
}
 
1126
 
 
1127
/*
 
1128
 * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom() 
 
1129
 * operation takes the buffer from the argument rather than creating
 
1130
 * new ones.
 
1131
 */
 
1132
PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
 
1133
                                                 pj_pool_t *pool,
 
1134
                                                 unsigned buff_size,
 
1135
                                                 void *readbuf[],
 
1136
                                                 pj_uint32_t flags)
 
1137
{
 
1138
    PJ_UNUSED_ARG(ssock);
 
1139
    PJ_UNUSED_ARG(pool);
 
1140
    PJ_UNUSED_ARG(buff_size);
 
1141
    PJ_UNUSED_ARG(readbuf);
 
1142
    PJ_UNUSED_ARG(flags);
 
1143
    return PJ_ENOTSUP;
 
1144
}
 
1145
 
 
1146
static void send_cb(int err, void *key)
 
1147
{
 
1148
    pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
 
1149
    write_state_t *st = &ssock->write_state;
 
1150
 
 
1151
    /* Check connection status */
 
1152
    if (err != KErrNone || !PjSymbianOS::Instance()->IsConnectionUp() ||
 
1153
        !ssock->established) 
 
1154
    {
 
1155
        ssock->established = PJ_FALSE;
 
1156
        return;
 
1157
    }
 
1158
 
 
1159
    /* Remove sent data from buffer */
 
1160
    st->start += st->current_data->len;
 
1161
    st->len -= st->current_data->len;
 
1162
 
 
1163
    /* Reset current outstanding send */
 
1164
    st->current_data = NULL;
 
1165
 
 
1166
    /* Let's check if there is pending data to send */
 
1167
    if (st->len) {
 
1168
        write_data_t *wdata = (write_data_t*)st->start;
 
1169
        pj_status_t status;
 
1170
        
 
1171
        st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
 
1172
        st->current_data = wdata;
 
1173
        status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, 0);
 
1174
        if (status != PJ_EPENDING) {
 
1175
            ssock->established = PJ_FALSE;
 
1176
            st->len = 0;
 
1177
            return;
 
1178
        }
 
1179
    } else {
 
1180
        /* Buffer empty, reset the start position */
 
1181
        st->start = st->buf;
 
1182
    }
 
1183
}
 
1184
 
 
1185
/*
 
1186
 * Send data using the socket.
 
1187
 */
 
1188
PJ_DEF(pj_status_t) pj_ssl_sock_send (pj_ssl_sock_t *ssock,
 
1189
                                      pj_ioqueue_op_key_t *send_key,
 
1190
                                      const void *data,
 
1191
                                      pj_ssize_t *size,
 
1192
                                      unsigned flags)
 
1193
{
 
1194
    PJ_CHECK_STACK();
 
1195
    PJ_ASSERT_RETURN(ssock && data && size, PJ_EINVAL);
 
1196
    PJ_ASSERT_RETURN(ssock->write_state.max_len == 0 || 
 
1197
                     ssock->write_state.max_len >= (pj_size_t)*size, 
 
1198
                     PJ_ETOOSMALL);
 
1199
    
 
1200
    /* Check connection status */
 
1201
    if (!PjSymbianOS::Instance()->IsConnectionUp() || !ssock->established) 
 
1202
    {
 
1203
        ssock->established = PJ_FALSE;
 
1204
        return PJ_ECANCELLED;
 
1205
    }
 
1206
 
 
1207
    write_state_t *st = &ssock->write_state;
 
1208
    
 
1209
    /* Synchronous mode */
 
1210
    if (st->max_len == 0) {
 
1211
        st->send_ptr.Set((TUint8*)data, (TInt)*size);
 
1212
        return ssock->sock->SendSync(st->send_ptr, flags);
 
1213
    }
 
1214
 
 
1215
    /* CSecureSocket only allows one outstanding send operation, so
 
1216
     * we use buffering mechanism to allow application to perform send 
 
1217
     * operations at any time.
 
1218
     */
 
1219
    
 
1220
    pj_size_t needed_len = *size + sizeof(write_data_t) - 1;
 
1221
    
 
1222
    /* Align needed_len to be multiplication of 4 */
 
1223
    needed_len = ((needed_len + 3) >> 2) << 2; 
 
1224
 
 
1225
    /* Block until there is buffer slot available and contiguous! */
 
1226
    while (st->start + st->len + needed_len > st->buf + st->max_len) {
 
1227
        pj_symbianos_poll(-1, -1);
 
1228
    }
 
1229
 
 
1230
    /* Push back the send data into the buffer */
 
1231
    write_data_t *wdata = (write_data_t*)(st->start + st->len);
 
1232
    
 
1233
    wdata->len = needed_len;
 
1234
    wdata->key = send_key;
 
1235
    wdata->data_len = (pj_size_t)*size;
 
1236
    pj_memcpy(wdata->data, data, *size);
 
1237
    st->len += needed_len;
 
1238
 
 
1239
    /* If no outstanding send, send it */
 
1240
    if (st->current_data == NULL) {
 
1241
        pj_status_t status;
 
1242
            
 
1243
        wdata = (write_data_t*)st->start;
 
1244
        st->current_data = wdata;
 
1245
        st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
 
1246
        status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, flags);
 
1247
        
 
1248
        if (status != PJ_EPENDING) {
 
1249
            *size = -status;
 
1250
            return status;
 
1251
        }
 
1252
    }
 
1253
    
 
1254
    return PJ_SUCCESS;
 
1255
}
 
1256
 
 
1257
/*
 
1258
 * Send datagram using the socket.
 
1259
 */
 
1260
PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
 
1261
                                        pj_ioqueue_op_key_t *send_key,
 
1262
                                        const void *data,
 
1263
                                        pj_ssize_t *size,
 
1264
                                        unsigned flags,
 
1265
                                        const pj_sockaddr_t *addr,
 
1266
                                        int addr_len)
 
1267
{
 
1268
    PJ_UNUSED_ARG(ssock);
 
1269
    PJ_UNUSED_ARG(send_key);
 
1270
    PJ_UNUSED_ARG(data);
 
1271
    PJ_UNUSED_ARG(size);
 
1272
    PJ_UNUSED_ARG(flags);
 
1273
    PJ_UNUSED_ARG(addr);
 
1274
    PJ_UNUSED_ARG(addr_len);
 
1275
    return PJ_ENOTSUP;
 
1276
}
 
1277
 
 
1278
/*
 
1279
 * Starts asynchronous socket accept() operations on this SSL socket. 
 
1280
 */
 
1281
PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
 
1282
                                              pj_pool_t *pool,
 
1283
                                              const pj_sockaddr_t *local_addr,
 
1284
                                              int addr_len)
 
1285
{
 
1286
    PJ_UNUSED_ARG(ssock);
 
1287
    PJ_UNUSED_ARG(pool);
 
1288
    PJ_UNUSED_ARG(local_addr);
 
1289
    PJ_UNUSED_ARG(addr_len);
 
1290
    
 
1291
    return PJ_ENOTSUP;
 
1292
}
 
1293
 
 
1294
static void connect_cb(int err, void *key)
 
1295
{
 
1296
    pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
 
1297
    pj_status_t status;
 
1298
    
 
1299
    if (ssock->connect_timer) {
 
1300
        delete ssock->connect_timer;
 
1301
        ssock->connect_timer = NULL;
 
1302
    }
 
1303
 
 
1304
    status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
 
1305
    if (status == PJ_SUCCESS) {
 
1306
        ssock->established = PJ_TRUE;
 
1307
        update_certs_info(ssock);
 
1308
    } else {
 
1309
        delete ssock->sock;
 
1310
        ssock->sock = NULL;
 
1311
        if (err == KErrTimedOut) status = PJ_ETIMEDOUT;
 
1312
    }
 
1313
    
 
1314
    if (ssock->cb.on_connect_complete) {
 
1315
        pj_bool_t ret = (*ssock->cb.on_connect_complete)(ssock, status);
 
1316
        if (!ret) {
 
1317
            /* We've been destroyed */
 
1318
            return;
 
1319
        }
 
1320
    }
 
1321
}
 
1322
 
 
1323
static void connect_timer_cb(void *key)
 
1324
{
 
1325
    connect_cb(KErrTimedOut, key);
 
1326
}
 
1327
 
 
1328
/*
 
1329
 * Starts asynchronous socket connect() operation and SSL/TLS handshaking 
 
1330
 * for this socket. Once the connection is done (either successfully or not),
 
1331
 * the \a on_connect_complete() callback will be called.
 
1332
 */
 
1333
PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
 
1334
                                               pj_pool_t *pool,
 
1335
                                               const pj_sockaddr_t *localaddr,
 
1336
                                               const pj_sockaddr_t *remaddr,
 
1337
                                               int addr_len)
 
1338
{
 
1339
    CPjSSLSocket *sock = NULL;
 
1340
    pj_status_t status;
 
1341
    
 
1342
    PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
 
1343
                     PJ_EINVAL);
 
1344
 
 
1345
    /* Check connection status */
 
1346
    PJ_SYMBIAN_CHECK_CONNECTION();
 
1347
    
 
1348
    if (ssock->sock != NULL) {
 
1349
        CPjSSLSocket::ssl_state state = ssock->sock->GetState();
 
1350
        switch (state) {
 
1351
        case CPjSSLSocket::SSL_STATE_ESTABLISHED:
 
1352
            return PJ_SUCCESS;
 
1353
        default:
 
1354
            return PJ_EPENDING;
 
1355
        }
 
1356
    }
 
1357
 
 
1358
    /* Set SSL protocol */
 
1359
    TPtrC8 proto;
 
1360
    
 
1361
    if (ssock->proto == PJ_SSL_SOCK_PROTO_DEFAULT)
 
1362
        ssock->proto = PJ_SSL_SOCK_PROTO_TLS1;
 
1363
 
 
1364
    /* CSecureSocket only support TLS1.0 and SSL3.0 */
 
1365
    switch(ssock->proto) {
 
1366
    case PJ_SSL_SOCK_PROTO_TLS1:
 
1367
        proto.Set((const TUint8*)"TLS1.0", 6);
 
1368
        break;
 
1369
    case PJ_SSL_SOCK_PROTO_SSL3:
 
1370
        proto.Set((const TUint8*)"SSL3.0", 6);
 
1371
        break;
 
1372
    default:
 
1373
        return PJ_ENOTSUP;
 
1374
    }
 
1375
 
 
1376
    /* Prepare addresses */
 
1377
    TInetAddr localaddr_, remaddr_;
 
1378
    status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)localaddr, addr_len, 
 
1379
                                  localaddr_);
 
1380
    if (status != PJ_SUCCESS)
 
1381
        return status;
 
1382
    
 
1383
    status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)remaddr, addr_len,
 
1384
                                  remaddr_);
 
1385
    if (status != PJ_SUCCESS)
 
1386
        return status;
 
1387
 
 
1388
    pj_sockaddr_cp((pj_sockaddr_t*)&ssock->rem_addr, remaddr);
 
1389
 
 
1390
    /* Init SSL engine */
 
1391
    TRAPD(err, sock = CPjSSLSocket::NewL(proto, ssock->qos_type, 
 
1392
                                         ssock->qos_params));
 
1393
    if (err != KErrNone)
 
1394
        return PJ_ENOMEM;
 
1395
    
 
1396
    if (ssock->timeout.sec != 0 || ssock->timeout.msec != 0) {
 
1397
        ssock->connect_timer = new CPjTimer(&ssock->timeout, 
 
1398
                                            &connect_timer_cb, ssock);
 
1399
    }
 
1400
    
 
1401
    /* Convert server name to Symbian descriptor */
 
1402
    TPtrC8 servername_((TUint8*)ssock->servername.ptr, 
 
1403
                       ssock->servername.slen);
 
1404
    
 
1405
    /* Convert cipher list to Symbian descriptor */
 
1406
    TPtrC8 ciphers_((TUint8*)ssock->ciphers.ptr, 
 
1407
                    ssock->ciphers.slen);
 
1408
    
 
1409
    /* Try to connect */
 
1410
    status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
 
1411
                           servername_, ciphers_);
 
1412
    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
 
1413
        delete sock;
 
1414
        return status;
 
1415
    }
 
1416
 
 
1417
    ssock->sock = sock;
 
1418
    return status;
 
1419
}
 
1420
 
 
1421
 
 
1422
PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
 
1423
{
 
1424
    PJ_UNUSED_ARG(ssock);
 
1425
    return PJ_ENOTSUP;
 
1426
}