source: branches/fscctrl_safety_limits/dim/src/feeserver.c@ 18758

Last change on this file since 18758 was 11071, checked in by tbretz, 13 years ago
Replaced v19r21 by a version extracted with 'unzip -a' to get proper unix text format.
File size: 121.3 KB
Line 
1 Return to feeserver.c CVS log Up to [MAIN] / dcscvs / FeeServer / feeserver / src
2
3--------------------------------------------------------------------------------
4File: [MAIN] / dcscvs / FeeServer / feeserver / src / feeserver.c (download)
5Revision: 1.26, Wed May 7 14:08:13 2008 UTC (22 months ago) by dominik
6Branch: MAIN
7CVS Tags: d, HEAD, FeeServer_v0-9-4_RCU-v0-9-9-dev, FeeServer_v0-9-4_RCU-v0-9-8-dev, FeeServer_v0-9-4_RCU-v0-9-7-dev, FeeServer_v0-9-4_RCU-v0-9-6-dev, FeeServer_v0-9-4_RCU-v0-9-5-dev, FeeServer_v0-9-4_RCU-v0-9-4, FeeServer_v0-9-4_RCU-v0-9-14-dev, FeeServer_v0-9-4_RCU-v0-9-13-dev, FeeServer_v0-9-4_RCU-v0-9-12-dev, FeeServer_v0-9-4_RCU-v0-9-11-dev, FeeServer_v0-9-4_RCU-v0-9-10-dev
8Changes since 1.25: +32 -16 lines
9updated to core version 0.9.4
10
11
12
13--------------------------------------------------------------------------------
14
15/************************************************************************
16 **
17 **
18 ** This file is property of and copyright by the Department of Physics
19 ** Institute for Physic and Technology, University of Bergen,
20 ** Bergen, Norway.
21 ** In cooperation with Center for Technology Transfer and
22 ** Telecommunication (ZTT), University of Applied Sciences Worms
23 ** Worms, Germany.
24 **
25 ** This file has been written by Sebastian Bablok,
26 ** Sebastian.Bablok@uib.no
27 **
28 ** Important: This file is provided without any warranty, including
29 ** fitness for any particular purpose. Further distribution of this file,
30 ** even with changes in the code, is only allowed, when this copyright
31 ** and warranty paragraph is kept unchanged and included to the sources.
32 **
33 **
34 *************************************************************************/
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h> // for pause() necessary
39#include <string.h>
40#include <dim/dis.h> // dimserver library
41#include <math.h> // for fabsf
42
43#include <time.h> // time for threads
44#include <sys/time.h> // for gettimeofday()
45#include <pthread.h>
46//#include <stdbool.h> // included by fee_types.h
47#include <errno.h> // for the error numbers
48#include <signal.h>
49
50#include "fee_types.h" // declaration of own datatypes
51#include "fee_functions.h" // declaration of feeServer functions
52#include "fee_defines.h" // declaration of all globaly used constants
53#include "feepacket_flags.h" // declaration of flag bits in a feepacket
54#include "fee_errors.h" // defines of error codes
55#include "ce_command.h" //control engine header file
56
57#ifdef __UTEST
58#include "fee_utest.h"
59#endif
60
61/**
62 * @defgroup feesrv_core The FeeServer core
63 */
64
65//-- global variables --
66
67/**
68 * state of the server, possible states are: COLLECTING, RUNNING and ERROR_STATE.
69 * @ingroup feesrv_core
70 */
71static int state = COLLECTING;
72
73/**
74 * indicates, if CEReady has been signaled (used in backup solution of init watch dog).
75 * @ingroup feesrv_core
76 */
77static bool ceReadySignaled = false;
78
79/**
80 * Variable provides the init state of the CE.
81 * @ingroup feesrv_core
82 */
83static int ceInitState = CE_NOT_INIT; // CE_OK; this has changed in version 0.9.4
84
85/**
86 * pointer to the first ItemNode of the doubly linked list (float)
87 * @ingroup feesrv_core
88 */
89static ItemNode* firstNode = 0;
90
91/**
92 * pointer to the last ItemNode of the doubly linked list (float)
93 * @ingroup feesrv_core
94 */
95static ItemNode* lastNode = 0;
96
97/**
98 * The message struct providing the data for an event message.
99 * @ingroup feesrv_core
100 */
101static MessageStruct message;
102
103/**
104 * Stores the last send message over the message channel to compare it with
105 * a newly triggered messages.
106 * @ingroup feesrv_core
107 */
108static MessageStruct lastMessage;
109
110/**
111 * Counter for replication of log messages.
112 * @ingroup feesrv_core
113 */
114static unsigned short replicatedMsgCount = 0;
115
116/**
117 * Indicates if the watchdog for replicated log messages is running
118 * (true = running).
119 *
120 * @ingroup feesrv_core
121 */
122static bool logWatchDogRunning = false;
123
124/**
125 * Timeout for the watchdog of replicated log messages. After this time the
126 * hold back message will be sent for sure, if no other type of message has
127 * triggered its sending before (replicated messages are collected until
128 * either this timeout occurs or a different message is triggered. In the later
129 * case the hold back message is sent first).
130 *
131 * @ingroup feesrv_core
132 */
133static unsigned int logWatchDogTimeout = DEFAULT_LOG_WATCHDOG_TIMEOUT;
134
135/**
136 * Stores the number of added nodes to the item list (float).
137 * @ingroup feesrv_core
138 */
139static unsigned int nodesAmount = 0;
140
141/**
142 * Indicates if the float monitor thread for published items has been started
143 * (true = started).
144 *
145 * @ingroup feesrv_core
146 */
147static bool monitorThreadStarted = false;
148
149/**
150 * DIM-serviceID for the dedicated acknowledge-service
151 * @ingroup feesrv_core
152 */
153static unsigned int serviceACKID;
154
155/**
156 * DIM-serviceID for the dedicated message - service
157 * @ingroup feesrv_core
158 */
159static unsigned int messageServiceID;
160
161/**
162 * DIM-commandID
163 * @ingroup feesrv_core
164 */
165static unsigned int commandID;
166
167/**
168 * Pointer to acknowledge Data (used by the DIM-framework)
169 * @ingroup feesrv_core
170 */
171static char* cmndACK = 0;
172
173/**
174 * size of the acknowledge Data
175 * @ingroup feesrv_core
176 */
177static int cmndACKSize = 0;
178
179/**
180 * Name of the FeeServer
181 * @ingroup feesrv_core
182 */
183static char* serverName = 0;
184
185/**
186 * length of FeeServer name
187 * @ingroup feesrv_core
188 */
189static int serverNameLength = 0;
190
191/**
192 * Update rate, in which the whole Item-list should be checked for changes.
193 * This value is given in milliseconds.
194 * @ingroup feesrv_core
195 */
196static unsigned short updateRate = DEFAULT_UPDATE_RATE;
197
198/**
199 * Timeout for call of issue - the longest time a command can be executed by the CE,
200 * before the watch dog kills this thread. This value is given in milliseconds.
201 * @ingroup feesrv_core
202 */
203static unsigned long issueTimeout = DEFAULT_ISSUE_TIMEOUT;
204
205/**
206 * Stores the current log level for this FeeServer.
207 * In case that an environmental variable (FEE_LOG_LEVEL) tells the desired
208 * loglevel, the DEFAULT_LOGLEVEL is overwritten during init process.
209 * @ingroup feesrv_core
210 */
211static unsigned int logLevel = DEFAULT_LOGLEVEL;
212
213/**
214 * thread handle for the initialize thread
215 * @ingroup feesrv_core
216 */
217static pthread_t thread_init;
218
219/**
220 * thread handle for the monitoring thread (float list)
221 * @ingroup feesrv_core
222 */
223static pthread_t thread_mon;
224
225/**
226 * thread handle for the watchdog of replicated log messages.
227 * This watchdog checks, if there have been replicated log messages during a
228 * time period given by "replicatedLogMessageTimeout", which have been hold
229 * back. The content of these messages is then send including the number of
230 * how often this has been triggered and hold back.
231 * Afterwards the counter is set back to zero again and backup of the last
232 * send log message is cleared.
233 *
234 * @ingroup feesrv_core
235 */
236static pthread_t thread_logWatchdog;
237
238/**
239 * thread condition variable for the "watchdog" timer
240 * @ingroup feesrv_core
241 */
242static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
243
244/**
245 * thread condition variable for the "initialisation complete" - signal
246 * @ingroup feesrv_core
247 */
248static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER;
249
250/**
251 * thread mutex variable for the "watchdog" in command handler
252 * @ingroup feesrv_core
253 */
254static pthread_mutex_t wait_mut = PTHREAD_MUTEX_INITIALIZER;
255
256/**
257 * thread mutex variable for the initialize CE thread
258 * @ingroup feesrv_core
259 */
260static pthread_mutex_t wait_init_mut = PTHREAD_MUTEX_INITIALIZER;
261
262/**
263 * thread mutex variable for the commandAck data
264 * @ingroup feesrv_core
265 */
266static pthread_mutex_t command_mut = PTHREAD_MUTEX_INITIALIZER;
267
268/**
269 * mutex to lock access to the logging function ( createLogMessage() )
270 * @ingroup feesrv_core
271 */
272static pthread_mutex_t log_mut = PTHREAD_MUTEX_INITIALIZER;
273
274
275//// --------- NEW FEATURE SINCE VERSION 0.8.1 (2007-06-12) ---------- /////
276
277/**
278 * pointer to the first IntItemNode of the doubly linked list (int)
279 * @ingroup feesrv_core
280 */
281static IntItemNode* firstIntNode = 0;
282
283/**
284 * pointer to the last IntItemNode of the doubly linked list (int)
285 * @ingroup feesrv_core
286 */
287static IntItemNode* lastIntNode = 0;
288
289/**
290 * Stores the number of added integer nodes to the IntItem list.
291 * @ingroup feesrv_core
292 */
293static unsigned int intNodesAmount = 0;
294
295/**
296 * thread handle for the monitoring thread (int - list)
297 * @ingroup feesrv_core
298 */
299static pthread_t thread_mon_int;
300
301/**
302 * Indicates if the int monitor thread for published IntItems has been started
303 * (true = started).
304 *
305 * @ingroup feesrv_core
306 */
307static bool intMonitorThreadStarted = false;
308
309
310//// ------------- NEW Memory Management (2007-07-25) ----------------- ////
311
312/**
313 * pointer to the first MemoryNode of the doubly linked list (memory management)
314 * @ingroup feesrv_core
315 */
316static MemoryNode* firstMemoryNode = 0;
317
318/**
319 * pointer to the last MemoryNode of the doubly linked list (memory management)
320 * @ingroup feesrv_core
321 */
322static MemoryNode* lastMemoryNode = 0;
323
324
325/// ---- NEW FEATURE SINCE VERSION 0.8.2b [Char Channel] (2007-07-28) ----- ///
326
327/**
328 * Stores the number of added Character item nodes to the CharItem list.
329 * @ingroup feesrv_core
330 */
331static unsigned int charNodesAmount = 0;
332
333/**
334 * pointer to the first CharItemNode of the doubly linked list (char)
335 * @ingroup feesrv_core
336 */
337static CharItemNode* firstCharNode = 0;
338
339/**
340 * pointer to the last CharItemNode of the doubly linked list (char)
341 * @ingroup feesrv_core
342 */
343static CharItemNode* lastCharNode = 0;
344
345
346
347//-- Main --
348
349/**
350 * Main of FeeServer.
351 * This programm represents the DIM-Server running on the DCS-boards.
352 * It uses the DIM-Server-Library implemented by C. Gaspar from Cern.
353 *
354 * @author Christian Kofler, Sebastian Bablok
355 *
356 * @date 2003-04-24
357 *
358 * @update 2004-11-22 (and many more dates ...)
359 *
360 * @version 0.8.1
361 * @ingroup feesrv_core
362 */
363int main(int argc, char** arg) {
364 //-- only for unit tests
365# ifdef __UTEST
366 // insert here the testfunction-calls
367 testFrameWork();
368 return 0;
369# endif
370
371 // now here starts the real stuff
372 initialize();
373 // test server (functional test)
374 while (1) {
375 // maybe do some checks here, like:
376 // - monitoring thread is still in good state
377 // - CE is still in good state
378 // - everything within the FeeServer is OK (assertions?)
379 pause();
380 }
381 return 0;
382}
383
384
385void initialize() {
386 //-- Declaring variables --
387 struct timeval now;
388 struct timespec timeout;
389 pthread_attr_t attr;
390 int nRet;
391 int status;
392 int initState = FEE_CE_NOTINIT;
393 char* name = 0;
394 char* dns = 0;
395 bool initOk = true;
396 unsigned int envVal = 0;
397 char msg[250];
398 int restartCount = 0;
399
400 //-- register interrupt handler (CTRL-C)
401 // not used yet, causes problems
402// if (signal(SIGINT, interrupt_handler) == SIG_ERR) {
403//# ifdef __DEBUG
404// printf("Unable to register interrupt handler.\n");
405// printf("This is not fatal -> continuing.\n");
406//# endif
407// }
408
409 //-- get name of the server --
410 name = getenv("FEE_SERVER_NAME");
411 if (name == 0) {
412# ifdef __DEBUG
413 printf("No FEE_SERVER_NAME \n");
414# endif
415 exit(202);
416 }
417
418 serverName = (char*) malloc(strlen(name) + 1);
419 if (serverName == 0) {
420 //no memory available!
421# ifdef __DEBUG
422 printf("no memory available while trying to create server name!\n");
423# endif
424 exit(201);
425 }
426 strcpy(serverName, name);
427 serverNameLength = strlen(serverName);
428
429 //-- test, if DIM_DNS_NODE is specified
430 dns = getenv("DIM_DNS_NODE");
431 if (dns == 0) {
432# ifdef __DEBUG
433 printf("No DIM_DNS_NODE specified. \n");
434# endif
435 exit(203);
436 }
437
438 // set the desired log level, if provided
439 if (getenv("FEE_LOG_LEVEL")) {
440 sscanf(getenv("FEE_LOG_LEVEL"), "%d", &envVal);
441 if ((envVal < 0) || (envVal > MSG_MAX_VAL)) {
442# ifdef __DEBUG
443 printf("Environmental variable has invalid Log Level, using default instead.\n");
444 fflush(stdout);
445# endif
446 } else {
447 logLevel = envVal | MSG_ALARM;
448 }
449 }
450
451 // set logWatchDogTimeout, if env variable "FEE_LOGWATCHDOG_TIMEOUT" is set
452 if (getenv("FEE_LOGWATCHDOG_TIMEOUT")) {
453 sscanf(getenv("FEE_LOGWATCHDOG_TIMEOUT"), "%d", &envVal);
454 if ((envVal <= 0) || (envVal > MAX_TIMEOUT)) {
455# ifdef __DEBUG
456 printf("Environmental variable has invalid LogWatchDog Timeout, using default instead.\n");
457 fflush(stdout);
458# endif
459 } else {
460 logWatchDogTimeout = envVal;
461 }
462 }
463
464 // get restart counter
465 if (getenv("FEESERVER_RESTART_COUNT")) {
466 restartCount = atoi(getenv("FEESERVER_RESTART_COUNT"));
467 }
468
469 // Initial printout
470# ifdef __DEBUG
471 printf("\n ** FeeServer version %s ** \n\n", FEESERVER_VERSION);
472 printf("FeeServer name: %s\n", serverName);
473 printf("Using DIM_DNS_NODE: %s\n", dns);
474# ifdef __BENCHMARK
475 printf(" -> Benchmark version of FeeServer <- \n");
476# endif
477 printf("Current log level is: %d (MSG_ALARM (%d) is always on)\n", logLevel, MSG_ALARM);
478 printf("Restart Count is: %d; Restart-Env is: %s\n", restartCount,
479 getenv("FEESERVER_RESTART_COUNT"));
480# endif
481
482 //set dummy exit_handler to disable framework exit command, returns void
483 dis_add_exit_handler(&dim_dummy_exit_handler);
484
485 //set error handler to catch DIM framework messages
486 dis_add_error_handler(&dim_error_msg_handler);
487
488 // to ensure that signal is in correct state before init procedure
489 ceReadySignaled = false;
490
491 // lock mutex
492 status = pthread_mutex_lock(&wait_init_mut);
493 if (status != 0) {
494# ifdef __DEBUG
495 printf("Lock init mutex error: %d\n", status);
496 fflush(stdout);
497# endif
498 initOk = false;
499 } else {
500 // initiailisation of thread attribute only if mutex has been locked
501 status = pthread_attr_init(&attr);
502 if (status != 0) {
503# ifdef __DEBUG
504 printf("Init attribute error: %d\n", status);
505 fflush(stdout);
506# endif
507 initOk = false;
508 } else {
509 status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
510 if (status != 0) {
511# ifdef __DEBUG
512 printf("Set attribute error: %d\n", status);
513 fflush(stdout);
514# endif
515 initOk = false;
516 }
517 }
518 }
519
520 if (initOk == true) {
521 // call only if initOk == true,
522 status = pthread_create(&thread_init, &attr, (void*) &threadInitializeCE, 0);
523 if (status != 0) {
524# ifdef __DEBUG
525 printf("Create thread error: %d\n", status);
526 fflush(stdout);
527# endif
528 initState = FEE_CE_NOTINIT;
529 } else {
530# ifdef __DEBUG // for debugging the time amount the watchdog really waits (START)
531 time_t initStartTime = time(NULL);
532# endif //__DEBUG
533
534 // timeout set in ms, should be enough for initialisation; see fee_defines.h for current value
535 status = gettimeofday(&now, 0);
536 if ((status != 0) || (restartCount <= 0)) {
537 // backup solution for detetcting end of init process
538# ifdef __DEBUG
539 printf("Get time of day error: %d or restartCount <= 0 (%d), using backup solution\n",
540 status, restartCount);
541 fflush(stdout);
542# endif
543 // unlock mutex to enable functionality of signalCEReady
544 status = pthread_mutex_unlock(&wait_init_mut);
545# ifdef __DEBUG
546 if (status != 0) {
547 printf("Unlock mutex error: %d\n", status);
548 fflush(stdout);
549 }
550# endif
551 // sleep init-timeout length
552 usleep((TIMEOUT_INIT_CE_MSEC * 1000)); // sleep the microsec fraction
553
554 const int sleepFraction = 1; // to check ready signal each second
555 int sleepLoops = TIMEOUT_INIT_CE_SEC / sleepFraction;
556 int cycles = 0;
557 do {
558 dtq_sleep(sleepFraction);
559 if (ceReadySignaled) {
560 break;
561 }
562 } while ( cycles++ < sleepLoops);
563// dtq_sleep(TIMEOUT_INIT_CE_SEC); // old style without check each second
564
565 if (ceReadySignaled == false) {
566 status = pthread_cancel(thread_init);
567# ifdef __DEBUG
568 if (status != 0) {
569 printf("No thread to cancel: %d\n", status);
570 fflush(stdout);
571 }
572# endif
573 // start with "the CE is not initialized!"
574 initState = FEE_CE_NOTINIT;
575# ifdef __DEBUG
576 printf("Timeout in init [sleep]: %d\n", initState);
577 fflush(stdout);
578# endif
579 } else {
580 if (ceInitState != CE_OK) {
581 // init failed, but no timeout occured
582 // (insufficient memory, etc. ... or something else)
583# ifdef __DEBUG
584 printf("Init of CE failed, error: %d\n", ceInitState);
585 fflush(stdout);
586# endif
587 initState = FEE_CE_NOTINIT;
588 } else {
589 // start with "everything is fine"
590 initState = FEE_OK;
591# ifdef __DEBUG
592 printf("Init OK\n");
593 fflush(stdout);
594# endif
595 }
596 }
597 } else {
598 timeout.tv_sec = now.tv_sec + TIMEOUT_INIT_CE_SEC;
599 timeout.tv_nsec = (now.tv_usec * 1000) +
600 (TIMEOUT_INIT_CE_MSEC * 1000000);
601
602 // wait for finishing "issue" or timeout after the mutex is unlocked
603 // a retcode of 0 means, that pthread_cond_timedwait has returned
604 // with the cond_init signaled
605 status = pthread_cond_timedwait(&init_cond, &wait_init_mut, &timeout);
606 // -- start FeeServer depending on the state of the CE --
607 if (status != 0) {
608 status = pthread_cancel(thread_init);
609# ifdef __DEBUG
610 if (status != 0) {
611 printf("No thread to cancel: %d\n", status);
612 fflush(stdout);
613 }
614# endif
615 // start with "the CE is not initialized!"
616 initState = FEE_CE_NOTINIT;
617# ifdef __DEBUG
618 printf("Timeout in init [timed_wait]: %d\n", initState);
619 fflush(stdout);
620# endif
621 } else {
622 if (ceInitState != CE_OK) {
623 // init failed, but no timeout occured
624 // (insufficient memory, etc. ... or something else)
625# ifdef __DEBUG
626 printf("Init of CE failed, error: %d\n", ceInitState);
627 fflush(stdout);
628# endif
629 initState = FEE_CE_NOTINIT;
630 } else {
631 // start with "everything is fine"
632 initState = FEE_OK;
633# ifdef __DEBUG
634 printf("Init OK\n");
635 fflush(stdout);
636# endif
637 }
638 }
639 }
640# ifdef __DEBUG // for debugging the time amout the watchdog waits (STOP)
641 time_t initStopTime = time(NULL);
642 if (initState != FEE_OK) {
643 printf("Watchdog: CE init tread\n started %s",
644 ctime(&initStartTime));
645 printf(" killed %s\n", ctime(&initStopTime));
646 // don't put this into one printf line -
647 // ctime or printf doe not work correct then, why?
648 fflush(stdout);
649 } else {
650 printf("Watchdog: CE init tread\n started %s",
651 ctime(&initStartTime));
652 printf(" finished %s\n", ctime(&initStopTime));
653 // don't put this into one printf line -
654 // ctime or printf doe not work correct then, why?
655 fflush(stdout);
656 }
657# endif //__DEBUG
658 }
659 // destroy thread attribute
660 status = pthread_attr_destroy(&attr);
661# ifdef __DEBUG
662 if (status != 0) {
663 printf("Destroy attribute error: %d\n", status);
664 fflush(stdout);
665 }
666# endif
667 }
668
669 // init message struct -> FeeServer name, version and DNS are also provided
670 initMessageStruct();
671
672 if (initState != FEE_OK) {
673 // remove all services of Items of ItemList
674# ifdef __DEBUG
675 printf("Init failed, unpublishing item list\n");
676 fflush(stdout);
677# endif
678 unpublishItemList();
679 // new since version 0.8.1 -> int channels
680 unpublishIntItemList();
681 // new since version 0.8.2b -> char channels
682 unpublishCharItemList();
683 }
684
685 // add div. services and the command channel and then start DIM server
686 nRet = start(initState);
687
688 // unlock mutex
689 status = pthread_mutex_unlock(&wait_init_mut);
690 if (status != 0) {
691# ifdef __DEBUG
692 printf("Unlock mutex error: %d\n", status);
693 fflush(stdout);
694# endif
695 if (nRet == FEE_OK) {
696 createLogMessage(MSG_WARNING, "Unable to unlock init mutex.", 0);
697 }
698 }
699
700 if (nRet != FEE_OK) {
701# ifdef __DEBUG
702 printf("unable to start DIM server, exiting.\n");
703 fflush(stdout);
704# endif
705 fee_exit_handler(205);
706 } else {
707# ifdef __DEBUG
708 printf("DIM Server successfully started, ready to accept commands.\n");
709 fflush(stdout);
710# endif
711 }
712
713# ifdef __DEBUG
714 printf("DEBUG - Init-State: %d, CE-State: %d, Restart-Env: %s, RestartCount: %d.\n",
715 initState, ceInitState, getenv("FEESERVER_RESTART_COUNT"), restartCount);
716 fflush(stdout);
717# endif
718
719 // test for failed init of CE and init restart counter,
720 // counter counts backwards: only if counter > 0 restart is triggerd
721 if ((initState != FEE_OK) && (getenv("FEESERVER_RESTART_COUNT")) &&
722 (restartCount > 0)) {
723 msg[sprintf(msg,
724 "Triggering a FeeServer restart to give CE init another try. Restart count (backward counter): %d ",
725 restartCount)] = 0;
726 createLogMessage(MSG_WARNING, msg, 0);
727# ifdef __DEBUG
728 printf("Triggering a FeeServer restart for another CE init try (backward count: %d).\n",
729 restartCount);
730 fflush(stdout);
731# endif
732 // small sleep, that DIM is able to send log messages before restart
733 dtq_sleep(1);
734 // trigger restart to give it another try for the CE to init
735 triggerRestart(FEE_EXITVAL_TRY_INIT_RESTART);
736 // NOTE this function won't return ...
737 }
738 // look through watchdog and backup solution about ceInitState and check it again !!!
739 // afterwards the following line won't be necessary !!!
740 // needed later in information about properties !!!
741// ceInitState = initState;
742
743 return;
744}
745
746
747void threadInitializeCE() {
748 int status = -1;
749 status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
750 // if cancelation is not able, it won't hurt ?!
751# ifdef __DEBUG
752 if (status != 0) {
753 printf("Set cancel state (init) error: %d\n", status);
754 fflush(stdout);
755 }
756# endif
757
758 status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
759 // if cancelation is not able, it won't hurt ?!
760# ifdef __DEBUG
761 if (status != 0) {
762 printf("Set cancel type (init) error: %d\n", status);
763 fflush(stdout);
764 }
765# endif
766
767 // Here starts the actual CE
768 initializeCE();
769
770 // not necessary, return 0 is better
771// pthread_exit(0);
772 return;
773
774}
775
776
777void signalCEready(int ceState) {
778 int status = -1;
779
780 // set cancel type to deferred
781 status = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
782# ifdef __DEBUG
783 if (status != 0) {
784 printf("Set cancel type error: %d\n", status);
785 fflush(stdout);
786 }
787# endif
788
789 //lock the mutex before broadcast
790 status = pthread_mutex_lock(&wait_init_mut);
791# ifdef __DEBUG
792 if (status != 0) {
793 printf("Lock mutex error: %d\n", status);
794 fflush(stdout);
795 }
796# endif
797
798 // provide init state of CE
799 ceInitState = ceState;
800
801 //signal that CE has completed initialisation
802 // maybe try the call pthread_cond_signal instead for performance
803 pthread_cond_broadcast(&init_cond);
804
805 // set variable for backup solution
806 ceReadySignaled = true;
807
808 // unlock mutex
809 status = pthread_mutex_unlock(&wait_init_mut);
810# ifdef __DEBUG
811 if (status != 0) {
812 printf("Unlock mutex error: %d\n", status);
813 fflush(stdout);
814 }
815# endif
816
817 // set cancel type to asyncroneous
818 status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
819# ifdef __DEBUG
820 if (status != 0) {
821 printf("Set cancel type error: %d\n", status);
822 fflush(stdout);
823 }
824# endif
825}
826
827
828// -- Command handler routine --
829void command_handler(int* tag, char* address, int* size) {
830 struct timeval now;
831 struct timespec timeout;
832 int retcode = -1;
833 int status = -1;
834 pthread_t thread_handle;
835 pthread_attr_t attr;
836 IssueStruct issueParam;
837 CommandHeader header;
838 char* pHeaderStream = 0;
839 MemoryNode* memNode = 0;
840 bool useMM = false;
841
842#ifdef __BENCHMARK
843 char benchmsg[200];
844 // make benchmark entry
845 if ((size != 0 ) && (*size >= 4)) {
846 benchmsg[sprintf(benchmsg,
847 "FeeServer CommandHandler (Received command) - Packet-ID: %d",
848 *address)] = 0;
849 createBenchmark(benchmsg);
850 } else {
851 createBenchmark("FeeServer CommandHandler (Received command)");
852 }
853#endif
854
855 // init struct
856 initIssueStruct(&issueParam);
857
858 issueParam.nRet = FEE_UNKNOWN_RETVAL;
859
860 // check state (ERROR state is allowed for FeeServer commands, not CE)
861 if ((state != RUNNING) && (state != ERROR_STATE)) {
862 return;
863 }
864
865 // lock command mutex to save command &ACK data until it is send
866 // and only one CE-Thread exists at one time
867 status = pthread_mutex_lock(&command_mut);
868 if (status != 0) {
869# ifdef __DEBUG
870 printf("Lock command mutex error: %d\n", status);
871 fflush(stdout);
872# endif
873 createLogMessage(MSG_WARNING, "Unable to lock command mutex.", 0);
874 }
875
876 if ((tag == 0) || (address == 0) || (size == 0)) {
877 leaveCommandHandler(0, FEE_NULLPOINTER, MSG_WARNING,
878 "Received null pointer of DIM framework in command handler.");
879 return;
880 }
881
882 if (*size < HEADER_SIZE) {
883 leaveCommandHandler(0, FEE_INVALID_PARAM, MSG_WARNING,
884 "FeeServer received corrupted command.");
885 return;
886 }
887
888# ifdef __DEBUG
889 printf(" Cmnd - Size: %d\n", *size);
890 fflush(stdout);
891# endif
892
893 //-- storing the header information in struct --
894 memcpy(&header.id, address, HEADER_SIZE_ID);
895 memcpy(&header.errorCode, address + HEADER_OFFSET_ID, HEADER_SIZE_ERROR_CODE);
896 memcpy(&header.flags, address + HEADER_OFFSET_ERROR_CODE, HEADER_SIZE_FLAGS);
897 memcpy(&header.checksum, address + HEADER_OFFSET_FLAGS, HEADER_SIZE_CHECKSUM);
898
899 // --------------------- Check Flags --------------------------
900 if ((header.flags & HUFFMAN_FLAG) != 0) {
901 //-- do Huffmann decoding if flag is set --
902 // not implemented yet !!!
903 }
904
905 issueParam.size = *size - HEADER_SIZE;
906 issueParam.command = (address + HEADER_SIZE);
907 // !!! if Huffman decoding necessary, think about memory management ???
908
909 if ((header.flags & CHECKSUM_FLAG) != 0) {
910 //-- do checksum test if flag is set --
911 if (!checkCommand(issueParam.command, issueParam.size, header.checksum)) {
912 // -- checksum failed - notification
913 leaveCommandHandler(header.id, FEE_CHECKSUM_FAILED, MSG_WARNING,
914 "FeeServer received corrupted command data (checksum failed).");
915 return;
916 }
917 }
918
919 // -- here start the Commands for the FeeServer itself --
920 if ((header.flags & FEESERVER_UPDATE_FLAG) != 0) {
921#ifdef ENABLE_MASTERMODE
922 updateFeeServer(&issueParam);
923#else
924 createLogMessage(MSG_WARNING, "FeeServer is not authorized to execute shell programs, skip ...", 0);
925#endif //ENABLE_MASTERMODE
926 // this is only reached, if update has not been sucessful
927 issueParam.nRet = FEE_FAILED;
928 issueParam.size = 0;
929 } else if ((header.flags & FEESERVER_RESTART_FLAG) != 0) {
930 restartFeeServer();
931 } else if ((header.flags & FEESERVER_REBOOT_FLAG) != 0) {
932 createLogMessage(MSG_INFO, "Rebooting DCS board.", 0);
933 system("reboot");
934 exit(0);
935 } else if ((header.flags & FEESERVER_SHUTDOWN_FLAG) != 0) {
936 createLogMessage(MSG_INFO, "Shuting down DCS board.", 0);
937 system("poweroff");
938 exit(0);
939 } else if ((header.flags & FEESERVER_EXIT_FLAG) != 0) {
940 fee_exit_handler(0);
941 } else if ((header.flags & FEESERVER_SET_DEADBAND_FLAG) != 0) {
942 issueParam.nRet = setDeadband(&issueParam);
943 } else if ((header.flags & FEESERVER_GET_DEADBAND_FLAG) != 0) {
944 issueParam.nRet = getDeadband(&issueParam);
945 } else if ((header.flags & FEESERVER_SET_ISSUE_TIMEOUT_FLAG) != 0) {
946 issueParam.nRet = setIssueTimeout(&issueParam);
947 } else if ((header.flags & FEESERVER_GET_ISSUE_TIMEOUT_FLAG) != 0) {
948 issueParam.nRet = getIssueTimeout(&issueParam);
949 } else if ((header.flags & FEESERVER_SET_UPDATERATE_FLAG) != 0) {
950 issueParam.nRet = setUpdateRate(&issueParam);
951 } else if ((header.flags & FEESERVER_GET_UPDATERATE_FLAG) != 0) {
952 issueParam.nRet = getUpdateRate(&issueParam);
953 } else if ((header.flags & FEESERVER_SET_LOGLEVEL_FLAG) != 0) {
954 issueParam.nRet = setLogLevel(&issueParam);
955 } else if ((header.flags & FEESERVER_GET_LOGLEVEL_FLAG) != 0) {
956 issueParam.nRet = getLogLevel(&issueParam);
957 } else {
958 // commands for CE are not allowed in ERROR state
959 if (state == ERROR_STATE) {
960 leaveCommandHandler(header.id, FEE_WRONG_STATE, MSG_ERROR,
961 "FeeServer is in ERROR_STATE, ignoring command for CE!");
962 return;
963 }
964
965 // packet with no flags in header and no payload makes no sense
966 if (issueParam.size == 0) {
967 leaveCommandHandler(header.id, FEE_INVALID_PARAM, MSG_WARNING,
968 "FeeServer received empty command.");
969 return;
970 }
971
972 // lock mutex
973 status = pthread_mutex_lock(&wait_mut);
974 if (status != 0) {
975 leaveCommandHandler(header.id, FEE_THREAD_ERROR, MSG_ERROR,
976 "Unable to lock condition mutex for watchdog.");
977 return;
978 }
979
980 status = pthread_attr_init(&attr);
981 if (status != 0) {
982 unlockIssueMutex();
983 leaveCommandHandler(header.id, FEE_THREAD_ERROR, MSG_ERROR,
984 "Unable to initialize issue thread.");
985 return;
986 }
987
988 status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
989 if (status != 0) {
990 unlockIssueMutex();
991 leaveCommandHandler(header.id, FEE_THREAD_ERROR, MSG_ERROR,
992 "Unable to initialize issue thread.");
993 return;
994 }
995
996 status = pthread_create(&thread_handle, &attr, &threadIssue, (void*) &issueParam);
997 if (status != 0) {
998 unlockIssueMutex();
999 leaveCommandHandler(header.id, FEE_THREAD_ERROR, MSG_ERROR,
1000 "Unable to create issue thread.");
1001 return;
1002 }
1003
1004 status = pthread_attr_destroy(&attr);
1005 if (status != 0) {
1006# ifdef __DEBUG
1007 printf("Destroy attribute error: %d\n", status);
1008 fflush(stdout);
1009# endif
1010 createLogMessage(MSG_WARNING,
1011 "Unable to destroy thread attribute.", 0);
1012 }
1013
1014 // timeout set in ms, see fee_defines.h for current value
1015 status = gettimeofday(&now, 0);
1016 if (status == 0) {
1017 // issueTimeout is in milliseconds:
1018 // get second-part with dividing by 1000
1019 timeout.tv_sec = now.tv_sec + (int) (issueTimeout / 1000);
1020 // get rest of division by 1000 (which is milliseconds)
1021 // and make it nanoseconds
1022 timeout.tv_nsec = (now.tv_usec * 1000) +
1023 ((issueTimeout % 1000) * 1000000);
1024
1025 // wait for finishing "issue" or timeout, if signal has been sent
1026 // retcode is 0 !
1027 // this is the main logic of the watchdog for the CE of the FeeServer
1028 retcode = pthread_cond_timedwait(&cond, &wait_mut, &timeout);
1029# ifdef __DEBUG
1030 printf("Retcode of CMND timedwait: %d\n", retcode);
1031 fflush(stdout);
1032# endif
1033
1034 // check retcode to detect and handle Timeout
1035 if (retcode == ETIMEDOUT) {
1036# ifdef __DEBUG
1037 printf("ControlEngine watchdog detected TimeOut.\n");
1038 fflush(stdout);
1039# endif
1040 createLogMessage(MSG_WARNING,
1041 "ControlEngine watch dog noticed a time out for last command.", 0);
1042
1043 // kill not finished thread. no problem if this returns an error
1044 pthread_cancel(thread_handle);
1045 // setting errorCode to "a timout occured"
1046 issueParam.nRet = FEE_TIMEOUT;
1047 issueParam.size = 0;
1048 } else if (retcode != 0) {
1049 // "handling" of other error than timeout
1050# ifdef __DEBUG
1051 printf("ControlEngine watchdog detected unknown error.\n");
1052 fflush(stdout);
1053# endif
1054 createLogMessage(MSG_WARNING,
1055 "ControlEngine watch dog received an unknown for last command.", 0);
1056
1057 // kill not finished thread. no problem if this returns an error
1058 pthread_cancel(thread_handle);
1059 // setting errorCode to "a thread error occured"
1060 issueParam.nRet = FEE_THREAD_ERROR;
1061 issueParam.size = 0;
1062 }
1063
1064 } else {
1065# ifdef __DEBUG
1066 printf("Get time of day error: %d\n", status);
1067 fflush(stdout);
1068# endif
1069 createLogMessage(MSG_WARNING,
1070 "Watchdog timer could not be initialized. Using non-reliable sleep instead.",
1071 0);
1072 // release mutex to avoid hang up in issueThread before signaling condition
1073 unlockIssueMutex();
1074 // watchdog with condition signal could not be used, because gettimeofday failed.
1075 // sleeping instead for usual amount of time and trying to cancel thread aftterwards.
1076 usleep(issueTimeout * 1000);
1077 status = pthread_cancel(thread_handle);
1078 // if thread did still exist something went wrong -> "timeout" (== 0)
1079 if (status == 0) {
1080# ifdef __DEBUG
1081 printf("TimeOut occured.\n");
1082# endif
1083 createLogMessage(MSG_WARNING,
1084 "ControlEngine issue did not return in time.", 0);
1085 issueParam.nRet = FEE_TIMEOUT;
1086 issueParam.size = 0;
1087 }
1088 }
1089
1090 unlockIssueMutex();
1091 }
1092 //--- end of CE call area --------------------
1093
1094 // ---------- start to compose result -----------------
1095# ifdef __DEBUG
1096 printf("Issue-nRet: %d\n", issueParam.nRet);
1097 fflush(stdout);
1098# endif
1099 // check return value of issue
1100 if ((issueParam.nRet < FEE_UNKNOWN_RETVAL) ||
1101 (issueParam.nRet > FEE_MAX_RETVAL)) {
1102 issueParam.nRet = FEE_UNKNOWN_RETVAL;
1103 createLogMessage(MSG_DEBUG,
1104 "ControlEngine [command] returned unkown RetVal.", 0);
1105 }
1106
1107// start here with new memory management check for ACK
1108 // check if old ACK data is in MemoryNode list and free it
1109 if ((cmndACKSize > HEADER_SIZE) && (findMemoryNode(cmndACK + HEADER_SIZE) != 0)) {
1110 memNode = findMemoryNode(cmndACK + HEADER_SIZE);
1111 freeMemoryNode(memNode);
1112 } else { // free cmndACK in original way
1113 if (cmndACK != 0) {
1114 free(cmndACK);
1115 cmndACK = 0;
1116 }
1117 }
1118
1119 // check if new result data is in MemoryNode list
1120 memNode = findMemoryNode(issueParam.result);
1121 if (memNode != 0) {
1122 cmndACK = memNode->ptr;
1123 useMM = true;
1124 } else {
1125 // create Acknowledge as return value of command
1126 // HEADER_SIZE bytes are added before result to insert the command
1127 // header before the result -> see CommandHeader in Client for details
1128 cmndACK = (char*) malloc(issueParam.size + HEADER_SIZE);
1129 }
1130
1131 if (cmndACK == 0) {
1132 //no memory available!
1133# ifdef __DEBUG
1134 printf("no memory available!\n");
1135 fflush(stdout);
1136# endif
1137 createLogMessage(MSG_ERROR, "Insufficient memory for ACK.", 0);
1138
1139 // no ACK because no memory!
1140 cmndACKSize = 0;
1141 status = pthread_mutex_unlock(&command_mut);
1142 if (status != 0) {
1143# ifdef __DEBUG
1144 printf("Lock command mutex error: %d\n", status);
1145 fflush(stdout);
1146# endif
1147 createLogMessage(MSG_WARNING,
1148 "Error while trying to unlock command mutex.", 0);
1149 }
1150 return;
1151 }
1152
1153# ifdef __DEBUG
1154 if (issueParam.size > 0) {
1155// printf("in cmnd-Handler -> issue result: ");
1156// printData(issueParam.result, 0, issueParam.size);
1157// fflush(stdout);
1158 }
1159# endif
1160
1161 // checks checksumflag and calculates it if necessary
1162 if ((header.flags & CHECKSUM_FLAG) != 0) {
1163 header.checksum = calculateChecksum((unsigned char*) issueParam.result,
1164 issueParam.size);
1165 // !!! Do (Huffman- ) encoding, if wished afterwards.
1166 } else {
1167 header.checksum = CHECKSUM_ZERO;
1168 }
1169
1170 // keep the whole flags also for the result packet
1171 header.errorCode = (short) issueParam.nRet;
1172# ifdef __DEBUG
1173 printf("ErrorCode in Header: %d\n", header.errorCode);
1174 fflush(stdout);
1175# endif
1176
1177 pHeaderStream = marshallHeader(&header);
1178 memcpy((void*) cmndACK, (void*) pHeaderStream, HEADER_SIZE);
1179 if (pHeaderStream != 0) {
1180 free(pHeaderStream);
1181 }
1182
1183 if (useMM) {
1184 /*
1185# ifdef __DEBUG
1186 printf("ACK channel used with MemoryManagement in FeeServer.\n");
1187 fflush(stdout);
1188 createLogMessage(MSG_DEBUG,
1189 "ACK channel used with MemoryManagement in FeeServer.", 0);
1190# endif
1191 */
1192 } else {
1193 memcpy(((void*) cmndACK + HEADER_SIZE), (void*) issueParam.result,
1194 issueParam.size);
1195 }
1196
1197 //store the size of the result globally
1198 cmndACKSize = issueParam.size + HEADER_SIZE;
1199 // propagate change of ACK(nowledge channel) to upper Layers
1200 dis_update_service(serviceACKID);
1201
1202# ifdef __DEBUG
1203 // -- see the cmndACK as a char - string
1204 printf("ACK \n");
1205// printData(cmndACK, HEADER_SIZE, cmndACKSize);
1206 // -- see the cmndACK in a HEX view for the ALTRO
1207 //print_package(cmndACK + HEADER_SIZE);
1208# endif
1209
1210 if ((!useMM) && (issueParam.result != 0)) {
1211 free(issueParam.result);
1212 }
1213// end of new stuff for memory managment.
1214
1215/*
1216 if (cmndACK != 0) {
1217 free(cmndACK);
1218 cmndACK = 0;
1219 }
1220 // create Acknowledge as return value of command
1221 // HEADER_SIZE bytes are added before result to insert the command
1222 // header before the result -> see CommandHeader in Client for details
1223 cmndACK = (char*) malloc(issueParam.size + HEADER_SIZE);
1224 if (cmndACK == 0) {
1225 //no memory available!
1226# ifdef __DEBUG
1227 printf("no memory available!\n");
1228 fflush(stdout);
1229# endif
1230 createLogMessage(MSG_ERROR, "Insufficient memory for ACK.", 0);
1231
1232 // no ACK because no memory!
1233 cmndACKSize = 0;
1234 status = pthread_mutex_unlock(&command_mut);
1235 if (status != 0) {
1236# ifdef __DEBUG
1237 printf("Lock command mutex error: %d\n", status);
1238 fflush(stdout);
1239# endif
1240 createLogMessage(MSG_WARNING,
1241 "Error while trying to unlock command mutex.", 0);
1242 }
1243 return;
1244 }
1245
1246# ifdef __DEBUG
1247 if (issueParam.size > 0) {
1248// printf("in cmnd-Handler -> issue result: ");
1249// printData(issueParam.result, 0, issueParam.size);
1250// fflush(stdout);
1251 }
1252# endif
1253
1254 // checks checksumflag and calculates it if necessary
1255 if ((header.flags & CHECKSUM_FLAG) != 0) {
1256 header.checksum = calculateChecksum((unsigned char*) issueParam.result,
1257 issueParam.size);
1258 // !!! Do (Huffman- ) encoding, if wished afterwards.
1259 } else {
1260 header.checksum = CHECKSUM_ZERO;
1261 }
1262
1263 // keep the whole flags also for the result packet
1264 header.errorCode = (short) issueParam.nRet;
1265# ifdef __DEBUG
1266 printf("ErrorCode in Header: %d\n", header.errorCode);
1267 fflush(stdout);
1268# endif
1269
1270 pHeaderStream = marshallHeader(&header);
1271 memcpy((void*) cmndACK, (void*) pHeaderStream, HEADER_SIZE);
1272 if (pHeaderStream != 0) {
1273 free(pHeaderStream);
1274 }
1275 memcpy(((void*) cmndACK + HEADER_SIZE), (void*) issueParam.result,
1276 issueParam.size);
1277
1278 //store the size of the result globally
1279 cmndACKSize = issueParam.size + HEADER_SIZE;
1280 // propagate change of ACK(nowledge channel) to upper Layers
1281 dis_update_service(serviceACKID);
1282
1283# ifdef __DEBUG
1284 // -- see the cmndACK as a char - string
1285 printf("ACK \n");
1286// printData(cmndACK, HEADER_SIZE, cmndACKSize);
1287 // -- see the cmndACK in a HEX view for the ALTRO
1288 //print_package(cmndACK + HEADER_SIZE);
1289# endif
1290
1291 if (issueParam.result != 0) {
1292 free(issueParam.result);
1293 }
1294
1295*/
1296
1297
1298 // unlock command mutex, data has been sent
1299 status = pthread_mutex_unlock(&command_mut);
1300 if (status != 0) {
1301# ifdef __DEBUG
1302 printf("Lock command mutex error: %d\n", status);
1303 fflush(stdout);
1304# endif
1305 createLogMessage(MSG_WARNING,
1306 "Error while trying to unlock command mutex.", 0);
1307 }
1308}
1309
1310
1311//-- user_routine to provide the ACK-data
1312void ack_service(int* tag, char** address, int* size) {
1313#ifdef __BENCHMARK
1314 char benchmsg[200];
1315#endif
1316
1317 if ((tag == 0) || (*tag != ACK_SERVICE_TAG)) {
1318# ifdef __DEBUG
1319 printf("invalid ACK Service\n");
1320 fflush(stdout);
1321# endif
1322 createLogMessage(MSG_WARNING, "DIM Framework called wrong ACK channel.",
1323 0);
1324 return;
1325 }
1326// use the line below for checking flags of an outgoing feePacket!
1327// printf("\nack_service was called flags are:%x%x\n", *(cmndACK+6), *(cmndACK+7));
1328 if ((cmndACKSize > 0) && (cmndACK != 0)) {
1329 *address = cmndACK;
1330 *size = cmndACKSize;
1331 } else {
1332 *size = 0;
1333 }
1334#ifdef __BENCHMARK
1335 // make benchmark entry
1336 benchmsg[sprintf(benchmsg,
1337 "FeeServer AckHandler (sending ACK) - Packet-ID: %d", *cmndACK)] = 0;
1338 createBenchmark(benchmsg);
1339#endif
1340
1341}
1342
1343
1344void leaveCommandHandler(unsigned int id, short errorCode,
1345 unsigned int msgType, char* message) {
1346 int status = -1;
1347
1348# ifdef __DEBUG
1349 printf("%s\n", message);
1350 fflush(stdout);
1351# endif
1352
1353 createLogMessage(msgType, message, 0);
1354
1355 // tell client that command is ignored
1356 if (cmndACK != 0) {
1357 free(cmndACK);
1358 cmndACK = 0;
1359 }
1360 // send error code
1361 cmndACK = createHeader(id, errorCode, false, false, 0);
1362 cmndACKSize = HEADER_SIZE;
1363 dis_update_service(serviceACKID);
1364
1365 // unlock command mutex to "free" commandHandler
1366 status = pthread_mutex_unlock(&command_mut);
1367 if (status != 0) {
1368# ifdef __DEBUG
1369 printf("Lock command mutex error: %d\n", status);
1370 fflush(stdout);
1371# endif
1372 createLogMessage(MSG_WARNING,
1373 "Error while trying to unlock command mutex.", 0);
1374 }
1375}
1376
1377
1378void unlockIssueMutex() {
1379 int status = -1;
1380
1381 status = pthread_mutex_unlock(&wait_mut);
1382 if (status != 0) {
1383# ifdef __DEBUG
1384 printf("Unlock condition mutex error: %d. Going in ERROR state!\n", status);
1385 fflush(stdout);
1386# endif
1387 createLogMessage(MSG_ALARM,
1388 "Unable to unlock watchdog mutex. No more commands will be possible for CE. Going in ERROR state!",
1389 0);
1390 state = ERROR_STATE;
1391 }
1392}
1393
1394
1395//-- publish-function called by CE (Control Engine) to declare Float - Items
1396int publish(Item* item) {
1397 unsigned int id;
1398 char* serviceName = 0;
1399
1400 // check for right state
1401 if (state != COLLECTING) {
1402 return FEE_WRONG_STATE;
1403 }
1404
1405 // Testing for NULL - Pointer
1406 // !! Attention: if pointer is not initialized and also NOT set to NULL, this won't help !!
1407 if (item == 0) {
1408# ifdef __DEBUG
1409 printf("Bad item, not published\n");
1410 fflush(stdout);
1411# endif
1412 return FEE_NULLPOINTER;
1413 }
1414 if (item->name == 0 || item->location == 0) {
1415# ifdef __DEBUG
1416 printf("Bad item, not published\n");
1417 fflush(stdout);
1418# endif
1419 return FEE_NULLPOINTER;
1420 }
1421
1422 // Check name for duplicate here (float)
1423 if (findItem(item->name) != 0) {
1424# ifdef __DEBUG
1425 printf("Item name already published (float), new float item discarded.\n");
1426 fflush(stdout);
1427# endif
1428 return FEE_ITEM_NAME_EXISTS;
1429 }
1430 // Check in INT list
1431 if (findIntItem(item->name) != 0) {
1432# ifdef __DEBUG
1433 printf("Item name already published (int), float item discarded.\n");
1434 fflush(stdout);
1435# endif
1436 return FEE_ITEM_NAME_EXISTS;
1437 }
1438 // Check in Char service list
1439 if (findCharItem(item->name) != 0) {
1440# ifdef __DEBUG
1441 printf("Item name already published in char list, float item discarded.\n");
1442 fflush(stdout);
1443# endif
1444 return FEE_ITEM_NAME_EXISTS;
1445 }
1446
1447 // -- add item as service --
1448 serviceName = (char*) malloc(serverNameLength + strlen(item->name) + 2);
1449 if (serviceName == 0) {
1450 return FEE_INSUFFICIENT_MEMORY;
1451 }
1452 // terminate string with '\0'
1453 serviceName[sprintf(serviceName, "%s_%s", serverName, item->name)] = 0;
1454 id = dis_add_service(serviceName, "F", (int*) item->location,
1455 sizeof(float), 0, 0);
1456 free(serviceName);
1457 add_item_node(id, item);
1458
1459 return FEE_OK;
1460}
1461
1462
1463//-- function to add service to our servicelist
1464void add_item_node(unsigned int _id, Item* _item) {
1465 //create new node with enough memory
1466 ItemNode* newNode = 0;
1467
1468 newNode = (ItemNode*) malloc(sizeof(ItemNode));
1469 if (newNode == 0) {
1470 //no memory available!
1471# ifdef __DEBUG
1472 printf("no memory available while adding itemNode!\n");
1473# endif
1474 // !!! unable to run FeeServer, write msg in kernel logger !!! (->Tobias)
1475 cleanUp();
1476 exit(201);
1477 }
1478 //initialize "members" of node
1479 newNode->prev = 0;
1480 newNode->next = 0;
1481 newNode->id = _id;
1482 newNode->item = _item;
1483 newNode->lastTransmittedValue = *(_item->location);
1484 //if default deadband is negative -> set threshold 0, otherwise set half of defaultDeadband
1485 newNode->threshold = (_item->defaultDeadband < 0) ? 0.0 : (_item->defaultDeadband / 2);
1486 /*
1487 if(_item->defaultDeadband < 0) {
1488 newNode->threshold = 0.0;
1489 } else {
1490 newNode->threshold = _item->defaultDeadband / 2;
1491 }
1492*/
1493 newNode->locBackup = _item->location;
1494 newNode->checksum = calculateChecksum((unsigned char*) &(_item->location),
1495 sizeof(volatile float*));
1496 newNode->checksumBackup = newNode->checksum;
1497
1498#ifdef __DEBUG
1499 // complete debug display of added Item
1500/*
1501 printf("Item: %d\n", _id);
1502 printf("location: %f, locBackup %f\n", *(_item->location), *(newNode->locBackup));
1503 printf("location addr: %p, locBackup addr %p\n", _item->location, newNode->locBackup);
1504 printf("checksum1: %d, checksum2: %d\n\n", newNode->checksum,
1505 newNode->checksumBackup);
1506*/
1507#endif
1508
1509# ifdef __DEBUG
1510 // short debug display of added Item
1511 printf("init of %s with ID %d: %f\n", newNode->item->name, newNode->id,
1512 newNode->lastTransmittedValue);
1513 fflush(stdout);
1514# endif
1515
1516 ++nodesAmount;
1517 //redirect pointers of doubly linked list
1518 if (firstNode != 0) {
1519 lastNode->next = newNode;
1520 newNode->prev = lastNode;
1521 lastNode = newNode;
1522 } else {
1523 firstNode = newNode;
1524 lastNode = newNode;
1525 }
1526}
1527
1528
1529//-- Logging function -----
1530void createLogMessage(unsigned int type, char* description, char* origin) {
1531 int status = -1; // for mutex
1532 int descLength = 0;
1533 int originLength = 0;
1534 time_t timeVal;
1535 struct tm* now = 0;
1536
1537 // check if not in COLLECTING state
1538 if (state == COLLECTING) {
1539 return; // no log channel available at that time
1540 }
1541
1542 //lock access with mutex due to the fact that FeeServer & CE can use it
1543 status = pthread_mutex_lock(&log_mut);
1544 // discard eventual error, this would cause more problems
1545 // in each case, do NOT call createLogMessage ;) !
1546# ifdef __DEBUG
1547 if (status != 0) {
1548 printf("Lock log mutex error: %d\n", status);
1549 fflush(stdout);
1550 }
1551# endif
1552
1553 if (!checkLogLevel(type)) { //if not -> unlock mutex -> return
1554 //unlock mutex
1555 status = pthread_mutex_unlock(&log_mut);
1556 // discard eventual error, this would cause more problems
1557 // in each case, do NOT call createLogMessage ;)
1558# ifdef __DEBUG
1559 if (status != 0) {
1560 printf("Unlock log mutex error: %d\n", status);
1561 fflush(stdout);
1562 }
1563# endif
1564 return;
1565 }
1566
1567 // check if message is a replicate of the last log message
1568 if ((logWatchDogRunning) && (strncmp(description, lastMessage.description,
1569 (MSG_DESCRIPTION_SIZE - 1)) == 0)) {
1570 replicatedMsgCount++;
1571
1572 //unlock mutex
1573 status = pthread_mutex_unlock(&log_mut);
1574 // discard eventual error, this would cause more problems
1575 // in each case, do NOT call createLogMessage ;)
1576# ifdef __DEBUG
1577 if (status != 0) {
1578 printf("Unlock log mutex error: %d\n", status);
1579 fflush(stdout);
1580 }
1581# endif
1582 // message is a replicate of last message, leave Messenger
1583 return;
1584 } else {
1585 // message is not a replicate of last one send,
1586 // check if replicated log messages are pending
1587 if (checkReplicatedLogMessage()) {
1588 // sleep a small amount to let Dim update channel
1589// usleep(1000);
1590 }
1591 }
1592
1593 // prepare data (cut off overlength)
1594 if (description != 0) {
1595 // limit description to maximum of field in message struct if longer
1596 descLength = ((strlen(description) >= MSG_DESCRIPTION_SIZE)
1597 ? (MSG_DESCRIPTION_SIZE - 1) : strlen(description));
1598 }
1599 if (origin != 0) {
1600 // limit origin to maximum of field in message struct if longer
1601 // be aware that "source" also contains server name and a slash
1602 originLength = ((strlen(origin) >= MSG_SOURCE_SIZE - serverNameLength - 1)
1603 ? (MSG_SOURCE_SIZE - serverNameLength - 2) : strlen(origin));
1604 }
1605
1606 //set type
1607 message.eventType = type;
1608 //set detector
1609 memcpy(message.detector, LOCAL_DETECTOR, MSG_DETECTOR_SIZE);
1610 //set origin
1611 strcpy(message.source, serverName);
1612 if (origin != 0) {
1613 // append slash
1614 strcpy(message.source + serverNameLength, "/");
1615 // append origin maximum til end of source field in message struct
1616 strncpy(message.source + serverNameLength + 1, origin, originLength);
1617 // terminate with '\0'
1618 message.source[serverNameLength + 1 + originLength] = 0;
1619 }
1620 //set description
1621 if (description != 0) {
1622 // fill description field of message struct maximum til end
1623 strncpy(message.description, description, descLength);
1624 // terminate with '\0'
1625 message.description[descLength] = 0;
1626 } else {
1627 strcpy(message.description, "No description specified.");
1628 }
1629 //set current date and time
1630 time(&timeVal);
1631 now = localtime(&timeVal);
1632 message.date[strftime(message.date, MSG_DATE_SIZE, "%Y-%m-%d %H:%M:%S",
1633 now)] = 0;
1634
1635 //updateService
1636 dis_update_service(messageServiceID);
1637
1638 // copy send message to storage of last message
1639 lastMessage = message;
1640
1641 //unlock mutex
1642 status = pthread_mutex_unlock(&log_mut);
1643 // discard eventual error, this would cause more problems
1644 // in each case, do NOT call createLogMessage ;)
1645# ifdef __DEBUG
1646 if (status != 0) {
1647 printf("Unlock log mutex error: %d\n", status);
1648 fflush(stdout);
1649 }
1650# endif
1651}
1652
1653bool checkLogLevel(int event) {
1654 // Comparision with binary AND, if result has 1 as any digit, event is
1655 // included in current logLevel
1656 if ((logLevel & event) != 0) {
1657 return true;
1658 }
1659 return false;
1660}
1661
1662void dim_error_msg_handler(int severity, int error_code, char* msg) {
1663 char type[8];
1664 int eventType = 0;
1665 char message[MSG_DESCRIPTION_SIZE];
1666 int length = 0;
1667
1668 // map severity to own log levels
1669 switch (severity) {
1670 case 0:
1671 type[sprintf(type, "INFO")] = 0;
1672 eventType = MSG_INFO;
1673 break;
1674 case 1:
1675 type[sprintf(type, "WARNING")] = 0;
1676 eventType = MSG_WARNING;
1677 break;
1678 case 2:
1679 type[sprintf(type, "ERROR")] = 0;
1680 eventType = MSG_ERROR;
1681 break;
1682 case 3:
1683 type[sprintf(type, "FATAL")] = 0;
1684 eventType = MSG_ERROR;
1685 break;
1686 default :
1687 type[sprintf(type, "UNKNOWN")] = 0;
1688 eventType = MSG_WARNING;
1689 break;
1690 }
1691
1692# ifdef __DEBUG
1693 // print to command line if wanted
1694 printf("DIM: [%s - %d] - %d: %s.\n", type, severity, error_code, msg);
1695 fflush(stdout);
1696# endif
1697
1698 // send message only if FeeServer is in serving or error state
1699 if ((state == RUNNING) || (state == ERROR_STATE)) {
1700 // put DIM error code in front of message
1701 message[sprintf(message, "%s: ", mapDimErrorCodes(error_code))] = 0;
1702 length = strlen(message);
1703 strncpy((message + length), msg, (MSG_DESCRIPTION_SIZE - length - 1));
1704 message[MSG_DESCRIPTION_SIZE - 1] = 0;
1705 // deliver message to FeeServer message system
1706 createLogMessage(eventType, message, "DIM\0");
1707 }
1708}
1709
1710char* mapDimErrorCodes(int errorCode) {
1711 switch (errorCode) {
1712 case (0x1): return "DIMDNSUNDEF";
1713 case (0x2): return "DIMDNSREFUS";
1714 case (0x3): return "DIMDNSDUPLC";
1715 case (0x4): return "DIMDNSEXIT ";
1716 case (0x5): return "DIMDNSTMOUT";
1717
1718 case (0x10): return "DIMSVCDUPLC";
1719 case (0x11): return "DIMSVCFORMT";
1720 case (0x12): return "DIMSVCINVAL";
1721 case (0x13): return "DIMSVCTOOLG";
1722
1723 case (0x20): return "DIMTCPRDERR";
1724 case (0x21): return "DIMTCPWRRTY";
1725 case (0x22): return "DIMTCPWRTMO";
1726 case (0x23): return "DIMTCPLNERR";
1727 case (0x24): return "DIMTCPOPERR";
1728 case (0x25): return "DIMTCPCNERR";
1729 case (0x26): return "DIMTCPCNEST";
1730
1731 case (0x30): return "DIMDNSCNERR";
1732 case (0x31): return "DIMDNSCNEST";
1733
1734 default: return "DIMUNKWNERR";
1735 }
1736}
1737
1738//-- tells the server, that he can start serving;
1739//-- no services can be added when server is in state RUNNING
1740int start(int initState) {
1741 int nRet = FEE_UNKNOWN_RETVAL;
1742 char* serviceName = 0;
1743 char* messageName = 0;
1744 char* commandName = 0;
1745 char msgStructure[50];
1746
1747 if (state == COLLECTING) {
1748 //----- add service for acknowledge -----
1749 serviceName = (char*) malloc(serverNameLength + 13);
1750 if (serviceName == 0) {
1751 //no memory available!
1752# ifdef __DEBUG
1753 printf("no memory available while trying to create ACK channel!\n");
1754 fflush(stdout);
1755# endif
1756 // !!! unable to run FeeServer, write msg in kernel logger !!! (-> Tobias)
1757 cleanUp();
1758 exit(201);
1759 }
1760 // compose ACK channel name and terminate with '\0'
1761 serviceName[sprintf(serviceName, "%s_Acknowledge", serverName)] = 0;
1762 if (cmndACK != 0) {
1763 free(cmndACK);
1764 cmndACK = 0;
1765 }
1766 // take created header
1767 cmndACK = createHeader(0, initState, false, false, 0);
1768 cmndACKSize = HEADER_SIZE;
1769 // add ACK channel as service to DIM
1770 serviceACKID = dis_add_service(serviceName, "C", 0, 0, &ack_service,
1771 ACK_SERVICE_TAG);
1772 free(serviceName);
1773
1774 //----- add message service -----
1775 messageName = (char*) malloc(serverNameLength + 9);
1776 if (messageName == 0) {
1777 //no memory available!
1778# ifdef __DEBUG
1779 printf("no memory available while trying to create message channel!\n");
1780 fflush(stdout);
1781# endif
1782 // !!! unable to run FeeServer, write msg in kernel logger !!! (->Tobias)
1783 cleanUp();
1784 exit(201);
1785 }
1786 // compose message channel name and terminate with '\0'
1787 messageName[sprintf(messageName, "%s_Message", serverName)] = 0;
1788 // compose message structure
1789 msgStructure[sprintf(msgStructure, "I:1;C:%d;C:%d;C:%d;C:%d",
1790 MSG_DETECTOR_SIZE, MSG_SOURCE_SIZE, MSG_DESCRIPTION_SIZE,
1791 MSG_DATE_SIZE)] = 0;
1792 // add message channel as service to DIM
1793 messageServiceID = dis_add_service(messageName, msgStructure, (int*) &message,
1794 sizeof(unsigned int) + MSG_DETECTOR_SIZE + MSG_SOURCE_SIZE +
1795 MSG_DESCRIPTION_SIZE + MSG_DATE_SIZE, 0, 0);
1796 free(messageName);
1797
1798 //----- before start serving we add the only command handled by the server -----
1799 commandName = (char*) malloc(serverNameLength + 9);
1800 if (commandName == 0) {
1801 //no memory available!
1802# ifdef __DEBUG
1803 printf("no memory available while trying to create CMD channel!\n");
1804 fflush(stdout);
1805# endif
1806 // !!! unable to run FeeServer, write msg in kernel logger !!! (->Tobias)
1807 cleanUp();
1808 exit(201);
1809 }
1810 // compose Command channel name and terminate with '\0'
1811 commandName[sprintf(commandName, "%s_Command", serverName)] = 0;
1812 // add CMD channel as command to DIM, no tag needed,
1813 // only one command possible
1814 commandID = dis_add_cmnd(commandName, "C", &command_handler, 0);
1815 free(commandName);
1816
1817 //-- now start serving --
1818 if (dis_start_serving(serverName) == 1) {
1819 // if start server was successful
1820 if (initState == FEE_OK) {
1821 state = RUNNING;
1822 // start monitoring thread now
1823 nRet = startMonitorThread();
1824 if (nRet != FEE_OK) {
1825# ifdef __DEBUG
1826 printf("Could NOT start monitor thread, error: %d\n", nRet);
1827 fflush(stdout);
1828# endif
1829 createLogMessage(MSG_ERROR,
1830 "Unable to start monitor thread on FeeServer.", 0);
1831 return nRet;
1832 }
1833 // inform CE about update rate
1834 provideUpdateRate();
1835 createLogMessage(MSG_INFO,
1836 "FeeServer started correctly, including monitor thread.", 0);
1837 nRet = FEE_OK;
1838 } else {
1839 state = ERROR_STATE;
1840 createLogMessage(MSG_ERROR,
1841 "Initialisation of ControlEngine failed. FeeServer is running in ERROR state (without CE).",
1842 0);
1843 // starting itself worked, so nRet is OK
1844 nRet = FEE_OK;
1845 }
1846 // start "relicated log messages" watchdog now
1847 nRet = startLogWatchDogThread();
1848 if (nRet != FEE_OK) {
1849# ifdef __DEBUG
1850 printf("Could NOT start log watch dog thread, error: %d; FeeServer will run without it.\n",
1851 nRet);
1852 fflush(stdout);
1853# endif
1854 createLogMessage(MSG_WARNING,
1855 "Can not start LogWatchDog thread (filters replicated MSGs). Uncritical error - running without it.",
1856 0);
1857 }
1858 } else {
1859 // starting server was not successful, so remove added core - services
1860 // so they can be added again by next start() - call
1861 dis_remove_service(serviceACKID);
1862 free(cmndACK);
1863 cmndACK = 0;
1864 cmndACKSize = 0;
1865 dis_remove_service(messageServiceID);
1866 dis_remove_service(commandID);
1867 nRet = FEE_FAILED;
1868 }
1869 return nRet;
1870 }
1871 //server is already running
1872 return FEE_OK;
1873}
1874
1875// ****************************************
1876// ---- starts the monitoring thread ----
1877// ****************************************
1878int startMonitorThread() {
1879 int status = -1;
1880 pthread_attr_t attr;
1881
1882 // when item lists are empty, no monitor threads are needed
1883 if ((nodesAmount == 0) && (intNodesAmount == 0)) {
1884 createLogMessage(MSG_INFO,
1885 "No Items (float and int) for monitoring are available.", 0);
1886 return FEE_OK;
1887 }
1888
1889 // init thread attribut and set it
1890 status = pthread_attr_init(&attr);
1891 if (status != 0) {
1892# ifdef __DEBUG
1893 printf("Init attribute error [mon]: %d\n", status);
1894 fflush(stdout);
1895# endif
1896 return FEE_MONITORING_FAILED;
1897 }
1898 status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1899 if (status != 0) {
1900# ifdef __DEBUG
1901 printf("Set attribute error [mon]: %d\n", status);
1902 fflush(stdout);
1903# endif
1904 return FEE_MONITORING_FAILED;
1905 }
1906
1907 // start the monitor thread for float values
1908 if (nodesAmount > 0) {
1909 status = pthread_create(&thread_mon, &attr, (void*)&monitorValues, 0);
1910 if (status != 0) {
1911# ifdef __DEBUG
1912 printf("Create thread error [mon - float]: %d\n", status);
1913 fflush(stdout);
1914# endif
1915 return FEE_MONITORING_FAILED;
1916 }
1917 }
1918
1919 //start the monitor thread for int values --> NEW v.0.8.1
1920 if (intNodesAmount > 0) {
1921 status = pthread_create(&thread_mon_int, &attr, (void*)&monitorIntValues, 0);
1922 if (status != 0) {
1923# ifdef __DEBUG
1924 printf("Create thread error [mon - int]: %d\n", status);
1925 fflush(stdout);
1926# endif
1927 return FEE_MONITORING_FAILED;
1928 }
1929 }
1930
1931 // cleanup attribut
1932 status = pthread_attr_destroy(&attr);
1933 if (status != 0) {
1934# ifdef __DEBUG
1935 printf("Destroy attribute error [mon]: %d\n", status);
1936 fflush(stdout);
1937# endif
1938 // no error return value necessary !
1939 }
1940 return FEE_OK;
1941}
1942
1943// --- this is the monitoring thread ---
1944void monitorValues() {
1945 int status = -1;
1946 int nRet;
1947 unsigned long sleepTime = 0;
1948 ItemNode* current = 0;
1949 char msg[120];
1950 unsigned long innerCounter = 0; // used for update check after time interval
1951 unsigned long outerCounter = 0; // used for update check after time interval
1952
1953 // set flag, that monitor thread has been started
1954 monitorThreadStarted = true;
1955
1956 // set cancelation type
1957 status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
1958 if (status != 0) {
1959# ifdef __DEBUG
1960 printf("Set cancel state error [mon - float]: %d\n", status);
1961 fflush(stdout);
1962# endif
1963 createLogMessage(MSG_WARNING,
1964 "Unable to configure monitor thread (float) properly. Monitoring is not affected.", 0);
1965 }
1966 status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
1967 if (status != 0) {
1968# ifdef __DEBUG
1969 printf("Set cancel type error [mon - float]: %d\n", status);
1970 fflush(stdout);
1971# endif
1972 createLogMessage(MSG_WARNING,
1973 "Unable to configure monitor thread (float) properly. Monitoring is not affected.", 0);
1974 }
1975
1976 createLogMessage(MSG_DEBUG, "Started monitor thread for FLOAT values successfully.", 0);
1977
1978 while (1) {
1979 current = firstNode;
1980 sleepTime = (unsigned long) (updateRate / nodesAmount);
1981 while (current != 0) { // is lastNode->next (end of list)
1982 if (!checkLocation(current)) {
1983 msg[sprintf(msg, "Value of item %s (float) is corrupt, reconstruction failed. Ignoring!",
1984 current->item->name)] = 0;
1985 createLogMessage(MSG_ERROR, msg, 0);
1986 // message and do some stuff (like invalidate value)
1987 // (test, what happens if pointer is redirected ???)
1988 } else {
1989 if ((fabsf((*(current->item->location)) - current->lastTransmittedValue)
1990 >= current->threshold) || (outerCounter ==
1991 (innerCounter * TIME_INTERVAL_MULTIPLIER))) {
1992 nRet = dis_update_service(current->id);
1993 current->lastTransmittedValue = *(current->item->location);
1994# ifdef __DEBUG
1995 //printf("Updated %d clients for service %s [float]: %f\n", nRet,
1996 // current->item->name, *(current->item->location));
1997 //fflush(stdout);
1998# endif
1999 }
2000 }
2001
2002 ++innerCounter;
2003 current = current->next;
2004 usleep(sleepTime * 1000);
2005 // sleeps xy microseconds, needed milliseconds-> "* 1000"
2006 }
2007 // with the check of both counter, each service is at least updated after
2008 // every (deadband updateRate * nodesAmount) seconds
2009 innerCounter = 0;
2010 ++outerCounter;
2011 // after every service in list is updated set counter back to 0
2012 // the TIME_INTERVAL_MULTIPLIER is used to enlarge the time interval of
2013 // the request of services without touching the deadband checker updateRate
2014 if (outerCounter >= (nodesAmount * TIME_INTERVAL_MULTIPLIER)) {
2015 outerCounter = 0;
2016 }
2017 }
2018 // should never be reached !
2019 pthread_exit(0);
2020}
2021
2022// checks against bitflips in location
2023bool checkLocation(ItemNode* node) {
2024 if (node->item->location == node->locBackup) {
2025 // locations are identical, so no bitflip
2026 return true;
2027 }
2028 // locations are not identical, check further
2029
2030 if (node->checksum == calculateChecksum((unsigned char*)
2031 &(node->item->location), sizeof(volatile float*))) {
2032 // checksum tells, that first location should be valid, repair backup
2033 node->locBackup = node->item->location;
2034 return true;
2035 }
2036 // original location or first checksum is wrong, continue checking
2037
2038 if (node->checksum == calculateChecksum((unsigned char*)
2039 &(node->locBackup), sizeof(volatile float*))) {
2040 // checksum tells, that location backup should be valid, repair original
2041 node->item->location = node->locBackup;
2042 return true;
2043 }
2044 // location backup or first checksum is wrong, continue checking
2045
2046 if (node->checksum == node->checksumBackup) {
2047 // it seems that location and location backup are wrong
2048 // or checksum value runs banana, not repairable
2049 return false;
2050 }
2051 // it seems that first checksum is wrong
2052 // try to fix with second checksum
2053
2054 if (node->checksumBackup == calculateChecksum((unsigned char*)
2055 &(node->item->location), sizeof(volatile float*))) {
2056 // checksum backup tells, that first location should be valid, repair backup
2057 node->locBackup = node->item->location;
2058 // repair first checksum
2059 node->checksum = node->checksumBackup;
2060 return true;
2061 }
2062 // original location or second checksum is wrong, continue checking
2063
2064 if (node->checksumBackup == calculateChecksum((unsigned char*)
2065 &(node->locBackup), sizeof(volatile float*))) {
2066 // checksum backup tells, that location backup should be valid, repair original
2067 node->item->location = node->locBackup;
2068 // repair checksum
2069 node->checksum = node->checksumBackup;
2070 return true;
2071 }
2072 // value is totally banana, no chance to fix
2073 return false;
2074}
2075
2076// ****************************************
2077// ---- starts the LogWatchdog Thread ----
2078// ****************************************
2079int startLogWatchDogThread() {
2080 int status = -1;
2081 pthread_attr_t attr;
2082
2083 // init thread attribut and set it
2084 status = pthread_attr_init(&attr);
2085 if (status != 0) {
2086# ifdef __DEBUG
2087 printf("Init attribute error [LogWatchDog]: %d\n", status);
2088 fflush(stdout);
2089# endif
2090 return FEE_THREAD_ERROR;
2091 }
2092 status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2093 if (status != 0) {
2094# ifdef __DEBUG
2095 printf("Set attribute error [LogWatchDog]: %d\n", status);
2096 fflush(stdout);
2097# endif
2098 return FEE_THREAD_ERROR;
2099 }
2100
2101 // start the LogWatchDog thread
2102 status = pthread_create(&thread_logWatchdog, &attr, (void*) &runLogWatchDog,
2103 0);
2104 if (status != 0) {
2105# ifdef __DEBUG
2106 printf("Create thread error [LogWatchDog]: %d\n", status);
2107 fflush(stdout);
2108# endif
2109 return FEE_THREAD_ERROR;
2110 }
2111
2112 // cleanup attribut
2113 status = pthread_attr_destroy(&attr);
2114 if (status != 0) {
2115# ifdef __DEBUG
2116 printf("Destroy attribute error [LogWatchDog]: %d\n", status);
2117 fflush(stdout);
2118# endif
2119 // no error return value necessary !
2120 }
2121
2122 return FEE_OK;
2123}
2124
2125void runLogWatchDog() {
2126 int status = -1;
2127 unsigned int sleepSec = 0;
2128 unsigned int sleepMilliSec = 0;
2129
2130 // set cancelation type
2131 status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
2132 if (status != 0) {
2133# ifdef __DEBUG
2134 printf("Set cancel state error [LogWatchDog]: %d\n", status);
2135 fflush(stdout);
2136# endif
2137 createLogMessage(MSG_WARNING,
2138 "Can not set cancel state for LogWatchDog thread. WatchDog should not not be affected.",
2139 0);
2140 }
2141 status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
2142 if (status != 0) {
2143# ifdef __DEBUG
2144 printf("Set cancel type error [LogWatchDog]: %d\n", status);
2145 fflush(stdout);
2146# endif
2147 createLogMessage(MSG_WARNING,
2148 "Can not set cancel type for LogWatchDog thread. WatchDog should not not be affected.",
2149 0);
2150 }
2151
2152 // thread started successfully, set flag accordingly
2153 logWatchDogRunning = true;
2154 createLogMessage(MSG_DEBUG,
2155 "LogWatchDog thread for filtering replicated log messages successfully started.",
2156 0);
2157# ifdef __DEBUG
2158 printf("LogWatchDog thread for filtering replicated log messages successfully started.\n");
2159 fflush(stdout);
2160# endif
2161
2162 while (1) {
2163 // before test for replicated messages lock mutex,
2164 // DON'T call createLogMessage() inside mutex lock
2165 status = pthread_mutex_lock(&log_mut);
2166 // discard eventual error, this would cause more problems
2167# ifdef __DEBUG
2168 if (status != 0) {
2169 printf("Lock log mutex error: %d\n", status);
2170 fflush(stdout);
2171 }
2172# endif
2173
2174 // perform check here
2175 checkReplicatedLogMessage();
2176
2177 // release mutex
2178 status = pthread_mutex_unlock(&log_mut);
2179 // discard eventual error, this would cause more problems
2180# ifdef __DEBUG
2181 if (status != 0) {
2182 printf("Unlock log mutex error: %d\n", status);
2183 fflush(stdout);
2184 }
2185# endif
2186
2187 // set cancelation point
2188 pthread_testcancel();
2189 // prepare sleep time (timeout)
2190 sleepSec = logWatchDogTimeout / 1000;
2191 sleepMilliSec = logWatchDogTimeout % 1000;
2192 usleep(sleepMilliSec * 1000);
2193 dtq_sleep(sleepSec);
2194 // set cancelation point
2195 pthread_testcancel();
2196 }
2197
2198 // should never be reached !
2199 pthread_exit(0);
2200}
2201
2202bool checkReplicatedLogMessage() {
2203 int tempLength = 0;
2204 time_t timeVal;
2205 struct tm* now = 0;
2206
2207 // check if replicated messages are pending
2208 if (replicatedMsgCount > 0) {
2209 // replicated messages occured in between, informing upper layer ...
2210 message.description[sprintf(message.description,
2211 "Log message repeated %d times: ", replicatedMsgCount)] = 0;
2212 // append original message as far as possible
2213 tempLength = strlen(message.description);
2214 if ((strlen(lastMessage.description) + tempLength) >=
2215 MSG_DESCRIPTION_SIZE) {
2216 // copy only a part of the original message that fits in the
2217 // description field
2218 strncpy((message.description + tempLength), lastMessage.description,
2219 (MSG_DESCRIPTION_SIZE - tempLength));
2220 message.description[MSG_DESCRIPTION_SIZE - 1] = 0;
2221 } else {
2222 // enough space free, copy the whole original message
2223 strcpy((message.description + tempLength),
2224 lastMessage.description);
2225 message.description[strlen(lastMessage.description) +
2226 tempLength - 1] = 0;
2227 }
2228 // set correct timestamp
2229 time(&timeVal);
2230 now = localtime(&timeVal);
2231 message.date[strftime(message.date, MSG_DATE_SIZE, "%Y-%m-%d %H:%M:%S",
2232 now)] = 0;
2233
2234 //update MsgService with notification of repeated messages
2235 dis_update_service(messageServiceID);
2236 // clearing counter
2237 replicatedMsgCount = 0;
2238 return true;
2239 }
2240 return false;
2241}
2242
2243void* threadIssue(void* threadParam) {
2244 IssueStruct* issueParam = (IssueStruct*) threadParam;
2245 int status;
2246
2247 status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
2248 if (status != 0) {
2249# ifdef __DEBUG
2250 printf("Set cancel state error: %d\n", status);
2251 fflush(stdout);
2252# endif
2253 createLogMessage(MSG_WARNING,
2254 "Unable to configure issue thread properly. Execution might eventually be affected.", 0);
2255 }
2256
2257 status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
2258 if (status != 0) {
2259# ifdef __DEBUG
2260 printf("Set cancel type error error: %d\n", status);
2261 fflush(stdout);
2262# endif
2263 createLogMessage(MSG_WARNING,
2264 "Unable to configure issue thread properly. Execution might eventually be affected.", 0);
2265 }
2266
2267 // executing command inside CE
2268 issueParam->nRet = issue(issueParam->command, &(issueParam->result), &(issueParam->size));
2269
2270 //set cancel type to deferred
2271 status = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
2272 if (status != 0) {
2273# ifdef __DEBUG
2274 printf("Set cancel type error: %d\n", status);
2275 fflush(stdout);
2276# endif
2277 createLogMessage(MSG_WARNING,
2278 "Unable to configure issue thread properly. Execution might eventually be affected.", 0);
2279 }
2280
2281 //lock the mutex before broadcast
2282 status = pthread_mutex_lock(&wait_mut);
2283 if (status != 0) {
2284# ifdef __DEBUG
2285 printf("Lock cond mutex error: %d\n", status);
2286 fflush(stdout);
2287# endif
2288 createLogMessage(MSG_WARNING,
2289 "Unable to lock condition mutex for watchdog in issue thread. Execution might eventually be affected.",
2290 0);
2291 }
2292
2293 //signal that issue has returned from ControlEngine
2294 // maybe try the call pthread_cond_signal instead for performance
2295 pthread_cond_broadcast(&cond);
2296
2297 // unlock mutex
2298 status = pthread_mutex_unlock(&wait_mut);
2299 if (status != 0) {
2300# ifdef __DEBUG
2301 printf("Unlock cond mutex error: %d\n", status);
2302 fflush(stdout);
2303# endif
2304 createLogMessage(MSG_WARNING,
2305 "Unable to unlock condition mutex for watchdog in issue thread. Execution might eventually be affected.",
2306 0);
2307 }
2308
2309// not needed, return 0 is better solution
2310// pthread_exit(0);
2311 return 0;
2312}
2313
2314
2315char* createHeader(unsigned int id, short errorCode, bool huffmanFlag,
2316 bool checksumFlag, int checksum) {
2317 char* pHeader = 0;
2318 FlagBits flags = NO_FLAGS;
2319
2320 if (huffmanFlag) {
2321 //set huffman flag via binary OR
2322 flags |= HUFFMAN_FLAG;
2323 }
2324 if (checksumFlag) {
2325 //set checksum flag via binary OR
2326 flags |= CHECKSUM_FLAG;
2327 }
2328
2329 pHeader = (char*) malloc(HEADER_SIZE);
2330 if (pHeader == 0) {
2331 //no memory available!
2332# ifdef __DEBUG
2333 printf("no memory available while trying to create header!\n");
2334 fflush(stdout);
2335# endif
2336 createLogMessage(MSG_ALARM,
2337 "No more memory available, unable to continue serving - exiting.",
2338 0);
2339 cleanUp();
2340 exit(201);
2341 }
2342
2343 memcpy(pHeader, &id, HEADER_SIZE_ID);
2344 memcpy(pHeader + HEADER_OFFSET_ID, &errorCode, HEADER_SIZE_ERROR_CODE);
2345 memcpy(pHeader + HEADER_OFFSET_ERROR_CODE, &flags, HEADER_SIZE_FLAGS);
2346 memcpy(pHeader + HEADER_OFFSET_FLAGS, &checksum, HEADER_SIZE_CHECKSUM);
2347
2348 return pHeader;
2349}
2350
2351
2352bool checkCommand(char* payload, int size, unsigned int checksum) {
2353 unsigned int payloadChecksum = 0;
2354
2355 // payload has to contain data, if size is greater than 0,
2356 // and size must not be negative
2357 if (((payload == 0) && (size > 0)) || (size < 0)) {
2358 return false;
2359 }
2360
2361 payloadChecksum = calculateChecksum((unsigned char*) payload, size);
2362# ifdef __DEBUG
2363 printf("\nReceived Checksum: \t%x , \nCalculated Checksum: \t%x .\n\n",
2364 checksum, payloadChecksum);
2365 fflush(stdout);
2366# endif
2367 return (payloadChecksum == checksum) ? true : false;
2368}
2369
2370// ! Problems with signed and unsigned char, make differences in checksum
2371// -> so USE "unsigned char*" !
2372unsigned int calculateChecksum(unsigned char* buffer, int size) {
2373 int n;
2374 unsigned int checks = 0;
2375 unsigned long adler = 1L;
2376 unsigned long part1 = adler & 0xffff;
2377 unsigned long part2 = (adler >> 16) & 0xffff;
2378
2379 // calculates the checksum with the Adler32 algorithm
2380 for (n = 0; n < size; n++) {
2381 part1 = (part1 + buffer[n]) % ADLER_BASE;
2382 part2 = (part2 + part1) % ADLER_BASE;
2383 }
2384 checks = (unsigned int) ((part2 << 16) + part1);
2385
2386 return checks;
2387}
2388
2389char* marshallHeader(CommandHeader* pHeader) {
2390 char* tempHeader = 0;
2391
2392 tempHeader = (char*) malloc(HEADER_SIZE);
2393 if (tempHeader == 0) {
2394 //no memory available!
2395# ifdef __DEBUG
2396 printf("no memory available!\n");
2397 fflush(stdout);
2398# endif
2399 createLogMessage(MSG_ALARM,
2400 "No more memory available, unable to continue serving - exiting.",
2401 0);
2402 cleanUp();
2403 exit(201);
2404 }
2405
2406 memcpy(tempHeader, &(pHeader->id), HEADER_SIZE_ID);
2407 memcpy(tempHeader + HEADER_OFFSET_ID, &(pHeader->errorCode), HEADER_SIZE_ERROR_CODE);
2408 memcpy(tempHeader + HEADER_OFFSET_ERROR_CODE, &(pHeader->flags), HEADER_SIZE_FLAGS);
2409 memcpy(tempHeader + HEADER_OFFSET_FLAGS, &(pHeader->checksum), HEADER_SIZE_CHECKSUM);
2410
2411 return tempHeader;
2412}
2413
2414// *********************************************************************************************
2415// ---------------- here come all the FeeServer commands ----------------------------------------
2416// *********************************************************************************************
2417void updateFeeServer(IssueStruct* issueParam) {
2418#ifdef ENABLE_MASTERMODE
2419 int status = 0;
2420 int i = 0;
2421 FILE* fp = 0;
2422
2423 if ((*issueParam).size == 0) {
2424 createLogMessage(MSG_ERROR, "Received new FeeServer with size 0.", 0);
2425 return;
2426 }
2427# ifdef __DEBUG
2428 printf("Received update command, updating FeeServer now!\n");
2429 fflush(stdout);
2430# endif
2431 // execute instruction self and release mutex before return
2432 fp = fopen("newFeeserver", "w+b");
2433 if (fp == 0) {
2434 createLogMessage(MSG_ERROR, "Unable to save new FeeServer binary.", 0);
2435 return;
2436 }
2437
2438 for ( i = 0; i < (*issueParam).size; ++i) {
2439 fputc((*issueParam).command[i], fp);
2440 }
2441 fclose(fp);
2442 createLogMessage(MSG_INFO, "FeeServer updated.", 0);
2443
2444 // should we call cleanUp() before restart
2445 // better not: another possibility to hang ???
2446 // -> cleanUp is in restart implicit ! except opened drivers
2447 // could only be necessary, if some driver conns have to be closed.
2448 cleanUp();
2449 status = pthread_mutex_unlock(&command_mut);
2450# ifdef __DEBUG
2451 if (status != 0) {
2452 printf("Unlock FeeCommand mutex error: %d\n", status);
2453 fflush(stdout);
2454 }
2455# endif
2456
2457 // Exit status "3" tells the starting script to finalise update and restart
2458 // FeeServer after termination.
2459 exit(3);
2460#endif //ENABLE_MASTERMODE
2461}
2462
2463void restartFeeServer() {
2464 triggerRestart(FEE_EXITVAL_RESTART);
2465}
2466
2467void triggerRestart(int exitVal) {
2468 int status = 0;
2469 char msg[80];
2470
2471# ifdef __DEBUG
2472 printf("Triggering restart with exit value: %d\n", exitVal);
2473 fflush(stdout);
2474# endif
2475 msg[sprintf(msg, "Restarting FeeServer - exit value: %d ", exitVal)] = 0;
2476 createLogMessage(MSG_INFO, msg, 0);
2477
2478 // should we call cleanUp() before restart
2479 // better not: another possibility to hang ???
2480 // -> cleanUp is in restart implicit ! except opened drivers
2481 // could only be necessary, if some driver cons has to be closed.
2482 cleanUp();
2483 status = pthread_mutex_unlock(&command_mut);
2484# ifdef __DEBUG
2485 if (status != 0) {
2486 printf("Unlock FeeCommand mutex error: %d\n", status);
2487 fflush(stdout);
2488 }
2489# endif
2490 // Exit status tells the startScript which type of restart is performed
2491 exit(exitVal);
2492}
2493
2494int setDeadband(IssueStruct* issueParam) {
2495 char* itemName = 0;
2496 float newDeadband = 0;
2497 int nameLength = 0;
2498 ItemNode* node = 0;
2499 IntItemNode* intNode = 0;
2500 char msg[100];
2501 unsigned int count = 0;
2502
2503 if ((*issueParam).size <= sizeof(newDeadband)) {
2504 (*issueParam).size = 0;
2505 createLogMessage(MSG_DEBUG,
2506 "FeeServer command for setting dead band contained invalid parameter.",
2507 0);
2508 return FEE_INVALID_PARAM;
2509 }
2510
2511 nameLength = (*issueParam).size - sizeof(newDeadband);
2512
2513 if (nameLength <= 0) {
2514 (*issueParam).size = 0;
2515 createLogMessage(MSG_DEBUG,
2516 "FeeServer command for setting dead band contained no service name.",
2517 0);
2518 return FEE_INVALID_PARAM;
2519 }
2520
2521 itemName = (char*) malloc(nameLength + 1);
2522 if (itemName == 0) {
2523 (*issueParam).size = 0;
2524 return FEE_INSUFFICIENT_MEMORY;
2525 }
2526
2527 memcpy(&newDeadband, (*issueParam).command, sizeof(newDeadband));
2528 memcpy(itemName, (*issueParam).command + sizeof(newDeadband), nameLength);
2529 itemName[nameLength] = 0;
2530
2531 if (itemName[0] != '*') {
2532 // search wanted itemNode
2533 node = findItem(itemName);
2534 if (node == 0) {
2535 //check in IntItemList
2536 intNode = findIntItem(itemName);
2537 }
2538 if ((node == 0) && (intNode == 0)) {
2539 // message is NOT sent in findItem() or findIntItem()
2540 msg[sprintf(msg, "Item %s not found in list.", itemName)] = 0;
2541 createLogMessage(MSG_WARNING, msg, 0);
2542# ifdef __DEBUG
2543 printf("Item %s not found in list.\n", itemName);
2544 fflush(stdout);
2545# endif
2546
2547 free(itemName);
2548 (*issueParam).size = 0;
2549 createLogMessage(MSG_DEBUG,
2550 "FeeServer command for setting dead band contained invalid parameter.",
2551 0);
2552 return FEE_INVALID_PARAM;
2553 } else {
2554 // set new threshold ( = dead band / 2)
2555 if (node != 0) {
2556 node->threshold = newDeadband / 2;
2557 } else {
2558 intNode->threshold = newDeadband / 2;
2559 }
2560# ifdef __DEBUG
2561 printf("Set deadband on item %s to %f.\n", itemName, newDeadband);
2562 fflush(stdout);
2563# endif
2564 msg[sprintf(msg, "New dead band (%f) is set for item %s.",
2565 newDeadband, itemName)] = 0;
2566 createLogMessage(MSG_INFO, msg, 0);
2567 }
2568 } else {
2569 // set now for all wanted value the new deadband
2570 count = setDeadbandBroadcast(itemName, newDeadband);
2571
2572# ifdef __DEBUG
2573 printf("Set deadband for %d items (%s) to %f.\n", count, itemName, newDeadband);
2574 fflush(stdout);
2575# endif
2576 msg[sprintf(msg, "New dead band (%f) is set for %d items (%s).",
2577 newDeadband, count, itemName)] = 0;
2578 createLogMessage(MSG_INFO, msg, 0);
2579 }
2580
2581 free(itemName);
2582 (*issueParam).size = 0;
2583 return FEE_OK;
2584}
2585
2586int getDeadband(IssueStruct* issueParam) {
2587 char* itemName = 0;
2588 int nameLength = 0;
2589 ItemNode* node = 0;
2590 IntItemNode* intNode = 0;
2591 float currentDeadband = 0;
2592 char msg[120];
2593
2594 if ((*issueParam).size <= 0) {
2595 (*issueParam).size = 0;
2596 createLogMessage(MSG_DEBUG,
2597 "FeeServer command for getting dead band contained invalid parameter.",
2598 0);
2599 return FEE_INVALID_PARAM;
2600 }
2601
2602 nameLength = (*issueParam).size;
2603 itemName = (char*) malloc(nameLength + 1);
2604 if (itemName == 0) {
2605 (*issueParam).size = 0;
2606 return FEE_INSUFFICIENT_MEMORY;
2607 }
2608
2609 memcpy(itemName, (*issueParam).command, nameLength);
2610 itemName[nameLength] = 0;
2611
2612 // search wanted itemNode
2613 node = findItem(itemName);
2614 if (node == 0) {
2615 //check in IntItemList
2616 intNode = findIntItem(itemName);
2617 }
2618 if ((node == 0) && (intNode == 0)) {
2619 // message is NOT sent in findItem() or findIntItem()
2620 msg[sprintf(msg, "Item %s not found in list.", itemName)] = 0;
2621 createLogMessage(MSG_WARNING, msg, 0);
2622# ifdef __DEBUG
2623 printf("Item %s not found in list.\n", itemName);
2624 fflush(stdout);
2625# endif
2626
2627 free(itemName);
2628 (*issueParam).size = 0;
2629 createLogMessage(MSG_DEBUG,
2630 "FeeServer command for getting dead band contained invalid parameter.",
2631 0);
2632 return FEE_INVALID_PARAM;
2633 } else {
2634 (*issueParam).result = (char*) malloc(sizeof(float) + nameLength);
2635 if ((*issueParam).result == 0) {
2636 (*issueParam).size = 0;
2637 return FEE_INSUFFICIENT_MEMORY;
2638 }
2639
2640 // copy current deadband value to ACK result
2641 if (node != 0) {
2642 currentDeadband = node->threshold * 2.0; // compute deadband
2643 } else {
2644 currentDeadband = intNode->threshold * 2.0; // compute deadband
2645 }
2646
2647 memcpy((*issueParam).result, &currentDeadband, sizeof(float));
2648 memcpy((*issueParam).result + sizeof(float), itemName, nameLength);
2649 (*issueParam).size = sizeof(float) + nameLength;
2650# ifdef __DEBUG
2651 printf("Current deadband on item %s is %f.\n", itemName, currentDeadband);
2652 fflush(stdout);
2653# endif
2654 msg[sprintf(msg, "Current deadband for item %s is %f.", itemName,
2655 currentDeadband)] = 0;
2656 createLogMessage(MSG_DEBUG, msg, 0);
2657 }
2658 free(itemName);
2659 return FEE_OK;
2660}
2661
2662int setIssueTimeout(IssueStruct* issueParam) {
2663 char msg[70];
2664 unsigned long newTimeout;
2665
2666 if ((*issueParam).size < sizeof(unsigned long)) {
2667 (*issueParam).size = 0;
2668 createLogMessage(MSG_DEBUG,
2669 "FeeServer command for setting issue timeout contained invalid parameter.",
2670 0);
2671 return FEE_INVALID_PARAM;
2672 }
2673 memcpy(&newTimeout, (*issueParam).command, sizeof(unsigned long));
2674
2675 // check new timeout for possible buffer overflow (value will be multiplied
2676 // with 1000 later -> has to lower than 4294967 )
2677 if (newTimeout > MAX_ISSUE_TIMEOUT) {
2678 (*issueParam).size = 0;
2679 createLogMessage(MSG_WARNING,
2680 "New timeout for issue watchdog exceeded value limit (4294967).",
2681 0);
2682 return FEE_INVALID_PARAM;
2683 }
2684
2685 issueTimeout = newTimeout;
2686# ifdef __DEBUG
2687 printf("set new Issue timeout to %lu\n", issueTimeout);
2688 fflush(stdout);
2689# endif
2690 msg[sprintf(msg, "Watch dog time out is set to %lu.", issueTimeout)] = 0;
2691 createLogMessage(MSG_INFO, msg, 0);
2692
2693 (*issueParam).size = 0;
2694 return FEE_OK;
2695}
2696
2697int getIssueTimeout(IssueStruct* issueParam) {
2698 char msg[50];
2699
2700 (*issueParam).result = (char*) malloc(sizeof(unsigned long));
2701 if ((*issueParam).result == 0) {
2702 (*issueParam).size = 0;
2703 return FEE_INSUFFICIENT_MEMORY;
2704 }
2705
2706 // copy current timeout for issue to ACK result
2707 memcpy((*issueParam).result, &issueTimeout, sizeof(unsigned long));
2708 (*issueParam).size = sizeof(unsigned long);
2709# ifdef __DEBUG
2710 printf("issue timeout is %lu\n", issueTimeout);
2711 fflush(stdout);
2712# endif
2713 msg[sprintf(msg, "Issue timeout is %lu.", issueTimeout)] = 0;
2714 createLogMessage(MSG_DEBUG, msg, 0);
2715
2716 return FEE_OK;
2717}
2718
2719int setUpdateRate(IssueStruct* issueParam) {
2720 char msg[70];
2721 unsigned short newRate;
2722
2723 if ((*issueParam).size < sizeof(unsigned short)) {
2724 (*issueParam).size = 0;
2725 createLogMessage(MSG_DEBUG,
2726 "FeeServer command for setting update rate contained invalid parameter.",
2727 0);
2728 return FEE_INVALID_PARAM;
2729 }
2730 memcpy(&newRate, (*issueParam).command, sizeof(unsigned short));
2731 updateRate = newRate;
2732 // inform CE about update rate change
2733 provideUpdateRate();
2734# ifdef __DEBUG
2735 printf("set new update rate to %d\n", updateRate);
2736 fflush(stdout);
2737# endif
2738 msg[sprintf(msg, "New update rate for monitoring items: %d.", updateRate)] = 0;
2739 createLogMessage(MSG_INFO, msg, 0);
2740
2741 (*issueParam).size = 0;
2742 return FEE_OK;
2743}
2744
2745int getUpdateRate(IssueStruct* issueParam) {
2746 char msg[50];
2747
2748 (*issueParam).result = (char*) malloc(sizeof(unsigned short));
2749 if ((*issueParam).result == 0) {
2750 (*issueParam).size = 0;
2751 return FEE_INSUFFICIENT_MEMORY;
2752 }
2753
2754 // copy current update rate to ACK result
2755 memcpy((*issueParam).result, &updateRate, sizeof(unsigned short));
2756 (*issueParam).size = sizeof(unsigned short);
2757# ifdef __DEBUG
2758 printf("update rate is %d\n", updateRate);
2759 fflush(stdout);
2760# endif
2761 msg[sprintf(msg, "Monitoring update rate is %d.", updateRate)] = 0;
2762 createLogMessage(MSG_DEBUG, msg, 0);
2763
2764 return FEE_OK;
2765}
2766
2767// be aware of different size of unsigned int in heterogen systems !!
2768int setLogLevel(IssueStruct* issueParam) {
2769 int status = -1;
2770 char msg[70];
2771 unsigned int testLogLevel = 0;
2772
2773 if ((*issueParam).size < sizeof(unsigned int)) {
2774 (*issueParam).size = 0;
2775 createLogMessage(MSG_DEBUG,
2776 "FeeServer command for setting log level contained invalid parameter.",
2777 0);
2778 return FEE_INVALID_PARAM;
2779 }
2780 memcpy(&testLogLevel, (*issueParam).command, sizeof(unsigned int));
2781 // check loglevel for valid data
2782 if (testLogLevel > MSG_MAX_VAL) {
2783# ifdef __DEBUG
2784 printf("received invalid log level %d\n", testLogLevel);
2785 fflush(stdout);
2786# endif
2787 createLogMessage(MSG_DEBUG,
2788 "FeeServer command for setting log level contained invalid parameter.",
2789 0);
2790 return FEE_INVALID_PARAM;
2791 }
2792
2793 status = pthread_mutex_lock(&log_mut);
2794 // discard eventual error
2795 if (status != 0) {
2796# ifdef __DEBUG
2797 printf("Lock log mutex error: %d\n", status);
2798 fflush(stdout);
2799# endif
2800 (*issueParam).size = 0;
2801 return FEE_FAILED;
2802 } else {
2803 logLevel = testLogLevel | MSG_ALARM;
2804
2805 status = pthread_mutex_unlock(&log_mut);
2806 if (status != 0) {
2807# ifdef __DEBUG
2808 printf("Unlock log mutex error: %d\n", status);
2809 fflush(stdout);
2810# endif
2811 createLogMessage(MSG_WARNING, "Unable to unlock logger mutex.", 0);
2812 }
2813
2814# ifdef __DEBUG
2815 printf("set new logLevel to %d\n", logLevel);
2816 fflush(stdout);
2817# endif
2818 msg[sprintf(msg, "New log level on FeeServer: %d.", logLevel)] = 0;
2819 createLogMessage(MSG_INFO, msg, 0);
2820
2821 (*issueParam).size = 0;
2822 return FEE_OK;
2823 }
2824}
2825
2826int getLogLevel(IssueStruct* issueParam) {
2827 char msg[50];
2828
2829 (*issueParam).result = (char*) malloc(sizeof(unsigned int));
2830 if ((*issueParam).result == 0) {
2831 (*issueParam).size = 0;
2832 return FEE_INSUFFICIENT_MEMORY;
2833 }
2834
2835 // copy current update rate to ACK result
2836 memcpy((*issueParam).result, &logLevel, sizeof(unsigned int));
2837 (*issueParam).size = sizeof(unsigned int);
2838# ifdef __DEBUG
2839 printf("Requested loglevel is %d\n", logLevel);
2840 fflush(stdout);
2841# endif
2842 msg[sprintf(msg, "Requested LogLevel is %d.", logLevel)] = 0;
2843 createLogMessage(MSG_DEBUG, msg, 0);
2844
2845 return FEE_OK;
2846}
2847
2848void provideUpdateRate() {
2849 FeeProperty feeProp;
2850 if ((ceInitState == CE_OK) && ((nodesAmount > 0) || (intNodesAmount > 0))) {
2851 feeProp.flag = PROPERTY_UPDATE_RATE;
2852 feeProp.uShortVal = updateRate;
2853 signalFeePropertyChanged(&feeProp);
2854 }
2855}
2856
2857
2858unsigned int setDeadbandBroadcast(char* name, float newDeadbandBC) {
2859 unsigned int count = 0;
2860 ItemNode* current = 0;
2861 IntItemNode* intCurrent = 0;
2862 char* namePart = 0;
2863 char* itemNamePart = 0;
2864
2865 if (name == 0) {
2866 return count;
2867 }
2868
2869 // pointer at first occurance of "_"
2870 namePart = strpbrk(name, "_");
2871 if (namePart == 0) {
2872 return count;
2873 }
2874
2875 // go through list of float values
2876 current = firstNode;
2877 while (current != 0) { // is end of list
2878 // pointer at first occurance of "_"
2879 itemNamePart = strpbrk(current->item->name, "_");
2880 // check if "_" not first character in name and is existing
2881 if ((itemNamePart == 0) || (itemNamePart == current->item->name)) {
2882 current = current->next;
2883 continue;
2884 }
2885 if (strcmp(namePart, itemNamePart) == 0) {
2886 // success, set threshold (= deadband / 2)
2887 current->threshold = newDeadbandBC / 2;
2888 ++count;
2889 }
2890 current = current->next;
2891 }
2892
2893 // go through list of integer values
2894 intCurrent = firstIntNode;
2895 while (intCurrent != 0) { // is end of list
2896 // pointer at first occurance of "_"
2897 itemNamePart = strpbrk(intCurrent->intItem->name, "_");
2898 // check if "_" not first character in name and is existing
2899 if ((itemNamePart == 0) || (itemNamePart == intCurrent->intItem->name)) {
2900 intCurrent = intCurrent->next;
2901 continue;
2902 }
2903 if (strcmp(namePart, itemNamePart) == 0) {
2904 // success, set threshold (= deadband / 2)
2905 intCurrent->threshold = newDeadbandBC / 2;
2906 ++count;
2907 }
2908 intCurrent = intCurrent->next;
2909 }
2910
2911 return count;
2912}
2913
2914int updateFeeService(char* serviceName) {
2915 char msg[80];
2916 ItemNode* node = 0;
2917 IntItemNode* intNode = 0;
2918 CharItemNode* charNode = 0;
2919 int nRet = 0;
2920# ifdef __DEBUG
2921 char* addr = 0;
2922 char* data = 0;
2923 int size = 0;
2924# endif
2925
2926 if (state != RUNNING) {
2927 return FEE_WRONG_STATE;
2928 }
2929 if (serviceName == 0) {
2930 return FEE_NULLPOINTER;
2931 }
2932
2933 // find desired service
2934 node = findItem(serviceName);
2935 if (node == 0) {
2936 //check in IntItemList
2937 intNode = findIntItem(serviceName);
2938 }
2939 if ((node == 0) || (intNode == 0)) {
2940 //check in CharItemList
2941 charNode = findCharItem(serviceName);
2942 }
2943
2944 // check node
2945 if ((node == 0) && (intNode == 0) && (charNode == 0)) {
2946 // message is NOT sent in findItem(), findIntItem() or findCharItem()
2947 msg[sprintf(msg, "Item %s not found in list.", serviceName)] = 0;
2948 createLogMessage(MSG_WARNING, msg, 0);
2949# ifdef __DEBUG
2950 printf("Item %s not found in list.\n", serviceName);
2951 fflush(stdout);
2952# endif
2953 return FEE_INVALID_PARAM;
2954 } else {
2955 if (node != 0) {
2956 nRet = dis_update_service(node->id);
2957# ifdef __DEBUG
2958/* printf("CE triggered an updated on %d clients for service %s [float]: %f\n", */
2959/* nRet, node->item->name, *(node->item->location)); */
2960/* fflush(stdout); */
2961# endif
2962 } else if (intNode != 0) {
2963 nRet = dis_update_service(intNode->id);
2964# ifdef __DEBUG
2965/* printf("CE triggered an updated on %d clients for service %s [int]: %d\n", */
2966/* nRet, intNode->intItem->name, *(intNode->intItem->location)); */
2967/* fflush(stdout); */
2968# endif
2969 } else {
2970 nRet = dis_update_service(charNode->id);
2971# ifdef __DEBUG
2972 (charNode->charItem->user_routine)(&(charNode->charItem->tag),
2973 (int**) &addr, &size);
2974 data = (char*) malloc(size +1);
2975 strncpy(data, addr, size);
2976 data[size] = 0;
2977/* printf("CE triggered an updated on %d clients for service %s [char]: %s\n", */
2978/* nRet, charNode->charItem->name, data); */
2979/* fflush(stdout); */
2980 free(data);
2981# endif
2982 }
2983 }
2984
2985 // return number of updated clients
2986 return nRet;
2987}
2988
2989
2990// *********************************************************************************************
2991// ---------- here comes all the initialisation of selfdefined datatypes -----------------------
2992// *********************************************************************************************
2993void initIssueStruct(IssueStruct* issueStr) {
2994 issueStr->nRet = 0;
2995 issueStr->command = 0;
2996 issueStr->result = 0;
2997 issueStr->size = 0;
2998}
2999
3000void initMessageStruct() {
3001 time_t timeVal;
3002 struct tm* now;
3003
3004 // fill the original message struct
3005 message.eventType = MSG_INFO;
3006 memcpy(message.detector, LOCAL_DETECTOR, MSG_DETECTOR_SIZE);
3007 memcpy(message.source, "FeeServer\0", 10);
3008 message.description[sprintf(message.description,
3009 "FeeServer %s (Version: %s) has been initialized (DNS: %s) ...",
3010 serverName, FEESERVER_VERSION, getenv("DIM_DNS_NODE"))] = 0;
3011 //set current date and time
3012 time(&timeVal);
3013 now = localtime(&timeVal);
3014 message.date[strftime(message.date, MSG_DATE_SIZE, "%Y-%m-%d %H:%M:%S",
3015 now)] = 0;
3016
3017 // the the storage of the "last Message" struct - must be different in
3018 // the description compared to the original message struct above in init
3019 lastMessage.eventType = MSG_DEBUG;
3020 memcpy(lastMessage.detector, LOCAL_DETECTOR, MSG_DETECTOR_SIZE);
3021 memcpy(lastMessage.source, "FeeServer\0", 10);
3022 // now use a different description:
3023 lastMessage.description[sprintf(lastMessage.description,
3024 "Init of Backup Message Struct!")] = 0;
3025 //set current date and time
3026 time(&timeVal);
3027 now = localtime(&timeVal);
3028 lastMessage.date[strftime(lastMessage.date, MSG_DATE_SIZE,
3029 "%Y-%m-%d %H:%M:%S", now)] = 0;
3030}
3031
3032
3033void initItemNode(ItemNode* iNode) {
3034 iNode->prev = 0;
3035 iNode->next = 0;
3036 iNode->id = 0;
3037 iNode->item = 0;
3038 iNode->lastTransmittedValue = 0.0;
3039 iNode->threshold = 0.0;
3040 iNode->locBackup = 0;
3041 iNode->checksum = 0;
3042 iNode->checksumBackup = 0;
3043}
3044
3045ItemNode* findItem(char* name) {
3046// char msg[70];
3047 ItemNode* current = 0;
3048
3049 if (name == 0) {
3050 return 0;
3051 }
3052 current = firstNode;
3053 while (current != 0) { // is end of list
3054 if (strcmp(name, current->item->name) == 0) {
3055 // success, give back itemNode
3056 return current;
3057 }
3058 current = current->next;
3059 }
3060// since two lists, which are searched seperately don't make log output in
3061// findItem()-function -> move to where called to combine with other
3062// findXYItem calls
3063/*
3064 if (state == RUNNING) {
3065 msg[sprintf(msg, "Item %s not found in list.", name)] = 0;
3066 createLogMessage(MSG_WARNING, msg, 0);
3067# ifdef __DEBUG
3068 printf("Item %s not found in list.\n", name);
3069 fflush(stdout);
3070# endif
3071 }
3072*/
3073 return 0;
3074}
3075
3076void unpublishItemList() {
3077 ItemNode* current = 0;
3078
3079 current = firstNode;
3080 while (current != 0) {
3081 dis_remove_service(current->id);
3082 current = current->next;
3083 }
3084 // pretending ItemList is completely empty to avoid access
3085 // to not existing elements
3086 nodesAmount = 0;
3087 firstNode = 0;
3088 lastNode = 0;
3089}
3090
3091// ****************************************************************************
3092// ------------------ here come all the closing and cleanup functions ---------
3093// ****************************************************************************
3094void interrupt_handler(int sig) {
3095// *** causes props on DCS board -> not used yet ***
3096# ifdef __DEBUG
3097 printf("Received interrupt: %d, exiting now.\n", sig);
3098 fflush(stdout);
3099# endif
3100
3101 if ((state == RUNNING) || (state == ERROR_STATE)) {
3102 fee_exit_handler(0);
3103 } else {
3104 cleanUp();
3105 exit(0);
3106 }
3107}
3108
3109void fee_exit_handler(unsigned int state) {
3110 char msg[70];
3111
3112# ifdef __DEBUG
3113 printf("Exit state: %d\n\n", state);
3114 fflush(stdout);
3115# endif
3116 msg[sprintf(msg, "Exiting FeeServer (exit state: %d).", state)] = 0;
3117 createLogMessage(MSG_INFO, msg, 0);
3118
3119 cleanUp();
3120 exit(state);
3121}
3122
3123void dim_dummy_exit_handler(int* bufp) {
3124 char msg[200];
3125 char clientName[50];
3126 int dummy = 0;
3127
3128 // if bufp null pointer, redirect to valid value
3129 if (bufp == 0) {
3130 bufp = &dummy;
3131 }
3132
3133 // DO almost nothing, just to disable the build-in exit command of the DIM framework
3134 // just notifying about intrusion, except for framework exit
3135 clientName[0] = 0;
3136 dis_get_client(clientName);
3137 // let's asume exit from ambitious user has clientName (pid@host).
3138 if (clientName[0] == 0) {
3139# ifdef __DEBUG
3140 printf("Framework tries to exit FeeServer (%d)\n", *bufp);
3141 printf("Most likely FeeServer name already exists.\n");
3142 fflush(stdout);
3143# endif
3144 // IMPORTANT don't use the bufp - state of framework, it could interfere
3145 // with own specified exit states !! (e.g. for restarting in case of "2")
3146 // the same state is signaled by kill all servers of dns !?
3147 fee_exit_handler(204);
3148 } else {
3149 msg[sprintf(msg, "Ambitious user (%s) tried to kill FeeServer, ignoring command!",
3150 clientName)] = 0;
3151 createLogMessage(MSG_WARNING, msg, 0);
3152# ifdef __DEBUG
3153 printf("Ambitious user (%s) tried to kill FeeServer (%d)\n", clientName, *bufp);
3154 fflush(stdout);
3155# endif
3156 }
3157}
3158
3159void cleanUp() {
3160 // the order of the clean up sequence here is important to evade seg faults
3161# ifdef __DEBUG
3162 printf("Cleaning up FeeServer before finishing:\n");
3163 fflush(stdout);
3164# endif
3165 if (ceInitState == CE_OK) {
3166 cleanUpCE();
3167# ifdef __DEBUG
3168 printf(" - Clean up of CE finished\n");
3169 fflush(stdout);
3170# endif
3171 }
3172
3173 if (monitorThreadStarted) {
3174 pthread_cancel(thread_mon);
3175 }
3176 if (intMonitorThreadStarted) {
3177 pthread_cancel(thread_mon_int);
3178 }
3179 if (state == RUNNING) {
3180 pthread_cancel(thread_init);
3181 }
3182 if (logWatchDogRunning) {
3183 pthread_cancel(thread_logWatchdog);
3184 }
3185# ifdef __DEBUG
3186 printf(" - All threads except for main thread killed\n");
3187 fflush(stdout);
3188# endif
3189
3190 dis_stop_serving();
3191# ifdef __DEBUG
3192 printf(" - DIM server stopped\n");
3193 fflush(stdout);
3194# endif
3195
3196 deleteItemList();
3197 // new since version 0.8.1 -> int channels
3198 deleteIntItemList();
3199 // new since version 0.8.2b -> char channels
3200 deleteCharItemList();
3201
3202 if (cmndACK != 0) {
3203 free(cmndACK);
3204 }
3205 if (serverName != 0) {
3206 free(serverName);
3207 }
3208
3209 // new since 0.8.3 -> memory list
3210 //cleanupMemoryList();
3211# ifdef __DEBUG
3212 printf(" - Memory freed (lists and globaly allocated)\n");
3213 fflush(stdout);
3214# endif
3215}
3216
3217int deleteItemList() {
3218 ItemNode* tmp = 0;
3219
3220 while (firstNode != 0) {
3221 if (firstNode->item != 0) {
3222 if (firstNode->item->name != 0) {
3223 free(firstNode->item->name);
3224 }
3225 free(firstNode->item);
3226 }
3227
3228 tmp = firstNode->next;
3229 free(firstNode);
3230 firstNode = tmp;
3231 }
3232 return FEE_OK;
3233}
3234
3235/*
3236MessageStruct copyMessage(const MessageStruct* const orgMsg) {
3237 MessageStruct msg;
3238 msg.eventType = orgMsg->eventType;
3239 memcpy(msg.detector, orgMsg->detector, MSG_DETECTOR_SIZE);
3240 memcpy(msg.source, orgMsg->source, MSG_SOURCE_SIZE);
3241 memcpy(msg.description, orgMsg->description, MSG_DESCRIPTION_SIZE);
3242 memcpy(msg.date, orgMsg->date, MSG_DATE_SIZE);
3243 return msg;
3244}
3245*/
3246
3247//// --------- NEW FEATURE SINCE VERSION 0.8.1 (2007-06-12) ---------- /////
3248
3249int publishInt(IntItem* intItem) {
3250 unsigned int id;
3251 char* serviceName = 0;
3252
3253 // check for right state
3254 if (state != COLLECTING) {
3255 return FEE_WRONG_STATE;
3256 }
3257
3258 // Testing for NULL - Pointer
3259 // !! Attention: if pointer is not initialized and also NOT set to NULL, this won't help !!
3260 if (intItem == 0) {
3261# ifdef __DEBUG
3262 printf("Bad intItem, not published\n");
3263 fflush(stdout);
3264# endif
3265 return FEE_NULLPOINTER;
3266 }
3267 if (intItem->name == 0 || intItem->location == 0) {
3268# ifdef __DEBUG
3269 printf("Bad intItem, not published\n");
3270 fflush(stdout);
3271# endif
3272 return FEE_NULLPOINTER;
3273 }
3274
3275 // Check name for duplicate here
3276 // Check in Float list
3277 if (findItem(intItem->name) != 0) {
3278# ifdef __DEBUG
3279 printf("Item name already published in float list, int item discarded.\n");
3280 fflush(stdout);
3281# endif
3282 return FEE_ITEM_NAME_EXISTS;
3283 }
3284 // Check in INT list
3285 if (findIntItem(intItem->name) != 0) {
3286# ifdef __DEBUG
3287 printf("Item name already published in int list, new int item discarded.\n");
3288 fflush(stdout);
3289# endif
3290 return FEE_ITEM_NAME_EXISTS;
3291 }
3292 // Check in Char service list
3293 if (findCharItem(intItem->name) != 0) {
3294# ifdef __DEBUG
3295 printf("Item name already published in char list, int item discarded.\n");
3296 fflush(stdout);
3297# endif
3298 return FEE_ITEM_NAME_EXISTS;
3299 }
3300
3301
3302 // -- add intItem as service --
3303 serviceName = (char*) malloc(serverNameLength + strlen(intItem->name) + 2);
3304 if (serviceName == 0) {
3305 return FEE_INSUFFICIENT_MEMORY;
3306 }
3307 // terminate string with '\0'
3308 serviceName[sprintf(serviceName, "%s_%s", serverName, intItem->name)] = 0;
3309 id = dis_add_service(serviceName, "I", (int*) intItem->location,
3310 sizeof(int), 0, 0);
3311 free(serviceName);
3312 add_int_item_node(id, intItem);
3313
3314 return FEE_OK;
3315}
3316
3317void add_int_item_node(unsigned int _id, IntItem* _int_item) {
3318 //create new node with enough memory
3319 IntItemNode* newNode = 0;
3320
3321 newNode = (IntItemNode*) malloc(sizeof(IntItemNode));
3322 if (newNode == 0) {
3323 //no memory available!
3324# ifdef __DEBUG
3325 printf("no memory available while adding IntItemNode!\n");
3326 fflush(stdout);
3327# endif
3328 cleanUp();
3329 exit(201);
3330 }
3331 //initialize "members" of node
3332 newNode->prev = 0;
3333 newNode->next = 0;
3334 newNode->id = _id;
3335 newNode->intItem = _int_item;
3336 newNode->lastTransmittedIntValue = *(_int_item->location);
3337 //if default deadband is negative -> set threshold 0, otherwise set half of defaultDeadband
3338 newNode->threshold = (_int_item->defaultDeadband < 0) ? 0.0 : (_int_item->defaultDeadband / 2);
3339
3340 newNode->locBackup = _int_item->location;
3341
3342 // Check if these feature have to be ported as well ??? !!!
3343// newNode->checksum = calculateChecksum((unsigned char*) &(_item->location),
3344// sizeof(volatile float*));
3345// newNode->checksumBackup = newNode->checksum;
3346
3347#ifdef __DEBUG
3348 // complete debug display of added IntItem
3349/*
3350 printf("IntItem: %d\n", _id);
3351 printf("location: %f, locBackup %f\n", *(_int_item->location), *(newNode->locBackup));
3352 printf("location addr: %p, locBackup addr %p\n", _int_item->location, newNode->locBackup);
3353 printf("checksum1: %d, checksum2: %d\n\n", newNode->checksum,
3354 newNode->checksumBackup);
3355*/
3356#endif
3357
3358# ifdef __DEBUG
3359 // short debug display of added Item
3360 printf("init of %s (int) with ID %d: %d\n", newNode->intItem->name,
3361 newNode->id, newNode->lastTransmittedIntValue);
3362 fflush(stdout);
3363# endif
3364
3365 ++intNodesAmount;
3366 //redirect pointers of doubly linked list (int)
3367 if (firstIntNode != 0) {
3368 lastIntNode->next = newNode;
3369 newNode->prev = lastIntNode;
3370 lastIntNode = newNode;
3371 } else {
3372 firstIntNode = newNode;
3373 lastIntNode = newNode;
3374 }
3375}
3376
3377
3378IntItemNode* findIntItem(char* name) {
3379// char msg[70];
3380 IntItemNode* current = 0;
3381
3382 if (name == 0) {
3383 return 0;
3384 }
3385 current = firstIntNode;
3386 while (current != 0) { // is end of list
3387 if (strcmp(name, current->intItem->name) == 0) {
3388 // success, give back IntItemNode
3389 return current;
3390 }
3391 current = current->next;
3392 }
3393// since two lists, which are searched seperately don't make log output in
3394// findIntItem()-function -> move to where called to combine with other
3395// findXYItem calls
3396/*
3397 if (state == RUNNING) {
3398 msg[sprintf(msg, "Item %s not found in IntItem list.", name)] = 0;
3399 createLogMessage(MSG_WARNING, msg, 0);
3400# ifdef __DEBUG
3401 printf("Item %s not found in IntItem list.\n", name);
3402 fflush(stdout);
3403# endif
3404 }
3405*/
3406 return 0;
3407}
3408
3409int deleteIntItemList() {
3410 IntItemNode* tmp = 0;
3411
3412 while (firstIntNode != 0) {
3413 if (firstIntNode->intItem != 0) {
3414 if (firstIntNode->intItem->name != 0) {
3415 free(firstIntNode->intItem->name);
3416 }
3417 free(firstIntNode->intItem);
3418 }
3419
3420 tmp = firstIntNode->next;
3421 free(firstIntNode);
3422 firstIntNode = tmp;
3423 }
3424 return FEE_OK;
3425}
3426
3427void initIntItemNode(IntItemNode* intItemNode) {
3428 intItemNode->prev = 0;
3429 intItemNode->next = 0;
3430 intItemNode->id = 0;
3431 intItemNode->intItem = 0;
3432 intItemNode->lastTransmittedIntValue = 0;
3433 intItemNode->threshold = 0.0;
3434 intItemNode->locBackup = 0;
3435 intItemNode->checksum = 0;
3436 intItemNode->checksumBackup = 0;
3437}
3438
3439void unpublishIntItemList() {
3440 IntItemNode* current = 0;
3441
3442 current = firstIntNode;
3443 while (current != 0) {
3444 dis_remove_service(current->id);
3445 current = current->next;
3446 }
3447 // pretending ItemList is completely empty to avoid access
3448 // to not existing elements
3449 intNodesAmount = 0;
3450 firstIntNode = 0;
3451 lastIntNode = 0;
3452}
3453
3454Item* createItem() {
3455 Item* item = 0;
3456
3457 item = (Item*) malloc(sizeof(Item));
3458 if (item == 0) {
3459 //no memory available!
3460# ifdef __DEBUG
3461 printf("no memory available!\n");
3462# endif
3463 return 0;
3464 }
3465 item->location = 0;
3466 item->name = 0;
3467 item->defaultDeadband = 0;
3468 return item;
3469}
3470
3471IntItem* createIntItem() {
3472 IntItem* intItem = 0;
3473
3474 intItem = (IntItem*) malloc(sizeof(IntItem));
3475 if (intItem == 0) {
3476 //no memory available!
3477# ifdef __DEBUG
3478 printf("no memory available!\n");
3479# endif
3480 return 0;
3481 }
3482 intItem->location = 0;
3483 intItem->name = 0;
3484 intItem->defaultDeadband = 0;
3485 return intItem;
3486}
3487
3488Item* fillItem(float* floatLocation, char* itemName, float defDeadband) {
3489 Item* item = 0;
3490
3491 item = createItem();
3492 if (item == 0) {
3493 //no memory available!
3494# ifdef __DEBUG
3495 printf("no memory available!\n");
3496# endif
3497 return 0;
3498 }
3499 item->location = floatLocation;
3500 item->name = (char*) malloc(strlen(itemName) + 1);
3501 if (item->name == 0) {
3502 //no memory available!
3503# ifdef __DEBUG
3504 printf("no memory available!\n");
3505# endif
3506 free(item);
3507 return 0;
3508 }
3509 strcpy(item->name, itemName);
3510 item->defaultDeadband = defDeadband;
3511 return item;
3512}
3513
3514IntItem* fillIntItem(int* intLocation, char* itemName, int defDeadband) {
3515 IntItem* intItem = 0;
3516
3517 intItem = createIntItem();
3518 if (intItem == 0) {
3519 //no memory available!
3520# ifdef __DEBUG
3521 printf("no memory available!\n");
3522# endif
3523 return 0;
3524 }
3525 intItem->location = intLocation;
3526 intItem->name = (char*) malloc(strlen(itemName) + 1);
3527 if (intItem->name == 0) {
3528 //no memory available!
3529# ifdef __DEBUG
3530 printf("no memory available!\n");
3531# endif
3532 free(intItem);
3533 return 0;
3534 }
3535 strcpy(intItem->name, itemName);
3536 intItem->defaultDeadband = defDeadband;
3537 return intItem;
3538}
3539
3540void monitorIntValues() {
3541 int status = -1;
3542 int nRet;
3543 unsigned long sleepTime = 0;
3544 IntItemNode* current = 0;
3545 char msg[120];
3546 unsigned long innerCounter = 0; // used for update check after time interval
3547 unsigned long outerCounter = 0; // used for update check after time interval
3548
3549 // set flag, that monitor thread has been started
3550 intMonitorThreadStarted = true;
3551
3552 // set cancelation type
3553 status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
3554 if (status != 0) {
3555# ifdef __DEBUG
3556 printf("Set cancel state error [mon - int]: %d\n", status);
3557 fflush(stdout);
3558# endif
3559 createLogMessage(MSG_WARNING,
3560 "Unable to configure monitor thread (int) properly. Monitoring is not affected.", 0);
3561 }
3562 status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
3563 if (status != 0) {
3564# ifdef __DEBUG
3565 printf("Set cancel type error [mon - int]: %d\n", status);
3566 fflush(stdout);
3567# endif
3568 createLogMessage(MSG_WARNING,
3569 "Unable to configure monitor thread (int) properly. Monitoring is not affected.", 0);
3570 }
3571
3572 createLogMessage(MSG_DEBUG, "Started monitor thread for INT values successfully.", 0);
3573
3574 while (1) {
3575 current = firstIntNode;
3576 sleepTime = (unsigned long) (updateRate / intNodesAmount);
3577 while (current != 0) { // is lastIntNode->next (end of list)
3578 if (!checkIntLocation(current)) {
3579 msg[sprintf(msg, "Value of item %s (int) is corrupt, reconstruction failed. Ignoring!",
3580 current->intItem->name)] = 0;
3581 createLogMessage(MSG_ERROR, msg, 0);
3582 // message and do some stuff (like invalidate value)
3583 // (test, what happens if pointer is redirected ???)
3584 } else {
3585 if ((abs((*(current->intItem->location)) - current->lastTransmittedIntValue)
3586 >= current->threshold) || (outerCounter ==
3587 (innerCounter * TIME_INTERVAL_MULTIPLIER))) {
3588 nRet = dis_update_service(current->id);
3589 current->lastTransmittedIntValue = *(current->intItem->location);
3590# ifdef __DEBUG
3591 printf("CE triggered an updated on %d clients for service %s [int]: %d\n",
3592 nRet, current->intItem->name, *(current->intItem->location));
3593 fflush(stdout);
3594# endif
3595 }
3596 }
3597
3598 ++innerCounter;
3599 current = current->next;
3600 usleep(sleepTime * 1000);
3601 // sleeps xy microseconds, needed milliseconds-> "* 1000"
3602 }
3603 // with the check of both counter, each service is at least updated after
3604 // every (deadband updateRate * nodesAmount) seconds
3605 innerCounter = 0;
3606 ++outerCounter;
3607 // after every service in list is updated set counter back to 0
3608 // the TIME_INTERVAL_MULTIPLIER is used to enlarge the time interval of
3609 // the request of services without touching the deadband checker updateRate
3610 if (outerCounter >= (intNodesAmount * TIME_INTERVAL_MULTIPLIER)) {
3611 outerCounter = 0;
3612 }
3613 }
3614 // should never be reached !
3615 pthread_exit(0);
3616}
3617
3618// checks against bitflips in location (integer Item)
3619bool checkIntLocation(IntItemNode* node) {
3620 if (node->intItem->location == node->locBackup) {
3621 // locations are identical, so no bitflip
3622 return true;
3623 }
3624 // locations are not identical, check further
3625
3626 if (node->checksum == calculateChecksum((unsigned char*)
3627 &(node->intItem->location), sizeof(volatile int*))) {
3628 // checksum tells, that first location should be valid, repair backup
3629 node->locBackup = node->intItem->location;
3630 return true;
3631 }
3632 // original location or first checksum is wrong, continue checking
3633
3634 if (node->checksum == calculateChecksum((unsigned char*)
3635 &(node->locBackup), sizeof(volatile int*))) {
3636 // checksum tells, that location backup should be valid, repair original
3637 node->intItem->location = node->locBackup;
3638 return true;
3639 }
3640 // location backup or first checksum is wrong, continue checking
3641
3642 if (node->checksum == node->checksumBackup) {
3643 // it seems that location and location backup are wrong
3644 // or checksum value runs banana, not repairable
3645 return false;
3646 }
3647 // it seems that first checksum is wrong
3648 // try to fix with second checksum
3649
3650 if (node->checksumBackup == calculateChecksum((unsigned char*)
3651 &(node->intItem->location), sizeof(volatile int*))) {
3652 // checksum backup tells, that first location should be valid, repair backup
3653 node->locBackup = node->intItem->location;
3654 // repair first checksum
3655 node->checksum = node->checksumBackup;
3656 return true;
3657 }
3658 // original location or second checksum is wrong, continue checking
3659
3660 if (node->checksumBackup == calculateChecksum((unsigned char*)
3661 &(node->locBackup), sizeof(volatile int*))) {
3662 // checksum backup tells, that location backup should be valid, repair original
3663 node->intItem->location = node->locBackup;
3664 // repair checksum
3665 node->checksum = node->checksumBackup;
3666 return true;
3667 }
3668 // value is totally banana, no chance to fix
3669 return false;
3670}
3671
3672// --- Wrapper for the Float Items --- //
3673
3674int publishFloat(FloatItem* floatItem) {
3675 return publish(floatItem);
3676}
3677
3678
3679FloatItem* createFloatItem() {
3680 return createItem();
3681}
3682
3683
3684FloatItem* fillFloatItem(float* floatLocation, char* itemName, float defDeadband) {
3685 return fillItem(floatLocation, itemName, defDeadband);
3686}
3687
3688
3689//// ------------- NEW Memory Management (2007-07-25) ----------------- ////
3690
3691MemoryNode* findMemoryNode(void* addr) {
3692 MemoryNode* current = 0;
3693
3694 if (addr == 0) {
3695 /*
3696 createLogMessage(MSG_WARNING,
3697 "Reqesting MemoryNode with ID \"NULL\", discarding call!", 0);
3698# ifdef __DEBUG
3699 printf("Reqesting MemoryNode with ID \"NULL\", discarding call!\n");
3700 fflush(stdout);
3701# endif
3702 */
3703 return 0;
3704 }
3705
3706 current = firstMemoryNode;
3707 while (current != 0) { // is end of list
3708 if (current->identityAddr == addr) {
3709 // success, give back MemoryNode
3710 return current;
3711 }
3712 current = current->next;
3713 }
3714
3715/* // only used for debug output; comment it in if required
3716 if (current == 0) {
3717 char msg[80];
3718 msg[sprintf(msg, "Unable to find MemoryNode with ID \"%p\".",
3719 addr)] = 0;
3720 createLogMessage(MSG_DEBUG, msg, 0);
3721# ifdef __DEBUG
3722 printf("Unable to find MemoryNode with ID \"%p\".\n", addr);
3723 fflush(stdout);
3724# endif
3725 }
3726*/
3727
3728 return 0;
3729}
3730
3731
3732MemoryNode* createMemoryNode(unsigned int size, char type, char* module,
3733 unsigned int preSize) {
3734
3735 // check, if size is greater then preSize
3736 if (size <= preSize) {
3737 createLogMessage(MSG_ERROR,
3738 "Error: asking for memory smaller or equal than its prefix size.",
3739 0);
3740# ifdef __DEBUG
3741 printf("Error: asking for memory smaller or equal than its prefix size.\n");
3742 fflush(stdout);
3743# endif
3744 return 0;
3745 }
3746
3747 MemoryNode* memNode = (MemoryNode*) malloc(sizeof(MemoryNode));
3748 if (memNode == 0) {
3749 // insufficient memory
3750 createLogMessage(MSG_ERROR,
3751 "Insufficient memory! Unable to allocate memory for MemoryNode.",
3752 0);
3753# ifdef __DEBUG
3754 printf("Insufficient memory! Unable to allocate memory for MemoryNode.\n");
3755 fflush(stdout);
3756# endif
3757 }
3758
3759 // fill MemoryNode
3760 void* ptr = (void*) malloc(size);
3761 if (ptr == 0) {
3762 // insufficient memory
3763 char msg[100];
3764 msg[sprintf(msg,
3765 "Insufficient memory! Unable to allocate memory block of %d .",
3766 size)] = 0;
3767 createLogMessage(MSG_ERROR, msg, 0);
3768# ifdef __DEBUG
3769 printf("Insufficient memory! Unable to allocate memory block of %d .\n",
3770 size);
3771 fflush(stdout);
3772# endif
3773
3774 free(memNode);
3775 return 0;
3776 }
3777
3778 memNode->ptr = ptr;
3779 memNode->identityAddr = ptr + preSize;
3780 memNode->mmData.memSize = size;
3781 memNode->mmData.memType = type;
3782 if (module != 0) {
3783 strncpy(memNode->mmData.memDest, module, 30);
3784 memNode->mmData.memDest[29] = 0;
3785 } else {
3786 memNode->mmData.memDest[0] = 0;
3787 }
3788 if (preSize > 0) {
3789 memNode->mmData.prefixed = true;
3790 } else {
3791 memNode->mmData.prefixed = false;
3792 }
3793 memNode->mmData.prefixSize = preSize;
3794
3795 // add Node to list (add at end)
3796 memNode->prev = lastMemoryNode;
3797 memNode->next = 0;
3798
3799 if (lastMemoryNode != 0) {
3800 lastMemoryNode->next = memNode;
3801 }
3802 lastMemoryNode = memNode;
3803
3804 if (firstMemoryNode == 0) {
3805 firstMemoryNode = memNode;
3806 }
3807
3808 return memNode;
3809}
3810
3811
3812void freeMemoryNode(MemoryNode* node) {
3813 if (node == 0) {
3814 return;
3815 }
3816
3817 // free memory corresponding to this node
3818 if (node->ptr != 0) {
3819 free(node->ptr);
3820 }
3821
3822 // redirect links in doubly linked list
3823 if (node->next != 0) {
3824 node->next->prev = node->prev;
3825 } else {
3826 lastMemoryNode = node->prev;
3827 }
3828
3829 if (node->prev != 0) {
3830 node->prev->next = node->next;
3831 } else {
3832 firstMemoryNode = node->next;
3833 }
3834
3835 //free node itself
3836 free(node);
3837}
3838
3839
3840void cleanupMemoryList() {
3841 MemoryNode* current = firstMemoryNode;
3842 while (current != 0) {
3843 MemoryNode* nextMemNode = current->next;
3844 freeMemoryNode(current);
3845 current = nextMemNode;
3846 }
3847}
3848
3849
3850// ------ NEW interface functions for memory management ------ //
3851
3852int allocateMemory(unsigned int size, char type, char* module,
3853 char prefixPurpose, void** ptr) {
3854 MemoryNode* memNode = 0;
3855 unsigned int realSize = 0;
3856 unsigned int addSize = 0;
3857 char msg[200];
3858 *ptr = 0;
3859
3860 if (size == 0) {
3861 createLogMessage(MSG_WARNING,
3862 "FeeServer shall allocate memory of size 0; discarding call!", 0);
3863# ifdef __DEBUG
3864 printf("FeeServer shall allocate memory of size 0; discarding call!\n");
3865 fflush(stdout);
3866# endif
3867 return FEE_INVALID_PARAM;
3868 }
3869
3870 switch (prefixPurpose) {
3871 case ('0'):
3872 realSize = size;
3873 break;
3874
3875 case ('A'):
3876 realSize = size + HEADER_SIZE;
3877 addSize = HEADER_SIZE;
3878 break;
3879
3880 default:
3881 msg[sprintf(msg,
3882 "Received allocateMemory call with unknown prefix purpose ('%c'), discarding call.",
3883 prefixPurpose)] = 0;
3884 createLogMessage(MSG_ERROR, msg, 0);
3885# ifdef __DEBUG
3886 printf("%s\n", msg);
3887 fflush(stdout);
3888# endif
3889 return FEE_INVALID_PARAM;
3890 }
3891
3892 memNode = createMemoryNode(realSize, type, module, addSize);
3893 if (memNode == 0) {
3894 return FEE_FAILED;
3895 }
3896
3897 *ptr = memNode->identityAddr;
3898/* // only for debug output to test functyionality
3899 msg[sprintf(msg,
3900 "Allocated memory (type %c) for %s of size %d + prefix memory size %d. Purpose is set to: %c.",
3901 type, memNode->mmData.memDest, size, addSize, prefixPurpose)] = 0;
3902 createLogMessage(MSG_DEBUG, msg, 0);
3903# ifdef __DEBUG
3904 printf("%s\n", msg);
3905 fflush(stdout);
3906# endif
3907*/
3908 return FEE_OK;
3909}
3910
3911
3912int freeMemory(void* addr) {
3913 MemoryNode* memNode = 0;
3914 if (addr == 0) {
3915 // received NULL pointer
3916 createLogMessage(MSG_WARNING,
3917 "Received an NULL pointer for freeing memory, discarding call!", 0);
3918# ifdef __DEBUG
3919 printf("Received an NULL pointer for freeing memory, discarding call! \n");
3920 fflush(stdout);
3921# endif
3922 return FEE_NULLPOINTER;
3923 }
3924
3925 memNode = findMemoryNode(addr);
3926 if (memNode == 0) {
3927 // memory pointer id not found in list
3928 return FEE_INVALID_PARAM;
3929 }
3930
3931 freeMemoryNode(memNode);
3932 return FEE_OK;
3933}
3934
3935
3936/// --- NEW FEATURE SINCE VERSION 0.8.2b [Char channel] (2007-07-28) --- ///
3937
3938int publishChar(CharItem* charItem) {
3939 unsigned int id;
3940 char* serviceName = 0;
3941
3942 // check for right state
3943 if (state != COLLECTING) {
3944 return FEE_WRONG_STATE;
3945 }
3946
3947 // Testing for NULL - Pointer
3948 // !! Attention: if pointer is not initialized and also NOT set to NULL, this won't help !!
3949 if (charItem == 0) {
3950# ifdef __DEBUG
3951 printf("Bad charItem, not published\n");
3952 fflush(stdout);
3953# endif
3954 return FEE_NULLPOINTER;
3955 }
3956 if (charItem->name == 0 || charItem->user_routine == 0) {
3957# ifdef __DEBUG
3958 printf("Bad charItem, not published\n");
3959 fflush(stdout);
3960# endif
3961 return FEE_NULLPOINTER;
3962 }
3963
3964 // Check name for duplicate here
3965 // Check in Float list
3966 if (findItem(charItem->name) != 0) {
3967# ifdef __DEBUG
3968 printf("Item name already published in float list, char item discarded.\n");
3969 fflush(stdout);
3970# endif
3971 return FEE_ITEM_NAME_EXISTS;
3972 }
3973 // Check in INT list
3974 if (findIntItem(charItem->name) != 0) {
3975# ifdef __DEBUG
3976 printf("Item name already published in int list, char item discarded.\n");
3977 fflush(stdout);
3978# endif
3979 return FEE_ITEM_NAME_EXISTS;
3980 }
3981 // Check in CHAR list
3982 if (findCharItem(charItem->name) != 0) {
3983# ifdef __DEBUG
3984 printf("Item name already published in char list, new char item discarded.\n");
3985 fflush(stdout);
3986# endif
3987 return FEE_ITEM_NAME_EXISTS;
3988 }
3989
3990 // -- add charItem as service --
3991 serviceName = (char*) malloc(serverNameLength + strlen(charItem->name) + 2);
3992 if (serviceName == 0) {
3993 return FEE_INSUFFICIENT_MEMORY;
3994 }
3995 // terminate string with '\0'
3996 serviceName[sprintf(serviceName, "%s_%s", serverName, charItem->name)] = 0;
3997 // add service in DIM
3998 id = dis_add_service(serviceName, "C", 0, 0, charItem->user_routine,
3999 charItem->tag);
4000 free(serviceName);
4001
4002 // !!! implement add_char_item_node() func !!!
4003 add_char_item_node(id, charItem);
4004
4005 return FEE_OK;
4006}
4007
4008
4009CharItem* createCharItem() {
4010 CharItem* charItem = 0;
4011
4012 charItem = (CharItem*) malloc(sizeof(CharItem));
4013 if (charItem == 0) {
4014 //no memory available!
4015# ifdef __DEBUG
4016 printf("no memory available for CharItem!\n");
4017# endif
4018 return 0;
4019 }
4020 charItem->user_routine = 0;
4021 charItem->name = 0;
4022 charItem->tag = 0;
4023 return charItem;
4024}
4025
4026
4027//CharItem* fillCharItem(void* funcPointer, char* itemName, long tag) {
4028CharItem* fillCharItem(void (*funcPointer)(long*, int**, int*), char* itemName,
4029 long tag) {
4030 CharItem* charItem = 0;
4031
4032 charItem = createCharItem();
4033 if (charItem == 0) {
4034 //no memory available!
4035# ifdef __DEBUG
4036 printf("no memory available for CharItem!\n");
4037# endif
4038 return 0;
4039 }
4040 charItem->user_routine = funcPointer;
4041 charItem->name = (char*) malloc(strlen(itemName) + 1);
4042 if (charItem->name == 0) {
4043 //no memory available!
4044# ifdef __DEBUG
4045 printf("no memory available!\n");
4046# endif
4047 free(charItem);
4048 return 0;
4049 }
4050 strcpy(charItem->name, itemName);
4051 charItem->tag = tag;
4052 return charItem;
4053}
4054
4055
4056void add_char_item_node(unsigned int _id, CharItem* _char_item) {
4057 //create new node with enough memory
4058 CharItemNode* newNode = 0;
4059
4060 newNode = (CharItemNode*) malloc(sizeof(CharItemNode));
4061 if (newNode == 0) {
4062 //no memory available!
4063# ifdef __DEBUG
4064 printf("no memory available while adding CharItemNode!\n");
4065 fflush(stdout);
4066# endif
4067 cleanUp();
4068 exit(201);
4069 }
4070 //initialize "members" of node
4071 newNode->prev = 0;
4072 newNode->next = 0;
4073 newNode->id = _id;
4074 newNode->charItem = _char_item;
4075
4076# ifdef __DEBUG
4077 // complete debug display of added charItem
4078/*
4079 printf("CharItem ID: %d\n", _id);
4080 printf("CharItem name: %s\n", _char_item->name);
4081 printf("CharItem user_routine: %p\n", _char_item->user_routine);
4082 printf("CharItem tag: %d\n", _char_item->tag);
4083*/
4084# endif
4085
4086# ifdef __DEBUG
4087 // short debug display of added Item
4088 printf("init of %s (char) with ID %d; user_routine at: %p\n",
4089 newNode->charItem->name, newNode->id,
4090 newNode->charItem->user_routine);
4091 fflush(stdout);
4092# endif
4093
4094 ++charNodesAmount;
4095 //redirect pointers of doubly linked list (char)
4096 if (firstCharNode != 0) {
4097 lastCharNode->next = newNode;
4098 newNode->prev = lastCharNode;
4099 lastCharNode = newNode;
4100 } else {
4101 firstCharNode = newNode;
4102 lastCharNode = newNode;
4103 }
4104}
4105
4106
4107CharItemNode* findCharItem(char* name) {
4108// char msg[70];
4109 CharItemNode* current = 0;
4110
4111 if (name == 0) {
4112 return 0;
4113 }
4114 current = firstCharNode;
4115 while (current != 0) { // is end of list
4116 if (strcmp(name, current->charItem->name) == 0) {
4117 // success, give back CharItemNode
4118 return current;
4119 }
4120 current = current->next;
4121 }
4122// since three lists, which are searched seperately don't make log output in
4123// findCharItem()-function -> move to where called to combine with other
4124// findXYItem calls
4125/*
4126 if (state == RUNNING) {
4127 msg[sprintf(msg, "Item %s not found in CharItem list.", name)] = 0;
4128 createLogMessage(MSG_WARNING, msg, 0);
4129# ifdef __DEBUG
4130 printf("Item %s not found in CharItem list.\n", name);
4131 fflush(stdout);
4132# endif
4133 }
4134*/
4135 return 0;
4136}
4137
4138
4139int deleteCharItemList() {
4140 CharItemNode* tmp = 0;
4141
4142 while (firstCharNode != 0) {
4143 if (firstCharNode->charItem != 0) {
4144 if (firstCharNode->charItem->name != 0) {
4145 free(firstCharNode->charItem->name);
4146 }
4147 free(firstCharNode->charItem);
4148 }
4149
4150 tmp = firstCharNode->next;
4151 free(firstCharNode);
4152 firstCharNode = tmp;
4153 }
4154 return FEE_OK;
4155}
4156
4157
4158void initCharItemNode(CharItemNode* charItemNode) {
4159 charItemNode->prev = 0;
4160 charItemNode->next = 0;
4161 charItemNode->id = 0;
4162 charItemNode->charItem = 0;
4163}
4164
4165
4166void unpublishCharItemList() {
4167 CharItemNode* current = 0;
4168
4169 current = firstCharNode;
4170 while (current != 0) {
4171 dis_remove_service(current->id);
4172 current = current->next;
4173 }
4174 // pretending CharItemList is completely empty to avoid access
4175 // to not existing DIM services. Don't delete charItems, CE might still
4176 // try to access their content (same for float and int lists)
4177 charNodesAmount = 0;
4178 firstCharNode = 0;
4179 lastCharNode = 0;
4180}
4181
4182
4183/// -- NEW FEATURE V. 0.9.1 [Set FeeServer Properies in CE] (2007-08-17) -- ///
4184
4185bool setFeeProperty(FeeProperty* prop) {
4186 bool retVal = false;
4187 if (state != INITIALIZING) {
4188 createLogMessage(MSG_WARNING,
4189 "Trying to change a FeeProperty during wrong FeeServer state, ignoring ...",
4190 0);
4191# ifdef __DEBUG
4192 printf("Trying to change a FeeProperty during wrong FeeServer state, ignoring ...\n");
4193 fflush(stdout);
4194# endif
4195 return retVal;
4196 }
4197
4198 if (prop == 0) {
4199# ifdef __DEBUG
4200 printf("Received NULL pointer in setting FeeProperty, ignoring...\n");
4201 fflush(stdout);
4202# endif
4203 // No log message: in "INITIALIZING" state are no DIM channels available
4204 return retVal;
4205 }
4206
4207 switch (prop->flag) {
4208 case (PROPERTY_UPDATE_RATE):
4209 if (prop->uShortVal > 0) {
4210 updateRate = prop->uShortVal;
4211 retVal = true;
4212# ifdef __DEBUG
4213 printf("FeeProperty changed: new update rate (%d).\n",
4214 updateRate);
4215 fflush(stdout);
4216# endif
4217 } else {
4218# ifdef __DEBUG
4219 printf("Received invalid value for setting update rate (%d), ignoring...\n",
4220 prop->uShortVal);
4221 fflush(stdout);
4222# endif
4223 }
4224 break;
4225
4226 case (PROPERTY_LOGWATCHDOG_TIMEOUT):
4227 if (prop->uIntVal > 0) {
4228 logWatchDogTimeout = prop->uIntVal;
4229 retVal = true;
4230# ifdef __DEBUG
4231 printf("FeeProperty changed: new log watchdog timeout (%d).\n",
4232 logWatchDogTimeout);
4233 fflush(stdout);
4234# endif
4235 } else {
4236# ifdef __DEBUG
4237 printf("Received invalid value for setting log watchdog timeout (%d), ignoring...\n",
4238 prop->uIntVal);
4239 fflush(stdout);
4240# endif
4241 }
4242 break;
4243
4244 case (PROPERTY_ISSUE_TIMEOUT):
4245 if (prop->uLongVal > 0) {
4246 issueTimeout = prop->uLongVal;
4247 retVal = true;
4248# ifdef __DEBUG
4249 printf("FeeProperty changed: new issue timeout (%ld).\n",
4250 issueTimeout);
4251 fflush(stdout);
4252# endif
4253 } else {
4254# ifdef __DEBUG
4255 printf("Received invalid value for setting issue timeout (%ld), ignoring...\n",
4256 prop->uLongVal);
4257 fflush(stdout);
4258# endif
4259 }
4260 break;
4261
4262 case (PROPERTY_LOGLEVEL):
4263 if ((prop->uIntVal > 0) && (prop->uIntVal <= MSG_MAX_VAL)) {
4264 logLevel = prop->uIntVal | MSG_ALARM;
4265 retVal = true;
4266# ifdef __DEBUG
4267 printf("FeeProperty changed: new log level (%d).\n", logLevel);
4268 fflush(stdout);
4269# endif
4270 } else {
4271# ifdef __DEBUG
4272 printf("Received invalid value for setting loglevel (%d), ignoring...\n",
4273 prop->uIntVal);
4274 fflush(stdout);
4275# endif
4276 }
4277 break;
4278
4279 default:
4280 // unknown property flag, but no logging
4281# ifdef __DEBUG
4282 printf("Received unknown flag in setting FeeProperty (%d), ignoring...\n",
4283 prop->flag);
4284 fflush(stdout);
4285# endif
4286 }
4287
4288 return retVal;
4289}
4290
4291
4292/// ***************************************************************************
4293/// -- only for the benchmarking cases necessary
4294/// ***************************************************************************
4295#ifdef __BENCHMARK
4296void createBenchmark(char* msg) {
4297 // this part is only used for benchmarking
4298 // timestamp to benchmark reception of a command
4299 struct tm *today;
4300 struct timeval tStamp;
4301 char benchmark_msg[200];
4302 int status = 0;
4303 FILE* pFile = 0;
4304
4305 status = gettimeofday(&tStamp, 0);
4306 if (status != 0) {
4307 benchmark_msg[sprintf(benchmark_msg,
4308 "Unable to get timestamp for benchmark!")] = 0;
4309 } else {
4310 today = localtime(&(tStamp.tv_sec));
4311 benchmark_msg[sprintf(benchmark_msg,
4312 "%s: \t%.8s - %ld us", msg, asctime(today) + 11,
4313 tStamp.tv_usec)] = 0;
4314 }
4315
4316 if (getenv("FEE_BENCHMARK_FILENAME")) {
4317 pFile = fopen(getenv("FEE_BENCHMARK_FILENAME"), "a+");
4318 if (pFile) {
4319 fprintf(pFile, benchmark_msg);
4320 fprintf(pFile, "\n");
4321 fclose(pFile);
4322 } else {
4323#ifdef __DEBUG
4324 printf("Unable to open benchmark file.\n");
4325 printf("%s\n", benchmark_msg);
4326#endif
4327 createLogMessage(MSG_WARNING, "Unable to write to benchmarkfile.", 0);
4328 }
4329 } else {
4330 createLogMessage(MSG_SUCCESS_AUDIT, benchmark_msg, 0);
4331 }
4332}
4333#else
4334// empty function
4335void createBenchmark(char* msg) {
4336}
4337#endif
4338
4339
4340
4341/// ***************************************************************************
4342/// -- only for the debugging cases necessary
4343/// ***************************************************************************
4344#ifdef __DEBUG
4345void printData(char* data, int start, int size) {
4346 int i;
4347 int iBackUp;
4348
4349 if ((data == 0) || (size == 0)) {
4350 return;
4351 }
4352 iBackUp = start;
4353 for (i = start; (i < size) || (iBackUp < size); ++i) {
4354 ++iBackUp;
4355 printf("%c", data[i]);
4356 }
4357 printf("\nData - Size: %d", size);
4358 printf("\n\n");
4359 fflush(stdout);
4360}
4361#endif
4362
4363
4364//-- only for the testcases necessary
4365#ifdef __UTEST
4366const int getState() {
4367 return state;
4368}
4369
4370const ItemNode* getFirstNode() {
4371 return firstNode;
4372}
4373
4374const ItemNode* getLastNode() {
4375 return lastNode;
4376}
4377
4378int listSize() {
4379 ItemNode* tmp = firstNode;
4380 int count = 0;
4381
4382 while (tmp != 0) {
4383 tmp = tmp->next;
4384 ++count;
4385 }
4386 return count;
4387}
4388
4389const char* getCmndACK() {
4390 return cmndACK;
4391}
4392
4393void setState(int newState) {
4394 state = newState;
4395}
4396
4397void setCmndACK(char* newData) {
4398 cmndACK = newData;
4399}
4400
4401void setCmndACKSize(int size) {
4402 cmndACKSize = size;
4403}
4404
4405void setServerName(char* name) {
4406 if (serverName != 0) {
4407 free(serverName);
4408 }
4409 serverName = (char*) malloc(strlen(name) + 1);
4410 if (serverName == 0) {
4411 printf(" No memory available !\n");
4412 }
4413 strcpy(serverName, name);
4414}
4415
4416void clearServerName() {
4417 if (serverName != 0) {
4418 free(serverName);
4419 }
4420}
4421
4422void stopServer() {
4423 dis_remove_service(serviceACKID);
4424 dis_remove_service(commandID);
4425 dis_stop_serving();
4426}
4427
4428pthread_cond_t* getInitCondPtr() {
4429 return &init_cond;
4430}
4431
4432
4433pthread_mutex_t* getWaitInitMutPtr() {
4434 return &wait_init_mut;
4435}
4436
4437#endif
4438
4439
4440
4441--------------------------------------------------------------------------------
4442for assistance refer to the CVS howto. Maintained by Matthias Richter Powered by
4443ViewCVS 0.9.2
Note: See TracBrowser for help on using the repository browser.