Initial revision
[OpenSRF.git] / src / perlmods / OpenSRF / UnixServer.pm
1 package OpenSRF::UnixServer;
2 use strict; use warnings;
3 use base qw/OpenSRF/;
4 use OpenSRF::EX;
5 use OpenSRF::Utils::Logger qw(:level);
6 use OpenSRF::Transport::PeerHandle;
7 use OpenSRF::Application;
8 use OpenSRF::AppSession;
9 use OpenSRF::DomainObject::oilsResponse qw/:status/;
10 use OpenSRF::System;
11 use vars qw/@ISA/;
12 use Carp;
13
14 # XXX Need to add actual logging statements in the code
15 my $logger = "OpenSRF::Utils::Logger";
16
17 sub DESTROY { confess "Dying $$"; }
18
19 =head1 What am I
20
21 All inbound messages are passed on to the UnixServer for processing.
22 We take the data, close the Unix socket, and pass the data on to our abstract
23 'process()' method.  
24
25 Our purpose is to 'multiplex' a single TCP connection into multiple 'client' connections.
26 So when you pass data down the Unix socket to us, we have been preforked and waiting
27 to disperse new data among us.
28
29 =cut
30
31 {
32         my $app;
33         sub app { return $app; }
34
35         sub new {
36                 my( $class, $app1 ) = @_;
37                 if( ! $app1 ) {
38                         throw OpenSRF::EX::InvalidArg( "UnixServer requires an app name to run" );
39                 }
40                 $app = $app1;
41                 my $self = bless( {}, $class );
42                 if( OpenSRF::Utils::Config->current->system->server_type !~ /fork/i ) {
43                         $self->child_init_hook();
44                 }
45                 return $self;
46         }
47
48 }
49
50 =head2 process_request()
51
52 Takes the incoming data, closes the Unix socket and hands the data untouched 
53 to the abstract process() method.  This method is implemented in our subclasses.
54
55 =cut
56
57 sub process_request {
58
59         my $self = shift;
60         my $data; my $d;
61         while( $d = <STDIN> ) { $data .= $d; }
62
63
64         if( ! $data or ! defined( $data ) or $data eq "" ) {
65                 throw OpenSRF::EX::Socket(
66                                 "Unix child received empty data from socket" );
67         }
68
69         if( ! close( $self->{server}->{client} ) ) {
70                 $logger->debug( "Error closing Unix socket: $!", ERROR );
71         }
72
73
74         my $app = $self->app();
75         $logger->transport( "UnixServer for $app received $data", INTERNAL );
76
77         my $app_session = OpenSRF::Transport->handler( $self->app(), $data );
78         my $config = OpenSRF::Utils::Config->current;
79
80
81         my $keepalive = OpenSRF::Utils::Config->current->system->keep_alive;
82
83         my $req_counter = 0;
84         while( $app_session->state and $app_session->state != $app_session->DISCONNECTED() and
85                         $app_session->find( $app_session->session_id ) ) {
86                 
87
88                 my $before = time;
89                 $logger->transport( "UnixServer calling queue_wait $keepalive", INTERNAL );
90                 $app_session->queue_wait( $keepalive );
91                 my $after = time;
92
93                 if( ($after - $before) >= $keepalive ) { 
94
95                         my $res = OpenSRF::DomainObject::oilsConnectStatus->new(
96                                                                         status => "Disconnected on timeout",
97                                                                         statusCode => STATUS_TIMEOUT);
98                         $app_session->status($res);
99                         $app_session->state( $app_session->DISCONNECTED() );
100                         last;
101                 }
102
103         }
104
105         my $x = 0;
106         while( 1 ) {
107                 $logger->transport( "Looping on zombies " . $x++ , DEBUG);
108                 last unless ( $app_session->queue_wait(0));
109         }
110
111         $logger->transport( "Timed out, disconnected, or auth failed", INFO );
112         $app_session->kill_me;
113                 
114 }
115
116
117 sub serve {
118         my( $self ) = @_;
119         my $config = OpenSRF::Utils::Config->current;
120         my $app = $self->app();
121         my $conf_base =  $config->dirs->conf_dir;
122         my $conf = join( "/", $conf_base, $config->unix_conf->$app );
123         $logger->transport( 
124                         "Running UnixServer as @OpenSRF::UnixServer::ISA for $app with conf file: $conf", INTERNAL );
125         $self->run( 'conf_file' => $conf );
126 }
127
128 sub configure_hook {
129         my $self = shift;
130         my $app = $self->app;
131         my $config = OpenSRF::Utils::Config->current;
132
133         $logger->debug( "Setting application implementaion for $app", DEBUG );
134
135         OpenSRF::Application->application_implementation( $config->application_implementation->$app );
136         OpenSRF::Application->application_implementation->initialize()
137                 if (OpenSRF::Application->application_implementation->can('initialize'));
138         return OpenSRF::Application->application_implementation;
139 }
140
141 sub child_finish_hook {
142         my $self = shift;
143         OpenSRF::AppSession->kill_client_session_cache;
144 }
145
146 sub child_init_hook { 
147
148         my $self = shift;
149         $logger->transport( 
150                         "Creating PeerHandle from UnixServer child_init_hook", INTERNAL );
151         OpenSRF::Transport::PeerHandle->construct( $self->app() );
152         my $peer_handle = OpenSRF::System::bootstrap_client();
153         OpenSRF::Application->application_implementation->child_init
154                 if (OpenSRF::Application->application_implementation->can('child_init'));
155         return $peer_handle;
156
157 }
158
159 1;
160