package Security::Monitoring::Messaging; use Security::Monitoring::Messaging::Messenger; use 5.14.2; use strict; use warnings; use Proc::Daemon; use Carp qw(carp croak); use Storable qw(fd_retrieve); use POSIX qw(mkfifo); use File::Spec::Functions; use Cwd; use IO::Socket::UNIX; use IO::Socket::INET; my $class = "Security::Monitoring::Messaging::Messenger"; =head1 NAME Security::Monitoring::Messaging - The great new Security::Monitoring::Messaging! =head1 VERSION Version 0.01 =cut our $VERSION = '0.01'; =head1 SYNOPSIS you want to call this script using Proc::Daemon exec, that way it will be able to do its work from the background. Whenever another script needs to ask for a messenger (most of theses orders should be made at start time depending on the configuration) it should nstore a hash to the messenger unit named pipe. my %params = ( input=>{name=>'filename', type=>'unix_socket|network_socket|named_pipe', #where it will listen; listen=>$queue_size_for_listen;#for sockets local_addr=>'what it says on the can',#for network socket local_port=>'idem',#for network socket proto=>'tcp|udp',#for network socket } output1=>{name=>'filename', type=>'unix_socket|network_socket|named_pipe, bind=>address,#if network socket Local=>'pathname to local buffer',#unix socket only Listen=>$queue_size_for_listen',#for sockets peer_addr=>'address", ... ... }, output2=>{...}, ... outputn=>{...}, ); nstore_fd \%params $messaging_named_pipe; a messaging daemon should be started. =head1 DESCRIPTION this module is a daemon that listens for messenger requests and spawn little messenger daemon to handle IPC between units (such as report communication between the reporting unit and the monitoring unit) it is done so to allow each unit to run on a different server. =head1 SUBROUTINES/METHODS run =head2 run this is the main function, even if this is a pm file it also is a self contained program. One can run the whole module on one server or only part of it and have it interact with other servers. An Instance of the Messaging daemon has to run on each and every server that supports one of the main units (ie reporting unit, config unit, mailer unit, monitoring unit and db interaction unit) =cut =head3 sample param hash my %params = ( input=>{name=>'filename', type=>'unix_socket|network_socket|named_pipe', #where it will listen; listen=>$queue_size_for_listen;#for sockets peer=>'peer_buffer_file_name',#unix sockets local_addr=>'what it says on the can',#for network socket local_port=>'idem',#for network socket proto=>'tcp|udp',#for network socket } output1=>{name=>'filename', type=>'unix_socket|network_socket|named_pipe, bind=>address,#if network socket Local=>'pathname to local buffer',#unix socket only Listen=>$queue_size_for_listen',#for sockets peer_addr=>'address", ... ... }, output2=>{...}, ... outputn=>{...}, ); =cut sub run { #setup part my $request_file_name = shift;#named pipe to which the Messenging daemon will #listen for messenger spawn requests. my $log_file_name = shift; if (!defined($log_file_name)){ $log_file_name = '/dev/null'; } open my $log, '>>',$log_file_name or croak "could not open log_file"; if (!defined($request_file_name)){ croak "can not run without something to listen to!\n"; } mkfifo($request_file_name,0777)||croak "could not open named pipe : $!"; my %children = (); my $pid; my %messenger_params; print $log "I'm $$ and starting to run\n"; #running part ABORT:while(1){ open my $fh,'<',$request_file_name; my $params; eval{$params = fd_retrieve($fh)}; if($@){ print "continuing after error $@"; close $fh; redo; } close $fh; print "params input name = $params->{input}->{name}\n"; $messenger_params{input}->{name} = $params->{input}->{name}; $messenger_params{input}->{type} = $params->{input}->{type}; #put the input data into the messenger params hash given ($params->{input}->{type}){ when('unix_socket'){ $messenger_params{input}->{fh} = IO::Socket::UNIX::->new( Type=>SOCK_STREAM, Local=>$params->{input}->{name}, Listen=>$params->{input}->{Listen}, ); } when('network_socket'){ if(!exists($params->{input}->{local_addr})||!exists($params->{input}->{local_port})){ carp "I need a peer addr and a peer port to create a socket!"; goto ABORT; } $messenger_params{input}->{fh} = IO::Socket::INET->new( Listen=>$params->{input}->{Listen}, LocalAddr=>$params->{input}->{loca_addr}, Proto=>$params->{input}->{proto}, LocalPort=>$params->{input}->{local_port}, ); } when('named_pipe'){ mkfifo($params->{input}->{name},0777)||carp "could not open named pipe : $!"; open $messenger_params{input}->{fh}, '<',$params->{input}->{name} or carp "could not open namedpipe for input"; } } #putting the output subhashes into the messenger params hash my @keys = keys %{$params->{output}}; OUTPUT: foreach my $key (@keys){ $messenger_params{output}->{$key}->{type} = $params->{output}->{$key}->{type}; $messenger_params{output}->{$key}->{name} = $params->{output}->{$key}->{name}; given ($params->{output}->{$key}->{type}){ when('unix_socket'){ $messenger_params{output}->{$key}->{fh} = IO::Socket::UNIX->new( Type=>SOCK_STREAM, Local=>$params->{output}->{$key}->{name}, Listen=>$params->{output}->{$key}->{listen}, ); } when('network_socket'){ $messenger_params{output}->{$key}->{fh} = IO::Socket::INET->new( LocalAddr=>$params->{output}->{$key}->{local_addr}, LocalPort=>$params->{output}->{$key}->{local_port}, Proto=>$params->{output}->{$key}->{proto}, Listen=>$params->{output}->{$key}->{listen}, ); } when('named_pipe'){ mkfifo($messenger_params{output}->{$key}->{name},0777)||carp "could not open named pipe : $!"; } } } $pid = fork(); if (!$pid){#I'm the son my $messenger = $class->new(\%messenger_params); print "starting to relay\n"; $messenger->relay; } else{ print "$pid forked\n"; $children{$pid} = 1; } } } if(!defined(caller())){ my $filename = shift; my $logfile = shift; &run($filename,$logfile); }