Code

Updated deamon handle
[gosa.git] / gosa-si / gosa-si-bus
1 #!/usr/bin/perl
2 #===============================================================================
3 #
4 #         FILE:  gosa-server
5 #
6 #        USAGE:  ./gosa-server
7 #
8 #  DESCRIPTION:
9 #
10 #      OPTIONS:  ---
11 # REQUIREMENTS:  ---
12 #         BUGS:  ---
13 #        NOTES: 
14 #       AUTHOR:   (Andreas Rettenberger), <rettenberger@gonicus.de>
15 #      COMPANY:
16 #      VERSION:  1.0
17 #      CREATED:  12.09.2007 08:54:41 CEST
18 #     REVISION:  ---
19 #===============================================================================
21 use strict;
22 use warnings;
23 use Getopt::Long;
24 use Config::IniFiles;
25 use POSIX;
26 use Time::HiRes qw( gettimeofday );
28 use IO::Socket::INET;
29 use Crypt::Rijndael;
30 use MIME::Base64;
31 use Digest::MD5  qw(md5 md5_hex md5_base64);
32 use XML::Simple;
33 use Data::Dumper;
34 use Sys::Syslog qw( :DEFAULT setlogsock);
35 use Cwd;
36 use File::Spec;
37 use GOSA::GosaSupportDaemon;
38 use GOSA::DBsqlite;
40 my ($cfg_file, $default_cfg_file, %cfg_defaults, $foreground, $verbose);
41 my ($bus_activ, $bus_passwd, $bus_ip, $bus_port, $bus_address, $bus, $bus_mac_address, $network_interface);
42 my ($pid_file, $procid, $pid, $log_file, $my_own_address);
43 my (%free_child, %busy_child, $child_max, $child_min, %child_alive_time, $child_timeout);
44 my ($bus_known_server_db, $bus_known_server_file_name);
45 my ($xml, $bus_cipher);
47 $foreground = 0 ;
49 %cfg_defaults =
50 ("general" =>
51     {"log_file" => [\$log_file, "/var/run/".$0.".log"],
52     "pid_file" => [\$pid_file, "/var/run/".$0.".pid"],
53     "child_max" => [\$child_max, 10],
54     "child_min" => [\$child_min, 3],
55     "child_timeout" => [\$child_timeout, 180],
56     "bus_known_server_file_name" => [\$bus_known_server_file_name, "/var/lib/gosa-si/bus_known_server.db"]
57     },
58 "bus" =>
59     {"bus_activ" => [\$bus_activ, "on"],
60     "bus_passwd" => [\$bus_passwd, ""],
61     "bus_ip" => [\$bus_ip, "0.0.0.0"],
62     "bus_port" => [\$bus_port, "20080"],
63     }
64     );
66 #===  FUNCTION  ================================================================
67 #         NAME:  read_configfile
68 #   PARAMETERS:  cfg_file - string - 
69 #      RETURNS:  nothing 
70 #  DESCRIPTION:  read cfg_file and set variables
71 #===============================================================================
72 sub read_configfile {
73     my $cfg;
74     if( defined( $cfg_file) && ( length($cfg_file) > 0 )) {
75         if( -r $cfg_file ) {
76             $cfg = Config::IniFiles->new( -file => $cfg_file );
77         } else {
78             print STDERR "Couldn't read config file!";
79         }
80     } else {
81         $cfg = Config::IniFiles->new() ;
82     }
83     foreach my $section (keys %cfg_defaults) {
84         foreach my $param (keys %{$cfg_defaults{ $section }}) {
85             my $pinfo = $cfg_defaults{ $section }{ $param };
86             ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] );
87         }
88     }
89 }
91 #===  FUNCTION  ================================================================
92 #         NAME:  logging
93 #   PARAMETERS:  level - string - default 'info' 
94 #                msg - string - 
95 #                facility - string - default 'LOG_DAEMON' 
96 #      RETURNS:  nothing
97 #  DESCRIPTION:  function for logging
98 #===============================================================================
99 sub daemon_log {
100     my( $msg, $level ) = @_;
101     if(not defined $msg) { return }
102     if(not defined $level) { $level = 1 }
103     if(defined $log_file){
104         open(LOG_HANDLE, ">>$log_file");
105         if(not defined open( LOG_HANDLE, ">>$log_file" )) { 
106             print STDERR "cannot open $log_file: $!";
107             return }
108         chomp($msg);
109         if($level && $verbose && $level <= $verbose){
110             print LOG_HANDLE $msg."\n";
111             if(defined $foreground) { print $msg."\n" }
112         }
113     }
114     close( LOG_HANDLE );
115 #    my ($msg, $level, $facility) = @_;
116 #    if(not defined $msg) {return}
117 #    if(not defined $level) {$level = "info"}
118 #    if(not defined $facility) {$facility = "LOG_DAEMON"}
119 #    openlog($0, "pid,cons,", $facility);
120 #    syslog($level, $msg);
121 #    closelog;
122 #    return;
125 #===  FUNCTION  ================================================================
126 #         NAME:  check_cmdline_param
127 #   PARAMETERS:  nothing
128 #      RETURNS:  nothing
129 #  DESCRIPTION:  validates commandline parameter 
130 #===============================================================================
131 sub check_cmdline_param () {
132     my $err_config;
133     my $err_counter = 0;
134     if( not defined( $cfg_file)) {
135         my $cwd = getcwd;
136         my $name = "/etc/gosa-si/bus.conf";
137         $cfg_file = File::Spec->catfile( $cwd, $name );
138     }
139     if( $err_counter > 0 ) {
140         &usage( "", 1 );
141         if( defined( $err_config)) { print STDERR "$err_config\n"}
142         print STDERR "\n";
143         exit( -1 );
144     }
147 #===  FUNCTION  ================================================================
148 #         NAME:  check_pid
149 #   PARAMETERS:  nothing
150 #      RETURNS:  nothing
151 #  DESCRIPTION:  handels pid processing
152 #===============================================================================
153 sub check_pid {
154     $pid = -1;
155     # Check, if we are already running
156     if( open(LOCK_FILE, "<$pid_file") ) {
157         $pid = <LOCK_FILE>;
158         if( defined $pid ) {
159             chomp( $pid );
160             if( -f "/proc/$pid/stat" ) {
161                 my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/;
162                 if( $0 eq $stat ) {
163                     close( LOCK_FILE );
164                     exit -1;
165                 }
166             }
167         }
168         close( LOCK_FILE );
169         unlink( $pid_file );
170     }
172     # create a syslog msg if it is not to possible to open PID file
173     if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) {
174         my($msg) = "Couldn't obtain lockfile '$pid_file' ";
175         if (open(LOCK_FILE, '<', $pid_file)
176                 && ($pid = <LOCK_FILE>))
177         {
178             chomp($pid);
179             $msg .= "(PID $pid)\n";
180         } else {
181             $msg .= "(unable to read PID)\n";
182         }
183         if( ! ($foreground) ) {
184             openlog( $0, "cons,pid", "daemon" );
185             syslog( "warning", $msg );
186             closelog();
187         }
188         else {
189             print( STDERR " $msg " );
190         }
191         exit( -1 );
192     }
196 #===  FUNCTION  ================================================================
197 #         NAME:  usage
198 #   PARAMETERS:  nothing
199 #      RETURNS:  nothing
200 #  DESCRIPTION:  print out usage text to STDERR
201 #===============================================================================
202 sub usage {
203     print STDERR << "EOF" ;
204 usage: $0 [-hvf] [-c config]
206     -h        : this (help) message
207     -c <file> : config file
208     -f        : foreground, process will not be forked to background
209     -v        : be verbose (multiple to increase verbosity)
210 EOF
211     print "\n" ;
215 #===  FUNCTION  ================================================================
216 #         NAME:  sig_int_handler
217 #   PARAMETERS:  signal - string - signal arose from system
218 #      RETURNS:  noting
219 #  DESCRIPTION:  handels tasks to be done befor signal becomes active
220 #===============================================================================
221 sub sig_int_handler {
222     my ($signal) = @_;
223     if($bus){
224         close($bus);
225         print "$bus closed\n";
226     }
227     print "$signal\n";
228     exit(1);
230 $SIG{INT} = \&sig_int_handler;
232 #===  FUNCTION  ================================================================
233 #         NAME:  get_interface_for_ip
234 #   PARAMETERS:  ip address (i.e. 192.168.0.1)
235 #      RETURNS:  array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else
236 #  DESCRIPTION:  Uses proc fs (/proc/net/dev) to get list of interfaces.
237 #===============================================================================
238 sub get_interface_for_ip {
239         my $result;
240         my $ip= shift;
241         if ($ip && length($ip) > 0) {
242                 my @ifs= &get_interfaces();
243                 if($ip eq "0.0.0.0") {
244                         $result = "all";
245                 } else {
246                         foreach (@ifs) {
247                                 my $if=$_;
248                                 if(get_ip($if) eq $ip) {
249                                         $result = $if;
250                                 }
251                         }
252                 }
253         }
254         return $result;
257 #===  FUNCTION  ================================================================
258 #         NAME:  get_interfaces 
259 #   PARAMETERS:  none
260 #      RETURNS:  (list of interfaces) 
261 #  DESCRIPTION:  Uses proc fs (/proc/net/dev) to get list of interfaces.
262 #===============================================================================
263 sub get_interfaces {
264         my @result;
265         my $PROC_NET_DEV= ('/proc/net/dev');
267         open(PROC_NET_DEV, "<$PROC_NET_DEV")
268                 or die "Could not open $PROC_NET_DEV";
270         my @ifs = <PROC_NET_DEV>;
272         close(PROC_NET_DEV);
274         # Eat first two line
275         shift @ifs;
276         shift @ifs;
278         chomp @ifs;
279         foreach my $line(@ifs) {
280                 my $if= (split /:/, $line)[0];
281                 $if =~ s/^\s+//;
282                 push @result, $if;
283         }
285         return @result;
288 #===  FUNCTION  ================================================================
289 #         NAME:  get_mac 
290 #   PARAMETERS:  interface name (i.e. eth0)
291 #      RETURNS:  (mac address) 
292 #  DESCRIPTION:  Uses ioctl to get mac address directly from system.
293 #===============================================================================
294 sub get_mac {
295         my $ifreq= shift;
296         my $result;
297         if ($ifreq && length($ifreq) > 0) {
298                 if($ifreq eq "all") {
299                         $result = "00:00:00:00:00:00";
300                 } else {
301                         my $SIOCGIFHWADDR= 0x8927;     # man 2 ioctl_list
303                         # A configured MAC Address should always override a guessed value
304                         if ($bus_mac_address and length($bus_mac_address) > 0) {
305                                 return $bus_mac_address;
306                         }
308                         socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip')
309                                 or die "socket: $!";
311                         if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) {
312                                 my ($if, $mac)= unpack 'h36 H12', $ifreq;
314                                 if (length($mac) > 0) {
315                                         $mac=~ m/^([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/;
316                                         $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6);
317                                         $result = $mac;
318                                 }
319                         }
320                 }
321         }
322         return $result;
325 #===  FUNCTION  ================================================================
326 #         NAME:  get_ip 
327 #   PARAMETERS:  interface name (i.e. eth0)
328 #      RETURNS:  (ip address) 
329 #  DESCRIPTION:  Uses ioctl to get ip address directly from system.
330 #===============================================================================
331 sub get_ip {
332         my $ifreq= shift;
333         my $result= "";
334         my $SIOCGIFADDR= 0x8915;       # man 2 ioctl_list
335         my $proto= getprotobyname('ip');
337         socket SOCKET, PF_INET, SOCK_DGRAM, $proto
338                 or die "socket: $!";
340         if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) {
341                 my ($if, $sin)    = unpack 'a16 a16', $ifreq;
342                 my ($port, $addr) = sockaddr_in $sin;
343                 my $ip            = inet_ntoa $addr;
345                 if ($ip && length($ip) > 0) {
346                         $result = $ip;
347                 }
348         }
350         return $result;
353 #===  FUNCTION  ================================================================
354 #         NAME:  activating_child
355 #   PARAMETERS:  msg - string - incoming message
356 #                host - string - host from which the incomming message comes
357 #      RETURNS:  nothing
358 #  DESCRIPTION:  handels the distribution of incoming messages to working childs
359 #===============================================================================
360 sub activating_child {
361     my ($msg, $host) = @_;
362     my $child = &get_processing_child();
363     my $pipe_wr = $$child{'pipe_wr'};
364     daemon_log("activating: childpid: $$child{'pid'}", 5);
365     print $pipe_wr $msg.".".$host."\n";
366     return;
370 #===  FUNCTION  ================================================================
371 #         NAME:  get_processing_child
372 #   PARAMETERS:  nothing
373 #      RETURNS:  child - hash - holding the process id and the references to the pipe
374 #                               handles pipe_wr and pipe_rd
375 #  DESCRIPTION:  handels the forking, reactivating and keeping alive tasks
376 #===============================================================================
377 sub get_processing_child {
378     my $child;
379     # checking %busy_child{pipe_wr} if msg is 'done', then set child from busy to free
380     while(my ($key, $val) = each(%busy_child)) {
381         # check wether process still exists
382         my $exitus_pid = waitpid($key, WNOHANG);
383         if($exitus_pid != 0) {
384             delete $busy_child{$key};
385             daemon_log( "prozess:$key wurde aus busy_child entfernt\n", 5);
386             next;
387         }
389         # check wether process sitll works
390         my $fh = $$val{'pipe_rd'};
391         $fh->blocking(0); 
392         my $child_answer;
393         if(not $child_answer = <$fh>) { next }
394         chomp($child_answer);
395         if($child_answer eq "done") {
396             delete $busy_child{$key};
397             $free_child{$key} = $val;
398         }
399     }
401     while(my ($key, $val) = each(%free_child)) {
402         my $exitus_pid = waitpid($key, WNOHANG);
403         if($exitus_pid != 0) {
404             delete $free_child{$key};
405             daemon_log( "prozess:$key wurde aus free_child entfernt\n", 5);
406         }
407         daemon_log("free child:$key\n", 5);
408     }
409     # check @free_child and @busy_child
410     my $free_len = scalar(keys(%free_child));
411     my $busy_len = scalar(keys(%busy_child));
412     daemon_log("free children $free_len, busy children $busy_len\n",5);
413     
414     # if there is a free child, let the child work 
415     if($free_len > 0){
416         my @keys = keys(%free_child);
417         $child = $free_child{$keys[0]};
418         if(defined $child) {
419             $busy_child{$$child{'pid'}} = $child ; 
420             delete $free_child{$$child{'pid'}};          
421         }
422         return $child;
423     }
424     
425     # no free child, try to fork another one 
426     if($free_len + $busy_len < $child_max) {
427                 
428         daemon_log("not enough children, create a new one\n",5);
430         # New pipes for communication
431         my( $PARENT_wr, $PARENT_rd );
432         my( $CHILD_wr, $CHILD_rd );
433         pipe( $CHILD_rd,  $PARENT_wr );
434         pipe( $PARENT_rd, $CHILD_wr  );
435         $PARENT_wr->autoflush(1);
436         $CHILD_wr->autoflush(1);
438         ############
439         # fork child
440         ############
441         my $child_pid = fork();
442         
443         #CHILD
444         if($child_pid == 0) {
445             # Close unused pipes
446             close( $CHILD_rd );
447             close( $CHILD_wr );
448             while( 1 ) {
449                 my $rbits = "";
450                 vec( $rbits, fileno $PARENT_rd , 1 ) = 1;
452                 # waiting child_timeout for jobs to do
453                 my $nf = select($rbits, undef, undef, $child_timeout);
454                 if($nf < 0 ) {
455                     # if $nf < 1, error handling
456                     die "select(): $!\n";
457                 } elsif (! $nf) {
458                     # if already child_min childs are alive, then leave loop
459                     $free_len = scalar(keys(%free_child));
460                     $busy_len = scalar(keys(%busy_child));
461                     if($free_len + $busy_len >= $child_min) {
462                         last;
463                     } else {
464                         redo;
465                     }
466                 } 
468                 # a job for a child arise
469                 if ( vec $rbits, fileno $PARENT_rd, 1 ) {
470                     # read everything from pipe
471                     my $msg = "";
472                     $PARENT_rd->blocking(0);
473                     while(1) {
474                         my $read = <$PARENT_rd>;
475                         if(not defined $read) { last}
476                         $msg .= $read;
477                     }
479                     # forward the job msg to another function
480                     &process_incoming_msg($msg);
481                     daemon_log("processing of msg finished", 5);
483                     # important!!! wait until child says 'done', until then child is set from busy to free
484                     print $PARENT_wr "done";
485                     redo;
486                 }
487             }
488             # childs leaving the loop are allowed to die
489             exit(0);
491         #PARENT
492         } else {
493             # Close unused pipes
494             close( $PARENT_rd );
495             close( $PARENT_wr );
496             # add child to child alive hash
497             my %child_hash = (
498                     'pid' => $child_pid,
499                     'pipe_wr' => $CHILD_wr,
500                     'pipe_rd' => $CHILD_rd,
501                     );
503             $child = \%child_hash;
504             $busy_child{$$child{'pid'}} = $child;
505             return $child;
506         }
507     }
511 #===  FUNCTION  ================================================================
512 #         NAME:  process_incoming_msg
513 #   PARAMETERS:  crypted_msg - string - incoming crypted message
514 #      RETURNS:  nothing
515 #  DESCRIPTION:  handels the proceeded distribution to the appropriated functions
516 #===============================================================================
517 sub process_incoming_msg {
518     my ($crypted_msg) = @_;
519     if(not defined $crypted_msg) {
520         daemon_log("function 'process_incoming_msg': got no msg", 7);
521         return;
522     }
523     $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/;
524     $crypted_msg = $1;
525     my $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5);
527     my $msg;
528     my $msg_hash;
529     my $host_name;
530     my $host_key;
532     # check wether incoming msg is a new msg
533     $host_name = $bus_address;
534     $host_key = $bus_passwd;
535     daemon_log("process_incoming_msg: host_name: $host_name", 7);
536     daemon_log("process_incoming_msg: host_key: $host_key", 7);
537     eval{
538         my $key_cipher = &create_ciphering($host_key);
539         $msg = &decrypt_msg($crypted_msg, $key_cipher);
540         $msg_hash = &transform_msg2hash($msg);
541     };
542     if($@) {
543         daemon_log("process_incoming_msg: deciphering raise error", 7);
544         daemon_log("$@", 8);
545         $msg = undef;
546         $msg_hash = undef;
547         $host_name = undef;
548         $host_key = undef;
549     }
551     # check wether incoming msg is from a bus_known_server
552     if( not defined $msg ) {
553         my $query_res = $bus_known_server_db->select_dbentry( {table=>'bus_known_server'} );
554         while( my ($hit_num, $hit) = each %{ $query_res } ) {
555             $host_name = $hit->{hostname};
556             if( not $host_name =~ "^$host") {
557                 next;
558             }
559             $host_key = $hit->{hostkey};
560             daemon_log("process_incoming_msg: host_name: $host_name", 7);
561             daemon_log("process_incoming_msg: host_key: $host_key", 7);
562             eval{
563                 my $key_cipher = &create_ciphering($host_key);
564                 $msg = &decrypt_msg($crypted_msg, $key_cipher);
565                 $msg_hash = &transform_msg2hash($msg);
566             };
567             if($@) {
568                 daemon_log("process_incoming_msg: deciphering raise error", 7);
569                 daemon_log("$@", 8);
570                 $msg = undef;
571                 $msg_hash = undef;
572                 $host_name = undef;
573                 $host_key = undef;
574             } else {
575                 last;
576             }
577         }
578     }
580     if( not defined $msg ) {
581         daemon_log("WARNING: bus does not understand the message:", 5);
582         return;
583     }
585     # process incoming msg
586     my $header = @{$msg_hash->{header}}[0];
587     my $source = @{$msg_hash->{source}}[0];
589     daemon_log("header from msg: $header", 1);
590     daemon_log("msg to process:", 5);
591     daemon_log($msg, 5);
593     my @targets = @{$msg_hash->{target}};
594     my $len_targets = @targets;
596     if ($len_targets == 0){
597         daemon_log("ERROR: no target specified for msg $header", 1);
599     } elsif ($len_targets == 1){
600         # we have only one target symbol
601         my $target = $targets[0];
602         daemon_log("msg is for: $target", 7);
604         if($target eq $bus_address) {
605             # msg is for bus
606             if($header eq 'here_i_am'){ &here_i_am($msg_hash)}
607             elsif($header eq 'confirm_new_passwd'){ &confirm_new_passwd($msg_hash)}
608             elsif($header eq 'got_ping') { &got_ping($msg_hash)} 
609             elsif($header eq 'ping') { &ping($msg_hash)}
610             elsif($header eq 'who_has') { &who_has($msg_hash)}
611             elsif($header eq 'new_client') { &new_client($msg_hash)}
612             elsif($header eq 'delete_client') { &delete_client($msg_hash)}
614         } elsif ($target eq "*"){
615             # msg is for all server
616             my $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server'} );
617             while( my ($hit_num, $hit) = each %{ $query_res } ) {
618                 $host_name = $hit->{hostname};
619                 $host_key = $hit->{hostkey};
620                 $msg_hash->{target} = [$host_name];
621                 &send_msg_hash2address($msg_hash, $host_name, $host_key);
622             }
623             return;
624         }
626     } else {
627         # a list of targets is specified            
628         my $target_address;
629         foreach $target_address (@targets) {
631             my $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server', hostname=>$target_address} );
632             if( 1 == keys %{$query_res} ) {
633                 $host_key = $query_res->{1}->{hostkey};
634                 &send_msg_hash2address($msg_hash, $target_address, $host_key);
635                 next;
637             } else { 
638                 $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server'} );
639                 while( my ($hit_num, $hit) = each %{$query_res} ) {
640                     my $host_name = $hit->{hostname};
641                     my $host_key = $hit->{hostkey};
642                     my $clients = $hit->{clients};
643                     my @clients = split(/,/, $clients);
644                     foreach my $client (@clients) {
645                         if( not $client eq $target_address ) {
646                             next;
647                         }
648                         $msg_hash->{target} = [ $target_address ];
649                         &send_msg_hash2address($msg_hash, $host_name, $host_key);
650                         daemon_log("bus forwards msg $header for client $target_address to server $host_name", 3);
651                         last;
652                     }
653                 }
654             }
655         }
656     }
658     return;
662 #===  FUNCTION  ================================================================
663 #         NAME:  get_content_of_known_daemons
664 #   PARAMETERS:
665 #      RETURNS:
666 #  DESCRIPTION:
667 #===============================================================================
668 #sub get_content_of_known_daemons {
669 #    my ($host, $content) = @_;
670 #    return;
671 #}
674 #===  FUNCTION  ================================================================
675 #         NAME:  create_passwd
676 #   PARAMETERS:  nothing
677 #      RETURNS:  new_passwd - string 
678 #  DESCRIPTION:  creates a 32 bit long random passwd out of "a".."z","A".."Z",0..9
679 #===============================================================================
680 sub create_passwd {
681     my $new_passwd = "";
682     for(my $i=0; $i<31; $i++) {
683         $new_passwd .= ("a".."z","A".."Z",0..9)[int(rand(62))]
684     }
685     return $new_passwd;
689 #===  FUNCTION  ================================================================
690 #         NAME:  create_ciphering
691 #   PARAMETERS:  passwd - string - used to create ciphering
692 #      RETURNS:  cipher - object 
693 #  DESCRIPTION:  creates a Crypt::Rijndael::MODE_CBC object with passwd as key
694 #===============================================================================
695 #sub create_ciphering {
696 #    my ($passwd) = @_;
697 #    $passwd = substr(md5_hex("$passwd") x 32, 0, 32);
698 #    my $iv = substr(md5_hex('GONICUS GmbH'),0, 16);
700 #    my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC());
701 #    $my_cipher->set_iv($iv);
702 #    return $my_cipher;
703 #}
706 #===  FUNCTION  ================================================================
707 #         NAME:  encrypt_msg
708 #   PARAMETERS:  msg - string - message to encrypt
709 #                my_cipher - ref - reference to a Crypt::Rijndael object
710 #      RETURNS:  crypted_msg - string - crypted message
711 #  DESCRIPTION:  crypts the incoming message with the Crypt::Rijndael module
712 #===============================================================================
713 #sub encrypt_msg {
714 #    my ($msg, $my_cipher) = @_;
715 #    if(not defined $my_cipher) { print "no cipher object\n"; }
716 #    $msg = "\0"x(16-length($msg)%16).$msg;
717 #    my $crypted_msg = $my_cipher->encrypt($msg);
718 #    chomp($crypted_msg = &encode_base64($crypted_msg));
719 #    return $crypted_msg;
720 #}
723 #===  FUNCTION  ================================================================
724 #         NAME:  decrypt_msg
725 #   PARAMETERS:  crypted_msg - string - message to decrypt
726 #                my_cipher - ref - reference to a Crypt::Rijndael object
727 #      RETURNS:  msg - string - decrypted message
728 #  DESCRIPTION:  decrypts the incoming message with the Crypt::Rijndael module
729 #===============================================================================
730 #sub decrypt_msg {
731 #    my ($crypted_msg, $my_cipher) = @_ ;
732 #    $crypted_msg = &decode_base64($crypted_msg);
733 #    my $msg = $my_cipher->decrypt($crypted_msg); 
734 #    $msg =~ s/^\0*//g;
735 #    return $msg;
736 #}
739 #===  FUNCTION  ================================================================
740 #         NAME:  create_xml_hash
741 #   PARAMETERS:  header - string - message header (required)
742 #                source - string - where the message come from (required)
743 #                target - string - where the message should go to (required)
744 #                [header_value] - string - something usefull (optional)
745 #      RETURNS:  hash - hash - nomen est omen
746 #  DESCRIPTION:  creates a key-value hash, all values are stored in a array
747 #===============================================================================
748 #sub create_xml_hash {
749 #    my ($header, $source, $target, $header_value) = @_ ;
750 #    
751 #    if (not defined $header || not defined $source || not defined $target) {
752 #        daemon_log("ERROR: create_xml_hash function is invoked with uncompleted parameters", 7);
753 #    }
755 #    my $hash = {
756 #            header => [$header],
757 #            source => [$source],
758 #            target => [$target],
759 #            $header => [$header_value],
760 #    };
761 #    #daemon_log("create_xml_hash:", 7),
762 #    #chomp(my $tmp = Dumper $hash);
763 #    #daemon_log("\t$tmp\n", 7);
764 #    return $hash
765 #}
768 #===  FUNCTION  ================================================================
769 #         NAME:  create_xml_string
770 #   PARAMETERS:  xml_hash - hash - hash from function create_xml_hash
771 #      RETURNS:  xml_string - string - xml string representation of the hash
772 #  DESCRIPTION:  transform the hash to a string using XML::Simple module
773 #===============================================================================
774 #sub create_xml_string {
775 #    my ($xml_hash) = @_ ;
776 #    my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
777 #    #$xml_string =~ s/[\n]+//g;
778 #    return $xml_string;
779 #}
782 #===  FUNCTION  ================================================================
783 #         NAME:  add_content2xml_hash
784 #   PARAMETERS:  xml_ref - ref - reference to a hash from function create_xml_hash
785 #                element - string - key for the hash
786 #                content - string - value for the hash
787 #      RETURNS:  nothing 
788 #  DESCRIPTION:  add key-value pair to xml_ref, if key alread exists, then append value to list
789 #===============================================================================
790 #sub add_content2xml_hash {
791 #    my ($xml_ref, $element, $content) = @_;
792 #    if(not exists $$xml_ref{$element} ) {
793 #        $$xml_ref{$element} = [];
794 #    }
795 #    my $tmp = $$xml_ref{$element};
796 #    push(@$tmp, $content);
797 #    return;
798 #}
801 #===  FUNCTION  ================================================================
802 #         NAME:  get_content_from_xml_hash
803 #   PARAMETERS:  xml_ref - ref - reference of the xml hash
804 #                element - string - key of the value you want
805 #      RETURNS:  value - string - if key is either header, target or source
806 #                value - list - for all other keys in xml hash
807 #  DESCRIPTION:  
808 #===============================================================================
809 #sub get_content_from_xml_hash {
810 #    my ($xml_ref, $element) = @_;
811 #    my $result = $xml_ref->{$element};
812 #    if( $element eq "header" || $element eq "target" || $element eq "source") {
813 #        return @$result[0];
814 #    }
815 #    return @$result;
816 #}
819 #===  FUNCTION  ================================================================
820 #         NAME:  open_socket
821 #   PARAMETERS:  PeerAddr - string - something like 192.168.1.1 or 192.168.1.1:10000
822 #                [PeerPort] - string - necessary if port not appended by PeerAddr
823 #      RETURNS:  socket - IO::Socket::INET
824 #  DESCRIPTION:  open a socket to PeerAddr 
825 #===============================================================================
826 #sub open_socket {
827 #    my ($PeerAddr, $PeerPort) = @_ ;
828 #    if(defined($PeerPort)){
829 #        $PeerAddr = $PeerAddr.":".$PeerPort;
830 #    }
831 #    my $socket;
832 #    $socket = new IO::Socket::INET(PeerAddr => $PeerAddr ,
833 #            Porto => "tcp" ,
834 #            Type => SOCK_STREAM,
835 #            Reuse => 1,
836 #            Timeout => 5,
837 #            );
838 #    if(not defined $socket) {
839 #        return;
840 #    }
841 #    return $socket;
842 #}
845 #===  FUNCTION  ================================================================
846 #         NAME:  read_from_socket
847 #   PARAMETERS:  socket - fh - filehandel to read from  
848 #      RETURNS:  result - string - readed characters from socket
849 #  DESCRIPTION:  reads data from socket in 16 byte steps
850 #===============================================================================
851 sub read_from_socket {
852     my ($socket) = @_;
854     $socket->blocking(1);
855     my $result = <$socket>;
856     $socket->blocking(0);
857     my $part_msg;
858     while ($part_msg = <$socket>) {
859         if (not defined $part_msg) { last; }
860         $result .= $part_msg;
861     }
862     
863     #my $result = "";
864     #my $len = 16;
865     #while($len == 16){
866     #    my $char;
867     #    $len = sysread($socket, $char, 16);
868     #    if($len != 16) { last }
869     #    if($len != 16) { last }
870     #    $result .= $char;
871     #}
872     return $result;
876 #===  FUNCTION  ================================================================
877 #         NAME:  send_msg_hash2address
878 #   PARAMETERS:  msg_hash - hash - xml_hash created with function create_xml_hash
879 #                PeerAddr string - socket address to send msg
880 #                PeerPort string - socket port, if not included in socket address
881 #      RETURNS:  nothing
882 #  DESCRIPTION:  ????
883 #===============================================================================
884 #sub send_msg_hash2address {
885 #    my ($msg_hash, $address) = @_ ;
887 #    # fetch header for logging
888 #    my $header = &get_content_from_xml_hash($msg_hash, "header");
890 #    # generate xml string
891 #    my $msg_xml = &create_xml_string($msg_hash);
893 #    # fetch the appropriated passwd from hash
894 #    my $passwd = $known_daemons->{$address}->{passwd};
896 #    # create a ciphering object
897 #    my $act_cipher = &create_ciphering($passwd);
899 #    # encrypt xml msg
900 #    my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
902 #    # open socket
903 #    my $socket = &open_socket($address);
904 #    if(not defined $socket){
905 #        daemon_log("ERROR: cannot send '$header'-msg to $address , server not reachable", 1);
906 #        return;
907 #    }
909 #    # send xml msg
910 #    print $socket $crypted_msg."\n";
912 #    close $socket;
913 #    daemon_log("send '$header'-msg to $address", 5);
914 #    daemon_log("crypted_msg:\n\t$crypted_msg", 7);
915 #    return;
916 #}
919 #===  FUNCTION  ================================================================
920 #         NAME:  send_msg_hash2all
921 #   PARAMETERS:  msg_hash - hash - xml_hash created with function create_xml_hash
922 #      RETURNS:  nothing
923 #  DESCRIPTION:  send msg_hash to all registered daemons
924 #===============================================================================
925 #sub send_msg_hash2all {
926 #    my ($msg_hash) = @_;
928 #    # fetch header for logging
929 #    my $header = &get_content_from_xml_hash($msg_hash, "header");
931 #    # generate xml string
932 #    my $msg_xml = &create_xml_string($msg_hash);
934 #    # fetch a list of all target addresses 
935 #    my @targets = keys(%$known_daemons);
937 #    # itterates through the list an send each the msg
938 #    foreach my $target (@targets) {
939 #        if($target eq $bus_address) {next};   # do not send msg to bus
941 #        # fetch the appropriated passwd
942 #        my $passwd = $known_daemons->{$target}->{passwd};
944 #        # create ciphering object
945 #        my $act_cipher = &create_ciphering($passwd);
947 #        # encrypt xml msg
948 #        my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
950 #        # open socket
951 #        my $socket = &open_socket($target);
952 #        if(not defined $socket){
953 #            daemon_log("ERROR: cannot open socket to $target , server not reachable", 1);
954 #            &update_known_daemons_entry(hostname=>$target, status=>"down");
955 #            next;
956 #        }
958 #        # send xml msg
959 #        print $socket $crypted_msg."\n";
961 #        close $socket;
962 #        daemon_log("send '$header'-msg to $target", 5);
963 #        daemon_log("crypted_msg:\n\t$crypted_msg", 7);
964 #    }
965 #    return;
966 #}
969 #===  FUNCTION  ================================================================
970 #         NAME:  here_i_am
971 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
972 #      RETURNS:  nothing
973 #  DESCRIPTION:  process the incoming msg 'here_i_am'
974 #===============================================================================
975 sub here_i_am {
976     my ($msg_hash) = @_ ;
977     my $source = @{$msg_hash->{source}}[0];;
979     my $new_key = &create_passwd();
981     # create bus_known_server entry
982     my $add_hash = {
983         table=>"bus_known_server",
984         primkey=>"hostname",
985         hostname=>$source,
986         status=>"registered",
987         hostkey=>$bus_passwd,
988         clients=>"",
989     };
990     $bus_known_server_db->add_dbentry($add_hash);
992     # create outgoing msg
993     my $out_hash = &create_xml_hash("new_passwd", $bus_address, $source, $new_key);
994     &send_msg_hash2address($out_hash, $source, $bus_passwd);
996     # change hostkey, reason
997     my $update_hash = { table=>'bus_known_server' };
998     $update_hash->{where} = [ { hostname=>[$source] } ];
999     $update_hash->{update} = [ {  hostkey=>[$new_key] } ];
1000     $bus_known_server_db->update_dbentry($update_hash);
1002     return;
1006 #===  FUNCTION  ================================================================
1007 #         NAME:  confirm_new_passwd
1008 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
1009 #      RETURNS:  nothing
1010 #  DESCRIPTION:  process this incoming message
1011 #===============================================================================
1012 sub confirm_new_passwd {
1013     my ($msg_hash) = @_ ;
1014     my $source = @{$msg_hash->{source}}[0];
1016     my $update_hash = { table=>'bus_known_server' };
1017     $update_hash->{where} = [ { hostname=>[$source] } ];
1018     $update_hash->{update} = [ { status=>['key_confirmed'] } ];
1019     $bus_known_server_db->update_dbentry($update_hash);
1021     return;
1025 #===  FUNCTION  ================================================================
1026 #         NAME:  ping
1027 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
1028 #      RETURNS:  nothing
1029 #  DESCRIPTION:  process this incoming message
1030 #===============================================================================
1031 sub ping {
1032     my ($msg_hash) = @_ ;
1033     my $header = @{$msg_hash->{header}}[0];
1034     my $source = @{$msg_hash->{source}}[0];
1036     my $update_hash = { table=>'bus_known_server',
1037         where=> [ { hostname=>[$source] } ], 
1038         update=> [ { status=>$header } ],
1039     };
1040     $bus_known_server_db->update_dbentry($update_hash);
1042     my $out_hash = &create_xml_hash("got_ping", $bus_address, $source);
1043     
1044     my $res = $bus_known_server_db->select_dbentry( { table=>'bus_known_server', hostname=>$source } );
1045     my $hostkey = $res->{1}->{hostkey};
1046     &send_msg_hash2address($out_hash, $source, $hostkey);
1048     return;
1052 #===  FUNCTION  ================================================================
1053 #         NAME:  make ping
1054 #   PARAMETERS:  address - string - address which should be pinged
1055 #      RETURNS:  nothing
1056 #  DESCRIPTION:  send ping message to address
1057 #===============================================================================
1058 #sub make_ping {
1059 #    my ($address) = @_;
1060 #    daemon_log("ping:$address\n", 1);
1061 #    my $out_hash = &create_xml_hash("ping", "$bus_ip:$bus_port", $address);
1062 #    &send_msg_hash2address($out_hash, $address);
1063 #    return;
1064 #}
1067 #===  FUNCTION  ================================================================
1068 #         NAME:  got_ping
1069 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
1070 #      RETURNS:  nothing
1071 #  DESCRIPTION:  process this incoming message
1072 #===============================================================================
1073 sub got_ping {
1074     my ($msg_hash) = @_;
1075     my $source = @{$msg_hash->{source}}[0];
1077     my $update_hash = { table=>'bus_known_server',
1078         where=> [ { hostname=>[$source] } ], 
1079         update=> [ { status=>'got_ping' } ],
1080     };
1081     $bus_known_server_db->update_dbentry($update_hash);
1083     return;
1087 #===  FUNCTION  ================================================================
1088 #         NAME:  new_client
1089 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
1090 #      RETURNS:  nothing
1091 #  DESCRIPTION:  process this incoming message
1092 #===============================================================================
1093 sub new_client {
1094     my ($msg_hash) = @_ ;
1095     my $source = @{$msg_hash->{source}}[0];
1096     my $header = @{$msg_hash->{header}}[0];
1097     my $new_client = @{$msg_hash->{$header}}[0];
1098     
1099     my $res = $bus_known_server_db->select_dbentry( { table=>'bus_known_server', hostname=>$source } );
1100     my $clients = $res->{1}->{clients};
1102     # if host has alread more clients, than just append
1103     if( length($clients) != 0 ) {
1104         $clients .= ",$new_client";
1105     } else {
1106         $clients = $new_client;
1107     }
1109     my $update_hash =  { table=>'bus_known_server',
1110         where=>[ {hostname=>[$source] } ],
1111         update=>[ {clients=>[$clients] } ],    
1112     };
1114     $bus_known_server_db->update_dbentry( $update_hash );
1115     return;
1119 #===  FUNCTION  ================================================================
1120 #         NAME:  delete_client
1121 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
1122 #      RETURNS:  nothing
1123 #  DESCRIPTION:  process this incoming message
1124 #===============================================================================
1125 #sub delete_client {
1126 #    my ($msg_hash) = @_ ;
1127 #    my $source = &get_content_from_xml_hash($msg_hash, "source");
1128 #    my $header = &get_content_from_xml_hash($msg_hash, "header");
1129 #    my $del_client = (&get_content_from_xml_hash($msg_hash, $header))[0];
1130 #   
1131 #    if (not exists $known_daemons->{$source}->{$del_client}) {
1132 #        daemon_log
1133 #    }
1134 #    delete $known_daemons->{$source}->{$del_client};
1135 #    
1136 #    return;
1137 #}
1140 #===  FUNCTION  ================================================================
1141 #         NAME:  print_known_daemons_hash
1142 #   PARAMETERS:  nothing
1143 #      RETURNS:  nothing
1144 #  DESCRIPTION:  nome est omen
1145 #===============================================================================
1146 #sub print_known_daemons_hash {
1147 #    my ($tmp) = @_;
1148 #    print "####################################\n";
1149 #    print "# status of known_daemons\n";
1150 #    my $hosts;
1151 #    my $host_hash;
1152 #    $shmkh->shlock(LOCK_EX);
1153 #    my @hosts = keys %$known_daemons;
1154 #    foreach my $host (@hosts) {
1155 #        my $status = $known_daemons->{$host}->{status} ;
1156 #        my $passwd = $known_daemons->{$host}->{passwd};
1157 #        my $timestamp = $known_daemons->{$host}->{timestamp};
1158 #        my @clients = keys %{$known_daemons->{$host}->{clients}};
1159 #        my $client_string = join(", ", @clients);
1160 #        print "$host\n";
1161 #        print "\tstatus:    $status\n";
1162 #        print "\tpasswd:    $passwd\n";
1163 #        print "\ttimestamp: $timestamp\n";
1164 #        print "\tclients:   $client_string\n";
1165 #        
1166 #    }
1167 #    $shmkh->shunlock(LOCK_EX);
1168 #    print "####################################\n\n";
1169 #    return;
1170 #}
1173 #===  FUNCTION  ================================================================
1174 #         NAME:  create_known_daemons_entry
1175 #   PARAMETERS:  hostname - string - ip address and port of host
1176 #      RETURNS:  nothing
1177 #  DESCRIPTION:  nome est omen
1178 #===============================================================================
1179 #sub create_known_daemons_entry {
1180 #    my ($hostname) = @_;
1181 #    $shmkh->shlock(LOCK_EX);
1182 #    $known_daemons->{$hostname} = {};
1183 #    $known_daemons->{$hostname}->{status} = "none";
1184 #    $known_daemons->{$hostname}->{passwd} = "none";
1185 #    $known_daemons->{$hostname}->{timestamp} = "none";
1186 #    $known_daemons->{$hostname}->{clients} = {};
1187 #    $shmkh->shunlock(LOCK_EX); 
1188 #    return;  
1189 #}
1192 #===  FUNCTION  ================================================================
1193 #         NAME:  update_known_daemons_entry
1194 #   PARAMETERS:  hostname - string - ip address and port of host (required)
1195 #                status - string - (optional)
1196 #                passwd - string - (optional)
1197 #                client - string - ip address and port of client (optional)
1198 #      RETURNS:  nothing
1199 #  DESCRIPTION:  nome est omen and updates each time the timestamp of hostname
1200 #===============================================================================
1201 #sub update_known_daemons_entry {
1202 #    my $arg = {
1203 #        hostname => undef, status => undef, passwd => undef,
1204 #        client => undef,
1205 #        @_ };
1206 #    my $hostname = $arg->{hostname};
1207 #    my $status = $arg->{status};
1208 #    my $passwd = $arg->{passwd};
1209 #    my $client = $arg->{client};
1211 #    if (not defined $hostname) {
1212 #        daemon_log("ERROR: function add_content2known_daemons is not invoked with requiered parameter 'hostname'", 1);
1213 #        return;
1214 #    }
1216 #    my ($seconds, $minutes, $hours, $monthday, $month,
1217 #    $year, $weekday, $yearday, $sommertime) = localtime(time);
1218 #    $hours = $hours < 10 ? $hours = "0".$hours : $hours;
1219 #    $minutes = $minutes < 10 ? $minutes = "0".$minutes : $minutes;
1220 #    $seconds = $seconds < 10 ? $seconds = "0".$seconds : $seconds;
1221 #    $month+=1;
1222 #    $month = $month < 10 ? $month = "0".$month : $month;
1223 #    $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday;
1224 #    $year+=1900;
1225 #    my $t = "$year$month$monthday$hours$minutes$seconds";
1227 #    $shmkh->shlock(LOCK_EX);
1228 #    if (defined $status) {
1229 #        $known_daemons->{$hostname}->{status} = $status;
1230 #    }
1231 #    if (defined $passwd) {
1232 #        $known_daemons->{$hostname}->{passwd} = $passwd;
1233 #    }
1234 #    if (defined $client) {
1235 #        $known_daemons->{$hostname}->{clients}->{$client} = "";
1236 #    }
1237 #    $known_daemons->{$hostname}->{timestamp} = $t;
1238 #    $shmkh->shunlock(LOCK_EX);
1239 #    return;
1240 #}
1243 #==== MAIN = main ==============================================================
1245 #  parse commandline options
1246 Getopt::Long::Configure( "bundling" );
1247 GetOptions("h|help" => \&usage,
1248            "c|config=s" => \$cfg_file,
1249            "f|foreground" => \$foreground,
1250            "v|verbose+" => \$verbose,
1251            );
1253 #  read and set config parameters
1254 &check_cmdline_param ;
1255 &read_configfile;
1256 &check_pid;
1258 $SIG{CHLD} = 'IGNORE';
1260 # restart daemon log file
1261 if(-e $log_file ) { unlink $log_file }
1262 daemon_log(" ", 1);
1263 daemon_log("$0 started!", 1);
1265 # forward error messages to logfile
1266 if( ! $foreground ) {
1267         open(STDERR, '>>', $log_file);
1268         open(STDOUT, '>>', $log_file);
1271 # Just fork, if we"re not in foreground mode
1272 if( ! $foreground ) {
1273         chdir '/'                 or die "Can't chdir to /: $!";
1274         $pid = fork;
1275         setsid                    or die "Can't start a new session: $!";
1276         umask 0;
1279 else { $pid = $$; }
1281 # Do something useful - put our PID into the pid_file
1282 if( 0 != $pid ) {
1283     open( LOCK_FILE, ">$pid_file" );
1284     print LOCK_FILE "$pid\n";
1285     close( LOCK_FILE );
1286     if( !$foreground ) { exit( 0 ) };
1289 # connect to bus_known_server_db
1290 my @server_col_names = ('hostname', 'status', 'hostkey', 'timestamp', 'clients' );
1291 $bus_known_server_db = GOSA::DBsqlite->new($bus_known_server_file_name);
1292 $bus_known_server_db->create_table('bus_known_server', \@server_col_names);
1295 # detect own ip and mac address
1296 $network_interface= &get_interface_for_ip($bus_ip);
1297 $bus_mac_address= &get_mac($network_interface);
1299 daemon_log("bus ip address detected: $bus_ip", 1);
1300 daemon_log("bus mac address detected: $bus_mac_address", 1);
1302 # complete addresses
1303 $bus_address = "$bus_ip:$bus_port";
1305 # setup xml parser
1306 $xml = new XML::Simple();
1308 # create cipher object
1309 $bus_cipher = &create_ciphering($bus_passwd);
1310 $bus_address = "$bus_ip:$bus_port";
1312 # create reading and writing vectors
1313 my $rbits = my $wbits = my $ebits = "";
1315 # open the bus socket
1316 if($bus_activ eq "on") {
1317     daemon_log(" ", 1);
1318     $bus = IO::Socket::INET->new(LocalPort => $bus_port,
1319             Type => SOCK_STREAM,
1320             Reuse => 1,
1321             Listen => 20,
1322             ) or die "kann kein TCP-Server an Port $bus_port sein: $@\n";
1323     vec($rbits, fileno $bus, 1) = 1;
1324     vec($wbits, fileno $bus, 1) = 1;
1325     daemon_log ("start bus at $bus_ip:$bus_port", 1);        
1328 # add bus to known_daemons 
1330 #&create_known_daemons_entry($bus_address);
1331 #&update_known_daemons_entry(hostname=>$bus_address, status=>"bus", passwd=>$bus_passwd);
1334 while(1) {
1335     my $nf = select($rbits, $wbits, undef, undef);
1336     # error handling
1337     if($nf < 0 ) { 
1338     }
1340     # something is coming in 
1341     if(vec $rbits, fileno $bus, 1 ) {
1342         my $client = $bus->accept();
1343         my $other_end = getpeername($client);
1344         if(not defined $other_end) {
1345             daemon_log("Gegenstelle konnte nicht identifiziert werden: $!\n");
1346         } else {
1347             my ($port, $iaddr) = unpack_sockaddr_in($other_end);
1348             my $actual_ip = inet_ntoa($iaddr);
1349             daemon_log("\naccept client from $actual_ip\n", 5);
1350             my $in_msg = &read_from_socket($client);
1351             if(defined $in_msg){
1352                 &activating_child($in_msg, $actual_ip);
1353             } else {
1354                 daemon_log("cannot read from $actual_ip\n",1);
1355             }
1356         }
1357         close($client);        
1358     }