|
1 /** |
|
2 This file is part of CWRT package ** |
|
3 |
|
4 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** |
|
5 |
|
6 This program is free software: you can redistribute it and/or modify |
|
7 it under the terms of the GNU (Lesser) General Public License as |
|
8 published by the Free Software Foundation, version 2.1 of the License. |
|
9 This program is distributed in the hope that it will be useful, but |
|
10 WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 (Lesser) General Public License for more details. You should have |
|
13 received a copy of the GNU (Lesser) General Public License along |
|
14 with this program. If not, see <http://www.gnu.org/licenses/>. |
|
15 */ |
|
16 |
|
17 |
|
18 #include <QByteArray> |
|
19 #include "serviceipclocalsocket_p.h" |
|
20 |
|
21 namespace WRT |
|
22 { |
|
23 // CONSTANTS |
|
24 const char* REQUEST_COMPLETE_TOKEN = ";ROK"; |
|
25 const int REQUEST_COMPLETE_TOKEN_LENGTH = 4; |
|
26 const char REQUEST_DELIMITER_TOKEN = ';'; |
|
27 /*! |
|
28 \class ServiceLocalSocketIPC |
|
29 QLocalSocket based IPC client-side backend |
|
30 */ |
|
31 |
|
32 /*! |
|
33 Constructor |
|
34 */ |
|
35 ServiceLocalSocketIPC::ServiceLocalSocketIPC() : m_BufferType( ENoBuffer ) |
|
36 { |
|
37 m_Socket = new QLocalSocket(); |
|
38 QObject::connect(m_Socket, SIGNAL( error( QLocalSocket::LocalSocketError ) ), |
|
39 this, SLOT( handleError( QLocalSocket::LocalSocketError ) ) ); |
|
40 } |
|
41 |
|
42 /*! |
|
43 Destructor |
|
44 */ |
|
45 |
|
46 ServiceLocalSocketIPC::~ServiceLocalSocketIPC() |
|
47 { |
|
48 delete m_Socket; |
|
49 } |
|
50 |
|
51 /*! |
|
52 Connect to the server |
|
53 @param aServerName name of the server to connect to |
|
54 @return true if connected, false otherwise |
|
55 */ |
|
56 bool ServiceLocalSocketIPC::connect(const QString& aServerName) |
|
57 { |
|
58 bool rtn; |
|
59 m_Socket->connectToServer(aServerName); |
|
60 rtn = m_Socket->waitForConnected(); |
|
61 return rtn; |
|
62 } |
|
63 |
|
64 /*! |
|
65 Disconnect from the server |
|
66 */ |
|
67 void ServiceLocalSocketIPC::disconnect() |
|
68 { |
|
69 m_Socket->close(); |
|
70 } |
|
71 |
|
72 /*! |
|
73 Starts the service |
|
74 @param aServerName name of the server to connect to |
|
75 @param aExeName name of the server executable |
|
76 @return true if server started, false otherwise |
|
77 */ |
|
78 bool ServiceLocalSocketIPC::startServer(const QString& aServerName, |
|
79 const QString& aExeName) |
|
80 { |
|
81 bool started(true); |
|
82 |
|
83 //Semaphore with 1 initial count, |
|
84 //Use system semaphore to ensure no contention exists across multiple processes |
|
85 //According to QT documentation for System Semaphores on Windows, |
|
86 //the semaphore is automatically cleaned up if a process crashes, thus preventing deadlock |
|
87 // |
|
88 QSystemSemaphore funcSem(aServerName + FUNCTIONSEM, 1); |
|
89 funcSem.acquire(); |
|
90 |
|
91 // Shared chunk to check if the server has been started or not |
|
92 QSharedMemory sharedMem(aServerName); |
|
93 char* data(NULL); |
|
94 bool attached = sharedMem.attach(); |
|
95 if (attached) { |
|
96 data = (char*) sharedMem.data(); |
|
97 } |
|
98 |
|
99 // Shared memory not created or the flag was not set properly |
|
100 if (!attached || strcmp(data, SERVERNOTSTARTED) == 0) { |
|
101 // Create the server wait semaphore. When the server has listened, |
|
102 // it will signaled after listen has started |
|
103 // |
|
104 QSystemSemaphore sem(aServerName + SERVERSEM, 0); |
|
105 |
|
106 // Start the server, since this function is mutex'ed by the global semaphore |
|
107 // only 1 process/thread can reach here |
|
108 // |
|
109 started = QProcess::startDetached(aExeName); |
|
110 |
|
111 // Wait until the server signals |
|
112 if (started) { |
|
113 sem.acquire(); |
|
114 } |
|
115 } |
|
116 |
|
117 // Test if server started successfully |
|
118 #if _DEBUG |
|
119 attached = sharedMem.attach(); |
|
120 if( attached ) |
|
121 { |
|
122 data = (char*)sharedMem.data(); |
|
123 if( strcmp( data, SERVERSTARTED ) == 0 ) |
|
124 { |
|
125 qDebug() << "Server Started Successfully"; |
|
126 } |
|
127 } |
|
128 #endif // _DEBUG |
|
129 // Free shared memory |
|
130 sharedMem.detach(); |
|
131 |
|
132 // Release the function semaphore |
|
133 funcSem.release(1); |
|
134 return started; |
|
135 } |
|
136 |
|
137 /*! |
|
138 Send a request synchronously |
|
139 @param aRequestType type of request, toAscii() will be called to serialize the data |
|
140 @param aData aData data to send to the server |
|
141 @return true if data is sent, false otherwise |
|
142 */ |
|
143 bool ServiceLocalSocketIPC::sendSync(const QString& aRequestType, |
|
144 const QByteArray& aData) |
|
145 { |
|
146 QByteArray data; |
|
147 data.setNum(aData.length()); |
|
148 data.append(REQUEST_DELIMITER_TOKEN); |
|
149 data.append(aRequestType.toAscii()); |
|
150 data.append(REQUEST_DELIMITER_TOKEN); |
|
151 data.append(aData); |
|
152 int count = m_Socket->write(data); |
|
153 m_Socket->flush(); |
|
154 m_BufferType = ESyncBuffer; |
|
155 return (count > 0); |
|
156 } |
|
157 |
|
158 /*! |
|
159 Send a request asynchronously |
|
160 @param aRequestType type of request, toAscii() will be called to serialize the data |
|
161 @param aData data to send to the server |
|
162 */ |
|
163 void ServiceLocalSocketIPC::sendAsync(const QString& aRequestType, |
|
164 const QByteArray& aData) |
|
165 { |
|
166 QByteArray data; |
|
167 data.setNum(aData.length()); |
|
168 data.append(REQUEST_DELIMITER_TOKEN); |
|
169 data.append(aRequestType.toAscii()); |
|
170 data.append(REQUEST_DELIMITER_TOKEN); |
|
171 data.append(aData); |
|
172 m_Socket->write(data); |
|
173 |
|
174 // Connect the signal and reset aync data buffer |
|
175 m_AsyncData.clear(); |
|
176 QObject::connect(m_Socket, SIGNAL( readyRead() ), |
|
177 this, SLOT( handleReadyRead() ) ); |
|
178 m_BufferType = EAsyncBuffer; |
|
179 } |
|
180 |
|
181 /*! |
|
182 Reads all data pending in the buffer |
|
183 @return QByteArray data that has been read |
|
184 */ |
|
185 QByteArray ServiceLocalSocketIPC::readAll() |
|
186 { |
|
187 QByteArray result; |
|
188 |
|
189 // If asynchronous read all data from the socket |
|
190 // |
|
191 if ( m_BufferType == ESyncBuffer ) { |
|
192 // Wait for all data to be completed before returning |
|
193 // |
|
194 bool done = false; |
|
195 do { |
|
196 result.append(m_Socket->readAll()); |
|
197 if (result.right(REQUEST_COMPLETE_TOKEN_LENGTH) |
|
198 == REQUEST_COMPLETE_TOKEN) { |
|
199 // Chop the end token |
|
200 result.chop(REQUEST_COMPLETE_TOKEN_LENGTH); |
|
201 done = true; |
|
202 } |
|
203 } while (done == false); |
|
204 } |
|
205 // If async, return the internal databuffer |
|
206 else if( m_BufferType == EAsyncBuffer ){ |
|
207 // Should be just a d-ptr copy |
|
208 result = m_AsyncData; |
|
209 QObject::disconnect(m_Socket, SIGNAL( readyRead() ), |
|
210 this, SLOT( handleReadyRead() ) ); |
|
211 } |
|
212 m_BufferType = ENoBuffer; |
|
213 |
|
214 return result; |
|
215 } |
|
216 |
|
217 /*! |
|
218 Waits until data is available for reading |
|
219 @return bool true if data can be read |
|
220 */ |
|
221 bool ServiceLocalSocketIPC::waitForRead() |
|
222 { |
|
223 return m_Socket->waitForReadyRead(); |
|
224 } |
|
225 |
|
226 /*! |
|
227 Handle any socket errors |
|
228 @param socketError error |
|
229 */ |
|
230 void ServiceLocalSocketIPC::handleError(QLocalSocket::LocalSocketError aSocketError) |
|
231 { |
|
232 // Use base class to send this |
|
233 emitError(doMapErrors(aSocketError)); |
|
234 } |
|
235 |
|
236 /*! |
|
237 Handle when data is ready to be read |
|
238 */ |
|
239 void ServiceLocalSocketIPC::handleReadyRead() |
|
240 { |
|
241 m_AsyncData.append(m_Socket->readAll()); |
|
242 if (m_AsyncData.right(REQUEST_COMPLETE_TOKEN_LENGTH) |
|
243 == REQUEST_COMPLETE_TOKEN) { |
|
244 // Chop the end token |
|
245 m_AsyncData.chop(REQUEST_COMPLETE_TOKEN_LENGTH); |
|
246 |
|
247 // Use base class to send signal when all the data has been assembled |
|
248 emitReadyRead(); |
|
249 } |
|
250 } |
|
251 |
|
252 int ServiceLocalSocketIPC::doMapErrors( int aError ) |
|
253 { |
|
254 int error(0); |
|
255 |
|
256 // Map QT Local Socket error codes to custom error codes |
|
257 // |
|
258 switch( aError ) { |
|
259 case QLocalSocket::ConnectionError: |
|
260 case QLocalSocket::ConnectionRefusedError: { |
|
261 error = ServiceFwIPC::EConnectionError; |
|
262 break; |
|
263 } |
|
264 case QLocalSocket::PeerClosedError: { |
|
265 error = ServiceFwIPC::EConnectionClosed; |
|
266 break; |
|
267 } |
|
268 case QLocalSocket::ServerNotFoundError: { |
|
269 error = ServiceFwIPC::EServerNotFound; |
|
270 break; |
|
271 } |
|
272 case QLocalSocket::SocketAccessError: |
|
273 case QLocalSocket::SocketResourceError: |
|
274 case QLocalSocket::SocketTimeoutError: |
|
275 case QLocalSocket::DatagramTooLargeError: |
|
276 case QLocalSocket::UnsupportedSocketOperationError: { |
|
277 error = ServiceFwIPC::EIPCError; |
|
278 break; |
|
279 } |
|
280 case QLocalSocket::UnknownSocketError: { |
|
281 error = ServiceFwIPC::EUnknownError; |
|
282 break; |
|
283 } |
|
284 } |
|
285 return error; |
|
286 } |
|
287 |
|
288 } |
|
289 // END OF FILE |