Code

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