1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#include <exception>
43
#include <e32base.h>
44
#include <e32uid.h>
45
#include "qcore_symbian_p.h"
46
#include <string>
47
#include <in_sock.h>
48
#include "qdebug.h"
49
50
QT_BEGIN_NAMESPACE
51
52
/*
53
    Helper function for calling into Symbian classes that expect a TDes&.
54
    This function converts a QString to a TDes by allocating memory that
55
    must be deleted by the caller.
56
*/
57
58
Q_CORE_EXPORT HBufC* qt_QString2HBufC(const QString& aString)
59
{
60
    HBufC *buffer;
61
#ifdef QT_NO_UNICODE
62
    TPtrC8 ptr(reinterpret_cast<const TUint8*>(aString.toLocal8Bit().constData()));
63
#else
64
    TPtrC16 ptr(qt_QString2TPtrC(aString));
65
#endif
66
    buffer = HBufC::New(ptr.Length());
67
    Q_CHECK_PTR(buffer);
68
    buffer->Des().Copy(ptr);
69
    return buffer;
70
}
71
72
Q_CORE_EXPORT QString qt_TDesC2QString(const TDesC& aDescriptor)
73
{
74
#ifdef QT_NO_UNICODE
75
    return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length());
76
#else
77
    return QString(reinterpret_cast<const QChar *>(aDescriptor.Ptr()), aDescriptor.Length());
78
#endif
79
}
80
81
QHBufC::QHBufC()
82
    : m_hBufC(0)
83
{
84
}
85
86
QHBufC::QHBufC(const QHBufC &src)
87
	: m_hBufC(src.m_hBufC->Alloc())
88
{
89
    Q_CHECK_PTR(m_hBufC);
90
}
91
92
/*!
93
  \internal
94
  Constructs a QHBufC from an HBufC. Note that the QHBufC instance takes
95
  ownership of the HBufC.
96
*/
97
QHBufC::QHBufC(HBufC *src)
98
    : m_hBufC(src)
99
{
100
}
101
102
QHBufC::QHBufC(const QString &src)
103
{
104
    m_hBufC = qt_QString2HBufC(src);
105
}
106
107
QHBufC::~QHBufC()
108
{
109
    if (m_hBufC)
110
        delete m_hBufC;
111
}
112
113
class QS60RFsSession
114
{
115
public:
116
    QS60RFsSession() {
117
        qt_symbian_throwIfError(iFs.Connect());
118
        qt_symbian_throwIfError(iFs.ShareProtected());
119
        //BC with 4.7: create private path on system drive
120
        TInt sysdrive = iFs.GetSystemDrive();
121
        TInt err = iFs.CreatePrivatePath(sysdrive);
122
        if (err != KErrNone && err != KErrAlreadyExists)
123
            qWarning("Failed to create private path on system drive.");
124
        TFileName pfn = RProcess().FileName();
125
        TInt drive;
126
        if (pfn.Length() > 0 && iFs.CharToDrive(pfn[0], drive) == KErrNone) {
127
            //BC with 4.7: create private path on application drive (except rom or system drive which is done above)
128
            if (drive != sysdrive && drive != EDriveZ) {
129
                err = iFs.CreatePrivatePath(drive);
130
                if (err != KErrNone && err != KErrAlreadyExists)
131
                    qWarning("Failed to create private path on application drive.");
132
            }
133
            //BC with 4.7: set working directory to same drive as application
134
            iFs.SetSessionToPrivate(drive);
135
        }
136
    }
137
138
    ~QS60RFsSession() {
139
        iFs.Close();
140
    }
141
142
    RFs& GetRFs() {
143
        return iFs;
144
    }
145
146
private:
147
148
    RFs iFs;
149
};
150
151
uint qHash(const RSubSessionBase& key)
152
{
153
    return qHash(key.SubSessionHandle());
154
}
155
156
Q_GLOBAL_STATIC(QS60RFsSession, qt_s60_RFsSession);
157
158
Q_CORE_EXPORT RFs& qt_s60GetRFs()
159
{
160
    return qt_s60_RFsSession()->GetRFs();
161
}
162
163
QSymbianSocketManager::QSymbianSocketManager() :
164
    iNextSocket(0), iDefaultConnection(0)
165
{
166
    TSessionPref preferences;
167
    // ### In future this could be changed to KAfInet6 when that is more common than IPv4
168
    preferences.iAddrFamily = KAfInet;
169
    preferences.iProtocol = KProtocolInetIp;
170
    //use global message pool, as we do not know how many sockets app will use
171
    //TODO: is this the right choice?
172
    qt_symbian_throwIfError(iSocketServ.Connect(preferences, -1));
173
    qt_symbian_throwIfError(iSocketServ.ShareAuto());
174
}
175
176
QSymbianSocketManager::~QSymbianSocketManager()
177
{
178
    iSocketServ.Close();
179
    if(!socketMap.isEmpty()) {
180
        qWarning("leaked %d sockets on exit", socketMap.count());
181
    }
182
}
183
184
RSocketServ& QSymbianSocketManager::getSocketServer() {
185
    return iSocketServ;
186
}
187
188
int QSymbianSocketManager::addSocket(const RSocket& socket) {
189
    QHashableSocket sock(static_cast<const QHashableSocket &>(socket));
190
    QMutexLocker l(&iMutex);
191
    Q_ASSERT(!socketMap.contains(sock));
192
    if(socketMap.contains(sock))
193
        return socketMap.value(sock);
194
    // allocate socket number
195
    int guard = 0;
196
    while(reverseSocketMap.contains(iNextSocket)) {
197
        iNextSocket++;
198
        iNextSocket %= max_sockets;
199
        guard++;
200
        if(guard > max_sockets)
201
            return -1;
202
    }
203
    int id = iNextSocket;
204
205
    socketMap[sock] = id;
206
    reverseSocketMap[id] = sock;
207
    return id + socket_offset;
208
}
209
210
bool QSymbianSocketManager::removeSocket(const RSocket &socket) {
211
    QHashableSocket sock(static_cast<const QHashableSocket &>(socket));
212
    QMutexLocker l(&iMutex);
213
    if(!socketMap.contains(sock))
214
        return false;
215
    int id = socketMap.value(sock);
216
    socketMap.remove(sock);
217
    reverseSocketMap.remove(id);
218
    return true;
219
}
220
221
int QSymbianSocketManager::lookupSocket(const RSocket& socket) const {
222
    QHashableSocket sock(static_cast<const QHashableSocket &>(socket));
223
    QMutexLocker l(&iMutex);
224
    if(!socketMap.contains(sock))
225
        return -1;
226
    int id = socketMap.value(sock);
227
    return id + socket_offset;
228
}
229
230
bool QSymbianSocketManager::lookupSocket(int fd, RSocket& socket) const {
231
    QMutexLocker l(&iMutex);
232
    int id = fd - socket_offset;
233
    if(!reverseSocketMap.contains(id))
234
        return false;
235
    socket = reverseSocketMap.value(id);
236
    return true;
237
}
238
239
void QSymbianSocketManager::setDefaultConnection(RConnection* con)
240
{
241
    iDefaultConnection = con;
242
}
243
244
RConnection* QSymbianSocketManager::defaultConnection() const
245
{
246
    return iDefaultConnection;
247
}
248
249
void QSymbianSocketManager::addActiveConnection(TUint32 identifier)
250
{
251
    QMutexLocker l(&iMutex);
252
    activeConnectionsMap[identifier]++;
253
#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
254
    qDebug() << "addActiveConnection" << identifier << activeConnectionsMap[identifier];
255
#endif
256
}
257
258
void QSymbianSocketManager::removeActiveConnection(TUint32 identifier)
259
{
260
    QMutexLocker l(&iMutex);
261
    int& val(activeConnectionsMap[identifier]);
262
    Q_ASSERT(val > 0);
263
#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
264
    qDebug() << "removeActiveConnection" << identifier << val - 1;
265
#endif
266
    if (val <= 1)
267
        activeConnectionsMap.remove(identifier);
268
    else
269
        val--;
270
}
271
272
QList<TUint32> QSymbianSocketManager::activeConnections() const
273
{
274
    QMutexLocker l(&iMutex);
275
#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
276
    qDebug() << "activeConnections" <<  activeConnectionsMap.keys();
277
#endif
278
    return activeConnectionsMap.keys();
279
}
280
281
Q_GLOBAL_STATIC(QSymbianSocketManager, qt_symbianSocketManager);
282
283
QSymbianSocketManager& QSymbianSocketManager::instance()
284
{
285
    return *(qt_symbianSocketManager());
286
}
287
288
Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer()
289
{
290
    return QSymbianSocketManager::instance().getSocketServer();
291
}
292
293
QT_END_NAMESPACE