|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * This file contains implementation of the DataGatewaySOAPServerThread, |
|
16 * DataGatewayClientThread and DataGateway classes. |
|
17 */ |
|
18 |
|
19 // INCLUDES |
|
20 #include "stdsoap2.h" //should be first because of WinSock2.h errors |
|
21 #include "datagateway.h" |
|
22 #include "hticommon.h" |
|
23 #include "HtiMessage.h" |
|
24 #include <sstream> |
|
25 |
|
26 /* |
|
27 * This method is used to print the SOAP fault to a string |
|
28 */ |
|
29 void soap_sprint_fault(struct soap *soap, char *fd) |
|
30 { if (soap->error) |
|
31 { const char *c, *v = NULL, *s, **d; |
|
32 d = soap_faultcode(soap); |
|
33 if (!*d) |
|
34 soap_set_fault(soap); |
|
35 c = *d; |
|
36 if (soap->version == 2) |
|
37 v = *soap_faultsubcode(soap); |
|
38 s = *soap_faultstring(soap); |
|
39 d = soap_faultdetail(soap); |
|
40 sprintf(fd, "%s%d fault: %s [%s]\n\"%s\"\nDetail: %s\n", soap->version ? "SOAP 1." : "Error ", soap->version ? (int)soap->version : soap->error, c, v ? v : "no subcode", s ? s : "[no reason]", d && *d ? *d : "[no detail]"); |
|
41 } |
|
42 } |
|
43 |
|
44 //********************************************************************************** |
|
45 // Class DataGatewaySOAPServerThread |
|
46 // |
|
47 // This thread acts as a SOAP server, it listens to SOAP requests and forwards them |
|
48 // to HtiDispatcher which then forwards them to correct SOAPHandlers |
|
49 //********************************************************************************** |
|
50 |
|
51 DataGatewaySOAPServerThread::DataGatewaySOAPServerThread(HtiDispatcher* htiDispatcher, |
|
52 int port) |
|
53 : m_HtiDispatcher(htiDispatcher),m_TcpPort(port),m_Running(true) |
|
54 { |
|
55 } |
|
56 |
|
57 /* |
|
58 * This loop listens to incoming Soap reuests and forwards them to HtiDispatcher |
|
59 */ |
|
60 void DataGatewaySOAPServerThread::Run() |
|
61 { |
|
62 struct soap soap; |
|
63 //Initializes a static/stack-allocated runtime environment |
|
64 soap_init(&soap); |
|
65 //soap_init2(&soap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE); |
|
66 //_CrtDbgReport(_CRT_ERROR, _CRTDBG_MODE_WNDW); |
|
67 /* |
|
68 #ifdef _DEBUG |
|
69 HANDLE hLogFile; |
|
70 hLogFile = CreateFile("c:\\log.txt", GENERIC_WRITE, FILE_SHARE_WRITE, |
|
71 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
|
72 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); |
|
73 _CrtSetReportFile(_CRT_WARN, hLogFile); |
|
74 |
|
75 #endif |
|
76 */ |
|
77 while (m_Running) |
|
78 { |
|
79 int m, s; // master and slave sockets |
|
80 Util::Debug("soap_init"); |
|
81 |
|
82 //Returns master socket (backlog = max. queue size for requests). When host==NULL: host is the machine on which the service runs |
|
83 m = soap_bind(&soap, NULL, m_TcpPort, 100); |
|
84 if (m < 0) |
|
85 { |
|
86 //Util::Error("Failed to open socket", m_TcpPort); |
|
87 //soap_print_fault(&soap, stderr); |
|
88 char temp[512]; |
|
89 soap_sprint_fault(&soap, temp); |
|
90 Util::Error(temp); |
|
91 break; |
|
92 } |
|
93 else |
|
94 { |
|
95 Util::Debug("Socket connection successful"); |
|
96 /* |
|
97 #ifdef _DEBUG |
|
98 _CrtMemState startMem, endMem, diffMem; |
|
99 //Sleep(5000); |
|
100 #endif |
|
101 */ |
|
102 for (int i = 1; ; i++) |
|
103 { |
|
104 //_RPT1(_CRT_WARN, "---++++=======Iter %d=======++++---\n", i); |
|
105 //_RPT0(_CRT_WARN, "---Start dump---\n"); |
|
106 |
|
107 //_CrtMemCheckpoint(&startMem); |
|
108 //_CrtMemDumpStatistics(&startMem); |
|
109 //Returns slave socket |
|
110 s = soap_accept(&soap); |
|
111 if (s < 0) |
|
112 { |
|
113 //soap_print_fault(&soap, stderr); |
|
114 char temp[512]; |
|
115 soap_sprint_fault(&soap, temp); |
|
116 Util::Error(temp); |
|
117 |
|
118 break; |
|
119 } |
|
120 Util::Debug(" accepted connection"); |
|
121 |
|
122 //start of my dispatching code |
|
123 if ( !m_HtiDispatcher->DispatchSoapServe( &soap ) ) // process RPC request |
|
124 { |
|
125 //soap_print_fault(&soap, stderr); // print error |
|
126 // clean up class instances |
|
127 soap_destroy(&soap); |
|
128 // clean up everything and close socket |
|
129 soap_end(&soap); |
|
130 } |
|
131 else |
|
132 { |
|
133 // clean up allcated data |
|
134 soap_dealloc(&soap, NULL); |
|
135 // clean up class instances |
|
136 soap_destroy(&soap); |
|
137 //cleanup temp data |
|
138 soap_free(&soap); |
|
139 |
|
140 //soap_end(&soap); // clean up everything and close socket |
|
141 } |
|
142 /* |
|
143 #ifdef _DEBUG |
|
144 //Sleep(2000); //wait when hadler thread is over |
|
145 |
|
146 //copy |
|
147 memcpy( &startMem, &endMem, sizeof(_CrtMemState) ); |
|
148 _CrtMemCheckpoint(&endMem); |
|
149 _CrtMemDumpStatistics(&endMem); |
|
150 |
|
151 _RPT0(_CRT_WARN, "==========End diff==========\n"); |
|
152 |
|
153 if (_CrtMemDifference( &diffMem, &startMem, &endMem ) ) |
|
154 { |
|
155 |
|
156 _CrtMemDumpStatistics(&diffMem); |
|
157 _RPT0(_CRT_WARN, "########## Objects #############\n"); |
|
158 //_CrtMemDumpAllObjectsSince( &diffMem ); |
|
159 _RPT0(_CRT_WARN, "++++++End dump++++++\n"); |
|
160 } |
|
161 #endif |
|
162 */ |
|
163 Util::Debug("request dispatched"); |
|
164 } |
|
165 } |
|
166 } |
|
167 // Clean up deserialized data (except class instances) and temporary data |
|
168 soap_end(&soap); |
|
169 // close master socket and detach environment |
|
170 soap_done(&soap); |
|
171 Stop(); |
|
172 //#ifdef _DEBUG |
|
173 // CloseHandle(hLogFile); |
|
174 //#endif |
|
175 } |
|
176 |
|
177 void DataGatewaySOAPServerThread::Stop() |
|
178 { |
|
179 m_Running = false; |
|
180 } |
|
181 |
|
182 bool DataGatewaySOAPServerThread::IsRunning() |
|
183 { |
|
184 return m_Running; |
|
185 } |
|
186 |
|
187 //********************************************************************************** |
|
188 // Class DataGatewayClientThread |
|
189 // |
|
190 // This thread serves DataGateway's clients |
|
191 // Gets Data objects from incoming queue and forwards them to CommChannelPlugin. |
|
192 // The Data objects are actually SOAP requests which were received by DataGatewaySOAPServerThread handled by SOAPHandler and transferred to HtiMessages and eventually Data objects |
|
193 // The thread also reads incoming data from CommChannelPlugin and forwards them to outgoing queue which |
|
194 // HtiDispatcher then reads and forwards to correct SOAPHandler |
|
195 //********************************************************************************** |
|
196 |
|
197 DataGatewayClientThread::DataGatewayClientThread(int port, |
|
198 long bufsize, |
|
199 const string& commchannel) |
|
200 : m_HtiDispatcher(&m_ReaderQueue, &m_WriterQueue), |
|
201 m_SoapListener(&m_HtiDispatcher, port), |
|
202 m_CommChannelPluginName(commchannel), |
|
203 m_Running(true) |
|
204 { |
|
205 m_CCLateInit = true; |
|
206 |
|
207 if (bufsize > 0) |
|
208 { |
|
209 m_TcpIpBufferSize = bufsize; |
|
210 } |
|
211 else |
|
212 { |
|
213 m_TcpIpBufferSize = g_DataGatewayDefaultTcpIpBufferSize; |
|
214 } |
|
215 } |
|
216 |
|
217 DataGatewayClientThread::DataGatewayClientThread(int port, |
|
218 long bufsize, |
|
219 CommChannelPlugin** f) |
|
220 : m_HtiDispatcher(&m_ReaderQueue, &m_WriterQueue), |
|
221 m_SoapListener(&m_HtiDispatcher, port), |
|
222 m_CommChannelPluginName((*f)->GetName()), |
|
223 m_Running(true) |
|
224 { |
|
225 m_CCLateInit = false; |
|
226 |
|
227 m_CommChannelPlugin = *f; |
|
228 if (bufsize > 0) |
|
229 { |
|
230 m_TcpIpBufferSize = bufsize; |
|
231 } |
|
232 else |
|
233 { |
|
234 m_TcpIpBufferSize = g_DataGatewayDefaultTcpIpBufferSize; |
|
235 } |
|
236 } |
|
237 |
|
238 DataGatewayClientThread::~DataGatewayClientThread() |
|
239 { |
|
240 Util::Debug("DataGatewayClientThread::~DataGatewayClientThread()"); |
|
241 if (m_Running) |
|
242 { |
|
243 Stop(); |
|
244 } |
|
245 } |
|
246 |
|
247 /* |
|
248 * Main loop of thread |
|
249 * |
|
250 * Gets Data from incoming queue and forwards it to CommChannelPlugin. |
|
251 * Reads incoming data from CommChannelPlugin and forwards them to outgoing queue |
|
252 */ |
|
253 void DataGatewayClientThread::Run() |
|
254 { |
|
255 DWORD res; |
|
256 |
|
257 if (m_CCLateInit) |
|
258 { |
|
259 m_CommChannelPlugin = CommChannelPlugin::Instance(m_CommChannelPluginName); |
|
260 if (m_CommChannelPlugin == NULL) |
|
261 { |
|
262 g_ErrorCode = ERR_DG_COMMCHANNEL; |
|
263 return; |
|
264 } |
|
265 if ((res = m_CommChannelPlugin->Connect()) != NO_ERRORS) |
|
266 { |
|
267 Util::Error("[HtiGateway] Error - Cannot connect to the target."); |
|
268 m_CommChannelPlugin->Disconnect(); |
|
269 g_ErrorCode = res; |
|
270 return; |
|
271 } |
|
272 Util::Info("[HtiGateway] Communication Channel Plugin loaded succesfully"); |
|
273 } |
|
274 |
|
275 m_SoapListener.Start(); |
|
276 m_HtiDispatcher.Start(); |
|
277 |
|
278 // Flush comm input buffer; |
|
279 Data* dummy; |
|
280 while (m_CommChannelPlugin->Receive(&dummy) == NO_ERRORS) |
|
281 { |
|
282 dummy->FreeData(); |
|
283 continue; |
|
284 } |
|
285 dummy = NULL; |
|
286 |
|
287 while (m_Running) |
|
288 { |
|
289 if (!m_SoapListener.IsRunning() || |
|
290 !m_HtiDispatcher.IsRunning()) |
|
291 { |
|
292 Stop(); |
|
293 break; |
|
294 } |
|
295 |
|
296 // Receiving from TCP/IP port and |
|
297 // sending to CommChannelPlugin |
|
298 try { |
|
299 Data* d = m_ReaderQueue.front(50); |
|
300 m_ReaderQueue.pop(); |
|
301 m_CommChannelPlugin->Send(d); |
|
302 //_RPT2(_CRT_WARN,"DataGateway::Send %x %x\n", d, d->GetData()); |
|
303 d = NULL; |
|
304 } catch (TimeoutException te) |
|
305 { |
|
306 //Util::Debug("DataGatewayClientThread::TimeoutException"); |
|
307 } |
|
308 |
|
309 // Receiving from CommChannelPlugin and |
|
310 // sending data to TCP/IP port. If message |
|
311 // is error or control message it is also |
|
312 // handled here. |
|
313 Data* out; |
|
314 |
|
315 if (m_CommChannelPlugin->Receive(&out) != NO_ERRORS) continue; |
|
316 //_RPT2(_CRT_WARN,"DataGateway::Receive %x %x\n", out, out->GetData()); |
|
317 //printf(">>>>>>>>>Type %d clt<<<<<<\n", out->GetType()); |
|
318 switch (out->GetType()) |
|
319 { |
|
320 case Data::EData: |
|
321 { |
|
322 |
|
323 //printf("\t\tpush = %d\n", m_WriterQueue.size()); |
|
324 m_WriterQueue.push(out); |
|
325 //_RPT0(_CRT_WARN,"DataGateway::Write out NULL\n"); |
|
326 out = NULL; |
|
327 } |
|
328 break; |
|
329 case Data::EControl: |
|
330 { |
|
331 Util::Debug("ClientThread: Control Message Received"); |
|
332 /* |
|
333 switch (*(BYTE*)out->GetData()) |
|
334 { |
|
335 case ControlPhonePowered: |
|
336 { |
|
337 Util::Info("[HtiGateway] Phone powered up"); |
|
338 } |
|
339 break; |
|
340 } |
|
341 */ |
|
342 //generate HTI error message for waiting handlers |
|
343 //putting control message content in the detail field |
|
344 HtiMessage* errMsg = HtiMessage::CreateErrorMessage(0, (char*)out->GetData() ); |
|
345 out->FreeData(); |
|
346 out->SetData( errMsg->HtiData(), errMsg->HtiDataSize(), Data::EData); |
|
347 m_WriterQueue.push(out); |
|
348 out = NULL; |
|
349 } |
|
350 break; |
|
351 case Data::EError: |
|
352 { |
|
353 Util::Debug("ClientThread: Error Message Received"); |
|
354 Stop(); |
|
355 } |
|
356 break; |
|
357 |
|
358 default: |
|
359 { |
|
360 Util::Debug("ClientThread: Unknown Message Received"); |
|
361 } |
|
362 break; |
|
363 } |
|
364 delete out; |
|
365 out = NULL; |
|
366 } |
|
367 |
|
368 if (m_CCLateInit) |
|
369 { |
|
370 m_CommChannelPlugin->Disconnect(); |
|
371 Util::Info("[HtiGateway] Communication Channel Plugin unloaded"); |
|
372 m_CommChannelPlugin = NULL; |
|
373 } |
|
374 } |
|
375 |
|
376 void DataGatewayClientThread::Stop() |
|
377 { |
|
378 m_Running = false; |
|
379 m_SoapListener.Stop(); |
|
380 m_HtiDispatcher.Stop(); |
|
381 HANDLE handles[2]; |
|
382 handles[0] = m_SoapListener.ThreadHandle(); |
|
383 handles[1] = m_HtiDispatcher.ThreadHandle(); |
|
384 WaitForMultipleObjects(2, handles, TRUE, g_MaximumShutdownWaitTime); |
|
385 } |
|
386 |
|
387 //********************************************************************************** |
|
388 // Class DataGateway |
|
389 // |
|
390 // Main class/thread of HtiGateway |
|
391 //********************************************************************************** |
|
392 |
|
393 DataGateway::DataGateway(int port, |
|
394 long bufsize, |
|
395 const string& commchannel, |
|
396 bool stayalive, |
|
397 bool cclateinit) |
|
398 : m_TcpIpPort(port), |
|
399 m_TcpIpBufferSize(bufsize), |
|
400 m_CommChannelPluginName(commchannel), |
|
401 m_StayAlive(stayalive), |
|
402 m_CCLateInit(cclateinit), |
|
403 m_Running(true) |
|
404 { |
|
405 m_CommChannelPlugin = NULL; |
|
406 } |
|
407 |
|
408 /* |
|
409 * Main loop of HtiGateway |
|
410 * This loop: |
|
411 * -creates instance of CommChannelPlugin if lateinit isn't set on |
|
412 * -starts DataGatewayClient thread to serve the client |
|
413 */ |
|
414 void DataGateway::Run() |
|
415 { |
|
416 DWORD res; |
|
417 |
|
418 try |
|
419 { |
|
420 if (Util::GetVerboseLevel() >= Util::VerboseLevel::info) |
|
421 { |
|
422 char tmp[256]; |
|
423 sprintf(tmp, "[HtiGateway] Using TCP/IP port %d", m_TcpIpPort); |
|
424 string s(tmp); |
|
425 Util::Info(s); |
|
426 |
|
427 //sprintf(tmp, "[HtiGateway] TCP/IP receive buffer size is %d bytes", m_TcpIpBufferSize); |
|
428 //s.assign(tmp); |
|
429 //Util::Info(s); |
|
430 |
|
431 sprintf(tmp, "[HtiGateway] Loading Communication Channel Plugin for [%s]", m_CommChannelPluginName.c_str()); |
|
432 s.assign(tmp); |
|
433 Util::Info(s); |
|
434 } |
|
435 |
|
436 //SocketServer in(m_TcpIpPort, 1); |
|
437 //Util::Info("[HtiGateway] TCP/IP port opened"); |
|
438 |
|
439 if (!m_CCLateInit) |
|
440 { |
|
441 m_CommChannelPlugin = CommChannelPlugin::Instance(m_CommChannelPluginName); |
|
442 if (m_CommChannelPlugin == NULL) |
|
443 { |
|
444 throw UtilError("[HtiGateway] Error loading Communication Channel.", ERR_DG_COMMCHANNEL); |
|
445 } |
|
446 if ((res = m_CommChannelPlugin->Connect()) != NO_ERRORS) |
|
447 { |
|
448 m_CommChannelPlugin->Disconnect(); |
|
449 throw UtilError("[HtiGateway] Error connecting to the target.", res); |
|
450 } |
|
451 Util::Info("[HtiGateway] Communication Channel Plugin loaded succesfully"); |
|
452 } |
|
453 else |
|
454 { |
|
455 Util::Info("[HtiGateway] Communication Channel Plugin uses late initialization."); |
|
456 } |
|
457 |
|
458 g_ErrorCode = NO_ERRORS; |
|
459 Util::Info("[HtiGateway] Waiting connection"); |
|
460 //Socket* s = in.Accept(); |
|
461 Util::Info("[HtiGateway] Connection established"); |
|
462 DataGatewayClientThread* client; |
|
463 if (m_CCLateInit) |
|
464 { |
|
465 client = new DataGatewayClientThread(m_TcpIpPort, |
|
466 m_TcpIpBufferSize, |
|
467 m_CommChannelPluginName); |
|
468 } |
|
469 else |
|
470 { |
|
471 client = new DataGatewayClientThread(m_TcpIpPort, |
|
472 m_TcpIpBufferSize, |
|
473 &m_CommChannelPlugin); |
|
474 } |
|
475 client->Start(); |
|
476 |
|
477 HANDLE handles[2]; |
|
478 handles[0] = client->ThreadHandle(); |
|
479 handles[1] = m_ShutdownEvent.EventHandle(); |
|
480 DWORD dwResult = WaitForMultipleObjects(2, handles, FALSE, INFINITE); |
|
481 switch (dwResult) |
|
482 { |
|
483 case WAIT_OBJECT_0 + 0: |
|
484 { |
|
485 Util::Debug("DataGateway::Run() Client thread stopped"); |
|
486 } |
|
487 break; |
|
488 case WAIT_OBJECT_0 + 1: |
|
489 { |
|
490 Util::Debug("DataGateway::Run() Request to shutdown"); |
|
491 client->Stop(); |
|
492 WaitForSingleObject(client->ThreadHandle(), g_MaximumShutdownWaitTime); |
|
493 } |
|
494 break; |
|
495 } |
|
496 Util::Info("[HtiGateway] Connection closed."); |
|
497 delete client; |
|
498 client = NULL; |
|
499 //if (!m_StayAlive) break; |
|
500 if (!m_CCLateInit) |
|
501 { |
|
502 m_CommChannelPlugin->Disconnect(); |
|
503 Util::Info("[HtiGateway] Communication Channel Plugin unloaded"); |
|
504 m_CommChannelPlugin = NULL; |
|
505 } |
|
506 } catch (char* s) { |
|
507 char tmp[64]; |
|
508 sprintf(tmp, "[HtiGateway] Error opening TCP/IP port - %s", s); |
|
509 Util::Error(tmp); |
|
510 g_ErrorCode = ERR_DG_SOCKET; |
|
511 } catch (UtilError ue) { |
|
512 Util::Error(ue.iError, ue.iResult); |
|
513 g_ErrorCode = ue.iResult; |
|
514 } |
|
515 Util::Info("[HtiGateway] Closed"); |
|
516 } |
|
517 |
|
518 void DataGateway::Stop() |
|
519 { |
|
520 m_Running = false; |
|
521 m_ShutdownEvent.Set(); |
|
522 } |
|
523 |
|
524 bool DataGateway::IsRunning() |
|
525 { |
|
526 return m_Running; |
|
527 } |
|
528 |
|
529 // End of the file |