73abe331 |
1 | /************************************************************************** |
2 | * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * |
3 | * * |
4 | * Author: The ALICE Off-line Project. * |
5 | * Contributors are mentioned in the code where appropriate. * |
6 | * * |
7 | * Permission to use, copy, modify and distribute this software and its * |
8 | * documentation strictly for non-commercial purposes is hereby granted * |
9 | * without fee, provided that the above copyright notice appears in all * |
10 | * copies and that both the copyright notice and this permission notice * |
11 | * appear in the supporting documentation. The authors make no claims * |
12 | * about the suitability of this software for any purpose. It is * |
13 | * provided "as is" without express or implied warranty. * |
14 | **************************************************************************/ |
15 | |
16 | /* |
17 | $Log$ |
18 | Revision 1.1.1.1 2005/09/12 22:11:40 byordano |
19 | SHUTTLE package |
20 | |
21 | Revision 1.3 2005/08/30 10:53:23 byordano |
22 | some more descriptions added |
23 | |
24 | */ |
25 | |
26 | // |
27 | // This class represents the AliDCSClient. |
28 | // The client used for data retrieval from DCS server. |
29 | // There are two way for retrieving data from the server. |
30 | // 1) asking for DP (DataPoint) - usually changed frequently. |
31 | // 2) asking for Alias (Alias) - alias should be the same through whole |
32 | // experimnet. |
33 | // |
34 | // There are two type of read operations: |
35 | // Asking for single alias/dp or asking for set of aliases/dp |
36 | // |
37 | // In case of ServerError the coresponding error code and |
38 | // error string (description) could be got by GetServerErrorCode() and |
39 | // GetServerErrorString() |
40 | // |
41 | |
42 | #include "AliDCSClient.h" |
43 | |
44 | #include "AliDCSValue.h" |
45 | #include "AliLog.h" |
46 | |
47 | #include <TList.h> |
48 | #include <TMap.h> |
49 | #include <TObjString.h> |
50 | #include <TSystem.h> |
51 | |
52 | ClassImp(AliDCSClient) |
53 | |
54 | const Int_t AliDCSClient::fgkBadState; |
55 | |
56 | const Int_t AliDCSClient::fgkInvalidParameter; |
57 | |
58 | const Int_t AliDCSClient::fgkTimeout; |
59 | |
60 | const Int_t AliDCSClient::fgkBadMessage; |
61 | |
62 | const Int_t AliDCSClient::fgkCommError; |
63 | |
64 | const Int_t AliDCSClient::fgkServerError; |
65 | |
66 | const char* AliDCSClient::fgkBadStateString = "BadState"; |
67 | |
68 | const char* AliDCSClient::fgkInvalidParameterString = "InvalidParameter"; |
69 | |
70 | const char* AliDCSClient::fgkTimeoutString = "Timeout"; |
71 | |
72 | const char* AliDCSClient::fgkBadMessageString = "BadMessage"; |
73 | |
74 | const char* AliDCSClient::fgkCommErrorString = "CommunicationError"; |
75 | |
76 | const char* AliDCSClient::fgkServerErrorString = "ServerError"; |
77 | |
78 | AliDCSClient::AliDCSClient(const char* host, Int_t port, UInt_t timeout, |
79 | Int_t retries): |
80 | fSocket(NULL), fTimeout(timeout), fRetries(retries), |
81 | fServerErrorCode(AliDCSMessage::kNoneError), fServerError("") |
82 | { |
83 | // |
84 | // host: DCS server host |
85 | // port: DCS server port |
86 | // timeout: in case of communication error or socket read/write this |
87 | // timeout will be used before the next try is made. |
88 | // retries: the number of retries after which the connection is |
89 | // is considered as invalid and error is returned. |
90 | // |
91 | |
92 | Int_t tries = 0; |
93 | |
94 | while (tries < fRetries) { |
95 | fSocket = new TSocket(host, port); |
96 | if (fSocket->IsValid()) { |
97 | AliDebug(1, Form("Connected to %s:%d", host, port)); |
98 | fSocket->SetOption(kNoBlock, 1); |
99 | break; |
100 | } |
101 | |
102 | AliDebug(1, Form("Connection timeout! tries <%d> ...", tries)); |
103 | |
104 | delete fSocket; |
105 | fSocket = NULL; |
106 | |
107 | gSystem->Sleep(fTimeout); |
108 | tries ++; |
109 | } |
110 | } |
111 | |
112 | AliDCSClient::~AliDCSClient() { |
113 | if (fSocket) { |
114 | Close(); |
115 | delete fSocket; |
116 | } |
117 | } |
118 | |
119 | Int_t AliDCSClient::SendBuffer(const char* buffer, Int_t size) { |
120 | |
121 | Int_t sentSize = 0; |
122 | Int_t tries = 0; |
123 | |
124 | while (sentSize < size && tries < fRetries) { |
125 | |
126 | Int_t sResult = fSocket->Select(TSocket::kWrite, fTimeout); |
127 | |
128 | if (sResult == 0) { |
129 | AliDebug(1, Form("Timeout! tries <%d> ...", tries)); |
130 | tries ++; |
131 | continue; |
132 | |
133 | } else if (sResult < 0) { |
134 | AliDebug(1, Form("Communication error <%d>!", |
135 | fSocket->GetErrorCode())); |
136 | return AliDCSClient::fgkCommError; |
137 | } |
138 | |
139 | sResult = fSocket->SendRaw(buffer + sentSize, size - sentSize, |
140 | kDontBlock); |
141 | |
142 | if (sResult > 0) { |
143 | sentSize += sResult; |
144 | } else { |
145 | AliDebug(1, Form("Communication error <%d>!", |
146 | fSocket->GetErrorCode())); |
147 | return AliDCSClient::fgkCommError; |
148 | } |
149 | } |
150 | |
151 | if (tries == fRetries) { |
152 | return AliDCSClient::fgkTimeout; |
153 | } |
154 | |
155 | return sentSize; |
156 | } |
157 | |
158 | Int_t AliDCSClient::ReceiveBuffer(char* buffer, Int_t size) { |
159 | |
160 | Int_t receivedSize = 0; |
161 | Int_t tries = 0; |
162 | |
163 | while (receivedSize < size && tries < fRetries) { |
164 | |
165 | Int_t sResult = fSocket->Select(TSocket::kRead, fTimeout); |
166 | |
167 | if (sResult == 0) { |
168 | AliDebug(1, Form("Timeout! tries <%d> ...", tries)); |
169 | tries ++; |
170 | continue; |
171 | |
172 | } else if (sResult < 0) { |
173 | AliDebug(1, Form("Communication error <%d>", |
174 | fSocket->GetErrorCode())); |
175 | return AliDCSClient::fgkCommError; |
176 | } |
177 | |
178 | sResult = fSocket->RecvRaw(buffer + receivedSize, |
179 | size - receivedSize, kDontBlock); |
180 | |
181 | if (sResult > 0) { |
182 | receivedSize += sResult; |
183 | } else { |
184 | AliDebug(1, Form("Communication error <%d>", |
185 | fSocket->GetErrorCode())); |
186 | return AliDCSClient::fgkCommError; |
187 | } |
188 | } |
189 | |
190 | if (tries == fRetries) { |
191 | return AliDCSClient::fgkTimeout; |
192 | } |
193 | |
194 | return receivedSize; |
195 | } |
196 | |
197 | Int_t AliDCSClient::SendMessage(AliDCSMessage& message) { |
198 | |
199 | message.StoreToBuffer(); |
200 | |
201 | AliDebug(2, "Sending message.\n"); |
202 | message.Print(); |
203 | |
204 | return SendBuffer(message.GetMessage(), message.GetMessageSize()); |
205 | } |
206 | |
207 | Int_t AliDCSClient::ReceiveMessage(AliDCSMessage& message) { |
208 | |
209 | char header[HEADER_SIZE]; |
210 | |
211 | Int_t sResult; |
212 | |
213 | if ((sResult = ReceiveBuffer(header, HEADER_SIZE)) < 0) { |
214 | AliDebug(1, Form("Can't receive message header! Reason: %s", |
215 | GetErrorString(sResult))); |
216 | return sResult; |
217 | } |
218 | |
219 | if (!message.SetRawHeader(header)) { |
220 | return AliDCSClient::fgkBadMessage; |
221 | } |
222 | |
223 | if ((sResult = ReceiveBuffer(message.GetBody(), |
224 | message.GetBodySize())) < 0) { |
225 | |
226 | AliDebug(1, Form("Can't receive message body! Reason: %s", |
227 | GetErrorString(sResult))); |
228 | return sResult; |
229 | } |
230 | |
231 | message.LoadFromBuffer(); |
232 | |
233 | AliDebug(2, "Message received."); |
234 | message.Print(); |
235 | |
236 | return HEADER_SIZE + sResult; |
237 | } |
238 | |
239 | Int_t AliDCSClient::GetValues(AliDCSMessage::RequestType reqType, |
240 | const char* reqString, UInt_t startTime, UInt_t endTime, TList& result) |
241 | { |
242 | if (!IsConnected()) { |
243 | AliError("Not connected!"); |
244 | return AliDCSClient::fgkBadState; |
245 | } |
246 | |
247 | Int_t sResult; |
248 | AliDCSMessage requestMessage; |
249 | requestMessage.CreateRequestMessage(reqType, startTime, endTime, |
250 | reqString); |
251 | |
252 | if ((sResult = SendMessage(requestMessage)) < 0) { |
253 | AliError(Form("Can't send request message! Reason: %s", |
254 | GetErrorString(sResult))); |
255 | Close(); |
256 | return sResult; |
257 | } |
258 | |
259 | sResult = ReceiveValueSet(result); |
260 | |
261 | Close(); |
262 | |
263 | return sResult; |
264 | } |
265 | |
266 | Int_t AliDCSClient::GetValues(AliDCSMessage::RequestType reqType, |
267 | UInt_t startTime, UInt_t endTime, TMap& result) |
268 | { |
269 | if (!IsConnected()) { |
270 | AliError("Not connected!"); |
271 | return AliDCSClient::fgkBadState; |
272 | } |
273 | |
274 | AliDCSMessage multiRequestMessage; |
275 | multiRequestMessage.CreateMultiRequestMessage(reqType, |
276 | startTime, endTime); |
277 | |
278 | TList requests; |
279 | |
280 | TIter iter(&result); |
281 | TObjString* aRequest; |
282 | |
283 | // copy request strings to temporary TList because |
284 | // TMap doesn't guarantee the order of elements!!! |
285 | while ((aRequest = (TObjString*) iter.Next())) { |
286 | requests.Add(aRequest); |
287 | if (!multiRequestMessage.AddRequestString(aRequest->String())) |
288 | { |
289 | return AliDCSClient::fgkInvalidParameter; |
290 | } |
291 | } |
292 | |
293 | Int_t sResult; |
294 | if ((sResult = SendMessage(multiRequestMessage)) < 0) { |
295 | AliError(Form("Can't send request message! Reason: %s", |
296 | GetErrorString(sResult))); |
297 | Close(); |
298 | return sResult; |
299 | } |
300 | |
301 | result.SetOwner(0); |
302 | result.Clear(); |
303 | |
304 | TIter reqIter(&requests); |
305 | while ((aRequest = (TObjString*) reqIter.Next())) { |
306 | TList* resultSet = new TList(); |
307 | resultSet->SetOwner(1); |
308 | |
309 | if ((sResult = ReceiveValueSet(*resultSet)) < 0) { |
310 | AliError(Form("Can't get values for %s!" , |
311 | aRequest->String().Data())); |
312 | |
313 | delete resultSet; |
314 | break; |
315 | } |
316 | |
317 | result.Add(aRequest, resultSet); |
318 | } |
319 | |
320 | if (sResult < 0) { |
321 | result.DeleteValues(); |
322 | result.Clear(); |
323 | |
324 | requests.Delete(); |
325 | } else { |
326 | result.SetOwner(1); |
327 | } |
328 | |
329 | Close(); |
330 | |
331 | return sResult; |
332 | } |
333 | |
334 | Int_t AliDCSClient::ReceiveValueSet(TList& result) { |
335 | |
336 | Int_t sResult; |
337 | |
338 | AliDCSMessage responseMessage; |
339 | if ((sResult = ReceiveMessage(responseMessage)) < 0) { |
340 | AliError(Form("Can't receive response message! Reason: %s", |
341 | GetErrorString(sResult))); |
342 | return sResult; |
343 | } |
344 | |
345 | UInt_t valueCount; |
346 | |
347 | if (responseMessage.GetType() == AliDCSMessage::kCount) { |
348 | valueCount = responseMessage.GetCount(); |
349 | |
350 | } else if (responseMessage.GetType() == AliDCSMessage::kError) { |
351 | fServerErrorCode = responseMessage.GetErrorCode(); |
352 | fServerError = responseMessage.GetErrorString(); |
353 | |
354 | return AliDCSClient::fgkServerError; |
355 | |
356 | } else { |
357 | AliError("Bad message type received!"); |
358 | return AliDCSClient::fgkBadMessage; |
359 | } |
360 | |
361 | UInt_t receivedValues = 0; |
362 | |
363 | AliSimpleValue::Type valueType = AliSimpleValue::kInvalid; |
364 | |
365 | while (receivedValues < valueCount) { |
366 | |
367 | AliDCSMessage message; |
368 | |
369 | if ((sResult = ReceiveMessage(message)) < 0) { |
370 | AliError(Form("Can't receive message! Reason: %s", |
371 | GetErrorString(sResult))); |
372 | return sResult; |
373 | } |
374 | |
375 | if (message.GetType() == AliDCSMessage::kResultSet) { |
376 | |
377 | if (valueType == AliSimpleValue::kInvalid) { |
378 | valueType = message.GetSimpleValueType(); |
379 | } else { |
380 | if (valueType != message.GetSimpleValueType()) { |
381 | AliError("Unexpected value type!"); |
382 | return AliDCSClient::fgkBadMessage; |
383 | } |
384 | } |
385 | |
386 | receivedValues += message.GetValues(result); |
387 | |
388 | if (receivedValues > valueCount) { |
389 | AliError("Message contains more values than expected!"); |
390 | return AliDCSClient::fgkBadMessage; |
391 | } |
392 | |
393 | } else if (message.GetType() == AliDCSMessage::kError) { |
394 | fServerErrorCode = |
395 | responseMessage.GetErrorCode(); |
396 | fServerError = responseMessage.GetErrorString(); |
397 | |
398 | return AliDCSClient::fgkServerError; |
399 | } else { |
400 | AliError("Bad message type received!"); |
401 | return AliDCSClient::fgkBadMessage; |
402 | } |
403 | } |
404 | |
405 | return receivedValues; |
406 | } |
407 | |
408 | Int_t AliDCSClient::GetDPValues(const char* dpName, UInt_t startTime, |
409 | UInt_t endTime, TList& result) |
410 | { |
411 | // |
412 | // Reads a values from the server which correspond to this |
413 | // DataPoint (dpName) in time interval (startTime - endTime). |
414 | // result: Collection of AliDCSValue which contains the read values. |
415 | // |
416 | // Returns: |
417 | // If >= 0 , the number of values read. |
418 | // if < 0, the error code which has occured during the read. |
419 | // |
420 | |
421 | return GetValues(AliDCSMessage::kDPName, |
422 | dpName, startTime, endTime, result); |
423 | } |
424 | |
425 | Int_t AliDCSClient::GetAliasValues(const char* alias, UInt_t startTime, |
426 | UInt_t endTime, TList& result) |
427 | { |
428 | // |
429 | // Reads a values from the server which correspond to this |
430 | // alias (alias) in time interval (startTime - endTime). |
431 | // result: Collection of AliDCSValue which contains the read values. |
432 | // |
433 | // Returns: |
434 | // If >= 0 , the number of values read. |
435 | // if < 0, the error code which has occured during the read. |
436 | // |
437 | |
438 | return GetValues(AliDCSMessage::kAlias, |
439 | alias, startTime, endTime, result); |
440 | } |
441 | |
442 | Int_t AliDCSClient::GetDPValues(UInt_t startTime, UInt_t endTime, |
443 | TMap& result) |
444 | { |
445 | // |
446 | // For every key of 'result' (which must be TObjString) |
447 | // reads a valueSet. The key represents particular DataPoint to be read. |
448 | // For all DataPoints time interval (startTime - endTime) is used. |
449 | // After the read, the correspoding value for every key is a |
450 | // TList - collection of AliDCSValue, or result is an empty map in |
451 | // case of error. |
452 | // |
453 | // Returns: |
454 | // If >= 0 , the number of values read. |
455 | // if < 0, the error code which has occured during the read. |
456 | // |
457 | |
458 | return GetValues(AliDCSMessage::kDPName, startTime, endTime, result); |
459 | } |
460 | |
461 | Int_t AliDCSClient::GetAliasValues(UInt_t startTime, UInt_t endTime, |
462 | TMap& result) |
463 | { |
464 | // |
465 | // For every key of 'result' (which must be TObjString) |
466 | // reads a valueSet. The key represents particular Alias to be read. |
467 | // For all aliases time interval (startTime - endTime) is used. |
468 | // After the read, the correspoding value for every key is a |
469 | // TList - collection of AliDCSValue, or result is an empty map in |
470 | // case of error. |
471 | // |
472 | // Returns: |
473 | // If >= 0 , the number of values read. |
474 | // if < 0, the error code which has occured during the read. |
475 | // |
476 | |
477 | return GetValues(AliDCSMessage::kAlias, startTime, endTime, result); |
478 | } |
479 | |
480 | Bool_t AliDCSClient::IsConnected() { |
481 | // |
482 | // Returns kTRUE if there is a valid connection to the server. |
483 | // |
484 | |
485 | if (fSocket) { |
486 | return fSocket->IsValid(); |
487 | } |
488 | |
489 | return kFALSE; |
490 | } |
491 | |
492 | void AliDCSClient::Close() { |
493 | // |
494 | // Close the connection. |
495 | // |
496 | |
497 | if (fSocket) { |
498 | fSocket->Close(); |
499 | } |
500 | } |
501 | |
502 | const char* AliDCSClient::GetErrorString(Int_t code) { |
503 | // |
504 | // Returns a short string describing the error code. |
505 | // code: the error code. |
506 | // |
507 | |
508 | |
509 | switch (code) { |
510 | case AliDCSClient::fgkBadState: |
511 | return AliDCSClient::fgkBadStateString; |
512 | |
513 | case AliDCSClient::fgkInvalidParameter: |
514 | return AliDCSClient::fgkInvalidParameterString; |
515 | |
516 | case AliDCSClient::fgkTimeout: |
517 | return AliDCSClient::fgkTimeoutString; |
518 | |
519 | case AliDCSClient::fgkBadMessage: |
520 | return AliDCSClient::fgkBadMessageString; |
521 | |
522 | case AliDCSClient::fgkCommError: |
523 | return AliDCSClient::fgkCommErrorString; |
524 | |
525 | case AliDCSClient::fgkServerError: |
526 | return AliDCSClient::fgkServerErrorString; |
527 | |
528 | default: |
529 | AliErrorGeneral("AliDCSClient::GetErrorString", |
530 | "Unknown error code!"); |
531 | return "UnknownCode"; |
532 | } |
533 | } |
534 | |