Code

Removed usePrototype flag, its activated always now.
[gosa.git] / gosa-si / server / events / server_server_com.pm
1 package server_server_com;
3 use strict;
4 use warnings;
6 use Exporter;
7 use Data::Dumper;
8 use GOSA::GosaSupportDaemon;
9 use Time::HiRes qw( usleep);
10 use Socket;
12 our @ISA = qw(Exporter);
14 my @events = (
15     'information_sharing',
16     'new_server',
17     'confirm_new_server',
18     'new_foreign_client',
19     'trigger_wake',
20     'foreign_job_updates',
21     'confirm_usr_msg',
22     );
23     
24 our @EXPORT = @events;
26 BEGIN {}
28 END {}
30 ### Start ######################################################################
32 sub get_events {
33     return \@events;
34 }
37 sub information_sharing {
38     my ($msg, $msg_hash, $session_id) = @_ ;
39     my $header = @{$msg_hash->{'header'}}[0];
40     my $source = @{$msg_hash->{'source'}}[0];
41     my $target = @{$msg_hash->{'target'}}[0];
43     # Handling of msg tag 'new_user'
44     if (exists $msg_hash->{'new_user'}) {
45         my $new_user_list = $msg_hash->{'new_user'};
47         # Sanity check of new_user_list
48         if (ref($new_user_list) eq 'HASH') {
49             &main::daemon_log("$session_id ERROR: 'new_user'-tag in incoming msg has no content!", 1);
51         } else {
52                         my @user_list;
53             # Add each user to login_users_db
54             foreach my $new_user_info (@$new_user_list) {
55                 my ($client, $user) = split(/;/, $new_user_info);
56                 my %add_hash = ( table=>$main::login_users_tn, 
57                         primkey=> ['client', 'user'],
58                         client=>$client,
59                         user=>$user,
60                         timestamp=>&get_time,
61                         regserver=>$source,
62                         ); 
63                 my ($res, $error_str) = $main::login_users_db->add_dbentry( \%add_hash );
64                 if ($res != 0)  
65                                 {
66                     &main::daemon_log("$session_id ERROR: cannot add entry to known_clients: $error_str", 1);
67                 }
68                                 else
69                                 {
70                                         push(@user_list, "'$user' at '$client'");
71                                 }
72             }
73                         &main::daemon_log("$session_id INFO: server '$source' reports the following logged in user: ".join(", ", @user_list), 5);
74         }
75     }
77     # Handling of msg tag 'user_db'
78     if (exists $msg_hash->{'user_db'}) {
79         my $user_db_list = $msg_hash->{'user_db'};
81         # Sanity check of user_db_list
82         if (ref($user_db_list) eq 'HASH') {
83             &main::daemon_log("$session_id ERROR: 'user_db'-tag in incoming msg has no content!", 1);
85         } else {
86             # Delete all old login information
87             my $sql = "DELETE FROM $main::login_users_tn WHERE regserver='$source'"; 
88             my $res = $main::login_users_db->exec_statement($sql);
90             # Add each user to login_users_db
91                         my @user_list;
92             foreach my $user_db_info (@$user_db_list) {
93                 my ($client, $user) = split(/;/, $user_db_info);
94                 my %add_hash = ( table=>$main::login_users_tn, 
95                         primkey=> ['client', 'user'],
96                         client=>$client,
97                         user=>$user,
98                         timestamp=>&get_time,
99                         regserver=>$source,
100                         ); 
101                 my ($res, $error_str) = $main::login_users_db->add_dbentry( \%add_hash );
102                 if ($res != 0)  {
103                     &main::daemon_log("$session_id ERROR: cannot add entry to known_clients: $error_str", 1);
104                 }
105                                 else
106                                 {
107                                         push(@user_list, "'$user' at '$client'");
108                                 }
109             }
110                         &main::daemon_log("$session_id INFO: server '$source' reports the following logged in user: ".join(", ", @user_list), 5);
111         }
112     }
114     return;
117 sub foreign_job_updates {
118     my ($msg, $msg_hash, $session_id) = @_ ;
119     my $header = @{$msg_hash->{'header'}}[0];
120     my $source = @{$msg_hash->{'source'}}[0];
121     my $target = @{$msg_hash->{'target'}}[0];
122     
123     my @act_keys = keys %$msg_hash;
124     my @jobs;
125     foreach my $key (@act_keys) {
126         if ($key =~ /answer\d+/ ) { push(@jobs, $key); }
127     }
129     foreach my $foreign_job (@jobs) {
131         # add job to job queue
132         my $func_dic = {table=>$main::job_queue_tn,
133             primkey=>['macaddress', 'headertag'],
134             timestamp=>@{@{$msg_hash->{$foreign_job}}[0]->{'timestamp'}}[0],
135             status=>@{@{$msg_hash->{$foreign_job}}[0]->{'status'}}[0],
136             result=>@{@{$msg_hash->{$foreign_job}}[0]->{'result'}}[0],
137             progress=>@{@{$msg_hash->{$foreign_job}}[0]->{'progress'}}[0],
138             headertag=>@{@{$msg_hash->{$foreign_job}}[0]->{'headertag'}}[0],
139             targettag=>@{@{$msg_hash->{$foreign_job}}[0]->{'targettag'}}[0],
140             xmlmessage=>@{@{$msg_hash->{$foreign_job}}[0]->{'xmlmessage'}}[0],
141             macaddress=>@{@{$msg_hash->{$foreign_job}}[0]->{'macaddress'}}[0],
142             plainname=>@{@{$msg_hash->{$foreign_job}}[0]->{'plainname'}}[0],
143             siserver=>$source,
144             modified=>"0",
145         };
146         my $res = $main::job_db->add_dbentry($func_dic);
147         if (not $res == 0) {
148             &main::daemon_log("$session_id ERROR: ServerPackages: process_job_msg: $res", 1);
149         } else {
150             &main::daemon_log("$session_id INFO: ServerPackages: $header, job '".@{@{$msg_hash->{$foreign_job}}[0]->{'headertag'}}[0].
151                     "' successfully added to job queue", 5);
152         }
153     }
155     return;
159 sub new_server {
160     my ($msg, $msg_hash, $session_id) = @_ ;
161     my $header = @{$msg_hash->{'header'}}[0];
162     my $source = @{$msg_hash->{'source'}}[0];
163     my $target = @{$msg_hash->{'target'}}[0];
164     my $key = @{$msg_hash->{'key'}}[0];
165     my $mac = exists $msg_hash->{'macaddress'} ? @{$msg_hash->{'macaddress'}}[0] : "" ;
166     my @clients = exists $msg_hash->{'client'} ? @{$msg_hash->{'client'}} : qw();
167     my @loaded_modules = exists $msg_hash->{'loaded_modules'} ? @{$msg_hash->{'loaded_modules'}} : qw();
169         # Ignor message if I'm already within a registration process for server $source
170         my $check_statement = "SELECT * FROM $main::known_server_tn WHERE status='new_server' AND hostname='$source'"; 
171         &main::daemon_log("$session_id DEBUG $check_statement", 7);
172         my $check_res = $main::known_server_db->select_dbentry($check_statement);
173         my $blocking_process = keys(%$check_res);
174         if ($blocking_process)
175         {
176                 return;
177         }
179     # Sanity check
180     if (ref $key eq 'HASH') {
181         &main::daemon_log("$session_id ERROR: 'new_server'-message from host '$source' contains no key!", 1);
182         return;
183     }
184     # Add foreign server to known_server_db
185         my $new_update_time = &calc_timestamp(&get_time(), 'plus', $main::foreign_servers_register_delay);
186     my $func_dic = {table=>$main::known_server_tn,
187         primkey=>['hostname'],
188         hostname => $source,
189         macaddress => $mac,
190         status => "new_server",
191         hostkey => $key,
192         loaded_modules => join(',', @loaded_modules),
193         timestamp=>&get_time(),
194                 update_time=>$new_update_time,
195     };
196     my $res = $main::known_server_db->add_dbentry($func_dic);
197     if (not $res == 0) {
198         &main::daemon_log("$session_id ERROR: server_server_com.pm: cannot add server to known_server_db: $res", 1);
199     } else {
200         &main::daemon_log("$session_id INFO: server_server_com.pm: server '$source' successfully added to known_server_db", 5);
201     }
203     # delete all entries at foreign_clients_db coresponding to this server
204     my $del_sql = "DELETE FROM $main::foreign_clients_tn WHERE regserver='$source' ";
205     my $del_res = $main::foreign_clients_db->exec_statement($del_sql);
207     # add clients of foreign server to known_foreign_clients_db
208     my @sql_list;
209     foreach my $client (@clients) {
210         my @client_details = split(/,/, $client);
212         # workaround to avoid double entries in foreign_clients_db
213         my $del_sql = "DELETE FROM $main::foreign_clients_tn WHERE hostname='".$client_details[0]."'";
214         push(@sql_list, $del_sql);
216         my $sql = "INSERT INTO $main::foreign_clients_tn VALUES ("
217             ."'".$client_details[0]."',"   # hostname
218             ."'".$client_details[1]."',"   # macaddress
219             ."'".$source."',"              # regserver
220             ."'".&get_time()."')";         # timestamp
221         push(@sql_list, $sql);
222     }
223     if (@sql_list) {
224                 my $len = @sql_list;
225                 $len /= 2;
226         &main::daemon_log("$session_id DEBUG: Inserting ".$len." entries to foreign_clients_db", 8);
227         my $res = $main::foreign_clients_db->exec_statementlist(\@sql_list);
228     }
230     # fetch all registered clients
231     my $client_sql = "SELECT * FROM $main::known_clients_tn"; 
232     my $client_res = $main::known_clients_db->exec_statement($client_sql);
235     # add already connected clients to registration message 
236     my $myhash = &create_xml_hash('confirm_new_server', $main::server_address, $source);
237     &add_content2xml_hash($myhash, 'key', $key);
238     map(&add_content2xml_hash($myhash, 'client', @{$_}[0].",".@{$_}[4]), @$client_res);
240     # add locally loaded gosa-si modules to registration message
241     my $loaded_modules = {};
242     while (my ($package, $pck_info) = each %$main::known_modules) {
243         foreach my $act_module (keys(%{@$pck_info[2]})) {
244             $loaded_modules->{$act_module} = ""; 
245         }
246     }
247     map(&add_content2xml_hash($myhash, "loaded_modules", $_), keys(%$loaded_modules));
249     # add macaddress to registration message
250     my ($host_ip, $host_port) = split(/:/, $source);
251     my $local_ip = &get_local_ip_for_remote_ip($host_ip);
252     my $network_interface= &get_interface_for_ip($local_ip);
253     my $host_mac = &get_mac_for_interface($network_interface);
254     &add_content2xml_hash($myhash, 'macaddress', $host_mac);
256     # build registration message and send it
257     my $out_msg = &create_xml_string($myhash);
258     my $error =  &main::send_msg_to_target($out_msg, $source, $main::ServerPackages_key, 'confirm_new_server', $session_id); 
260     return;
264 sub confirm_new_server {
265     my ($msg, $msg_hash, $session_id) = @_ ;
266     my $header = @{$msg_hash->{'header'}}[0];
267     my $source = @{$msg_hash->{'source'}}[0];
268     my $key = @{$msg_hash->{'key'}}[0];
269     my $mac = exists $msg_hash->{'macaddress'} ? @{$msg_hash->{'macaddress'}}[0] : "" ;
270     my @clients = exists $msg_hash->{'client'} ? @{$msg_hash->{'client'}} : qw();
271     my @loaded_modules = exists $msg_hash->{'loaded_modules'} ? @{$msg_hash->{'loaded_modules'}} : qw();
273         my $new_update_time = &calc_timestamp(&get_time(), 'plus', $main::foreign_servers_register_delay);
274     my $sql = "UPDATE $main::known_server_tn".
275         " SET status='$header', hostkey='$key', loaded_modules='".join(",",@loaded_modules)."', macaddress='$mac', update_time='$new_update_time'".
276         " WHERE hostname='$source'"; 
277     my $res = $main::known_server_db->update_dbentry($sql);
279     # add clients of foreign server to known_foreign_clients_db
280     my @sql_list;
281     foreach my $client (@clients) {
282         my @client_details = split(/,/, $client);
284         # workaround to avoid double entries in foreign_clients_db
285         my $del_sql = "DELETE FROM $main::foreign_clients_tn WHERE hostname='".$client_details[0]."'";
286         push(@sql_list, $del_sql);
288         my $sql = "INSERT INTO $main::foreign_clients_tn VALUES ("
289             ."'".$client_details[0]."',"        # hostname
290             ."'".$client_details[1]."',"        # macaddress
291             ."'".$source."',"                   # regserver
292             ."'".&get_time()."')";                      # timestamp
293         push(@sql_list, $sql);
294     }
295     if (@sql_list) {
296                 my $len = @sql_list;
297                 $len /= 2;
298         &main::daemon_log("$session_id DEBUG: Inserting ".$len." entries to foreign_clients_db", 8);
299         my $res = $main::foreign_clients_db->exec_statementlist(\@sql_list);
300     }
303     return;
307 sub new_foreign_client {
308     my ($msg, $msg_hash, $session_id) = @_ ;
309     my $header = @{$msg_hash->{'header'}}[0];
310     my $source = @{$msg_hash->{'source'}}[0];
311     my $hostname = @{$msg_hash->{'client'}}[0];
312     my $macaddress = @{$msg_hash->{'macaddress'}}[0];
313         # if new client is known in known_clients_db
314         my $check_sql = "SELECT * FROM $main::known_clients_tn WHERE (macaddress LIKE '$macaddress')"; 
315         my $check_res = $main::known_clients_db->select_dbentry($check_sql);
317         if( (keys(%$check_res) == 1) ) {
318                         my $host_key = $check_res->{1}->{'hostkey'};
320                         # check if new client is still alive
321                         my $client_hash = &create_xml_hash("ping", $main::server_address, $hostname);
322                         &add_content2xml_hash($client_hash, 'session_id', $session_id);
323                         my $client_msg = &create_xml_string($client_hash);
324                         my $error = &main::send_msg_to_target($client_msg, $hostname, $host_key, 'ping', $session_id);
325                         my $message_id;
326                         my $i = 0;
327                         while (1) {
328                                         $i++;
329                                         my $sql = "SELECT * FROM $main::incoming_tn WHERE headertag='answer_$session_id'";
330                                         my $res = $main::incoming_db->exec_statement($sql);
331                                         if (ref @$res[0] eq "ARRAY") {
332                                                         $message_id = @{@$res[0]}[0];
333                                                         last;
334                                         }
336                                         # do not run into a endless loop
337                                         if ($i > 50) { last; }
338                                         usleep(100000);
339                         }
341                         # client is alive
342                         # -> new_foreign_client will be ignored
343                         if (defined $message_id) {
344                                 &main::daemon_log("$session_id ERROR: At new_foreign_clients: host '$hostname' is reported as a new foreign client, ".
345                                                                 "but the host is still registered at this server. So, the new_foreign_client-msg will be ignored: $msg", 1);
346                         }
347         }
349         
350         # new client is not found in known_clients_db or
351         # new client is dead -> new_client-msg from foreign server is valid
352         # -> client will be deleted from known_clients_db 
353         # -> inserted to foreign_clients_db
354         
355         my $del_sql = "DELETE FROM $main::known_clients_tn WHERE (hostname='$hostname')";
356         my $del_res = $main::known_clients_db->exec_statement($del_sql);
357     my $func_dic = { table => $main::foreign_clients_tn,
358         primkey => ['hostname'],
359         hostname =>   $hostname,
360         macaddress => $macaddress,
361         regserver =>  $source,
362         timestamp =>  &get_time(),
363     };
364     my $res = $main::foreign_clients_db->add_dbentry($func_dic);
365     if (not $res == 0) {
366         &main::daemon_log("$session_id ERROR: server_server_com.pm: cannot add server to foreign_clients_db: $res", 1);
367     } else {
368         &main::daemon_log("$session_id INFO: server_server_com.pm: client '$hostname' successfully added to foreign_clients_db", 5);
369     }
371     return;
375 sub trigger_wake {
376     my ($msg, $msg_hash, $session_id) = @_ ;
378     foreach (@{$msg_hash->{'macaddress'}}){
379         &main::daemon_log("$session_id INFO: trigger wake for $_", 5);
380         my $host    = $_;
381         my $ipaddr  = '255.255.255.255';
382         my $port    = getservbyname('discard', 'udp');
383         if (not defined $port) {
384                 &main::daemon_log("$session_id ERROR: cannot determine port for wol $_: 'getservbyname('discard', 'udp')' failed!",1);
385                 next;
386         }
388         my ($raddr, $them, $proto);
389         my ($hwaddr, $hwaddr_re, $pkt);
391         # get the hardware address (ethernet address)
392         $hwaddr_re = join(':', ('[0-9A-Fa-f]{1,2}') x 6);
393         if ($host =~ m/^$hwaddr_re$/) {
394           $hwaddr = $host;
395         } else {
396           &main::daemon_log("$session_id ERROR: trigger_wake called with non mac address", 1);
397         }
399         # Generate magic sequence
400         foreach (split /:/, $hwaddr) {
401                 $pkt .= chr(hex($_));
402         }
403         $pkt = chr(0xFF) x 6 . $pkt x 16 . $main::wake_on_lan_passwd;
405         # Allocate socket and send packet
407         $raddr = gethostbyname($ipaddr);
408         if (not defined $raddr) {
409                 &main::daemon_log("$session_id ERROR: cannot determine raddr for wol $_: 'gethostbyname($ipaddr)' failed!", 1);
410                 next;
411         }
413         $them = pack_sockaddr_in($port, $raddr);
414         $proto = getprotobyname('udp');
416         socket(S, AF_INET, SOCK_DGRAM, $proto) or die "socket : $!";
417         setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt : $!";
418         send(S, $pkt, 0, $them) or die "send : $!";
419         close S;
420     }
422     return;
426 sub confirm_usr_msg {
427     my ($msg, $msg_hash, $session_id) = @_ ;
428     &clMessages::confirm_usr_msg($msg, $msg_hash, $session_id);
429     return;
433 1;