6 use Sys::Syslog qw(syslog);
7 use Net::Server::PreFork;
10 use Data::Dumper; # For debugging
11 require UNIVERSAL::require;
13 #use Sip qw(readline);
14 use Sip::Constants qw(:all);
15 use Sip::Configuration;
16 use Sip::Checksum qw(checksum verify_cksum);
19 use constant LOG_SIP => "local6"; # Local alias for the logging facility
21 our @ISA = qw(Net::Server::PreFork);
27 RAW => \&raw_transport,
28 telnet => \&telnet_transport,
29 http => \&http_transport,
34 my $config = new Sip::Configuration $ARGV[0];
41 foreach my $svc (keys %{$config->{listeners}}) {
42 push @parms, "port=" . $svc;
48 push @parms, "log_file=Sys::Syslog", "syslog_ident=acs-server",
49 "syslog_facility=" . LOG_SIP;
52 # Server Management: set parameters for the Net::Server::PreFork
53 # module. The module silently ignores parameters that it doesn't
54 # recognize, and complains about invalid values for parameters
57 if (defined($config->{'server-params'})) {
58 while (my ($key, $val) = each %{$config->{'server-params'}}) {
59 push @parms, $key . '=' . $val;
66 # This is the main event.
67 SIPServer->run(@parms);
73 # process_request is the callback used by Net::Server to handle
74 # an incoming connection request.
80 my ($sockaddr, $port, $proto);
83 $self->{config} = $config;
85 $sockname = getsockname(STDIN);
86 ($port, $sockaddr) = sockaddr_in($sockname);
87 $sockaddr = inet_ntoa($sockaddr);
88 $proto = $self->{server}->{client}->NS_proto();
90 $self->{service} = $config->find_service($sockaddr, $port, $proto);
92 if (!defined($self->{service})) {
93 syslog("LOG_ERR", "process_request: Unknown recognized server connection: %s:%s/%s", $sockaddr, $port, $proto);
94 die "process_request: Bad server connection";
97 $transport = $transports{$self->{service}->{transport}};
99 if (!defined($transport)) {
100 syslog("LOG_WARN", "Unknown transport '%s', dropping", $service->{transport});
115 my $service = $self->{service};
121 local $SIG{ALRM} = sub { die "alarm\n"; };
122 syslog("LOG_DEBUG", "raw_transport: timeout is %d",
123 $service->{timeout});
125 alarm $service->{timeout};
126 $input = Sip::read_SIP_packet(*STDIN);
130 syslog("LOG_INFO", "raw_transport: shutting down: EOF during login");
134 $input =~ s/[\r\n]+$//sm; # Strip off trailing line terminator
136 last if Sip::MsgType::handle($input, $self, LOGIN);
141 syslog("LOG_ERR", "raw_transport: LOGIN ERROR: '$@'");
142 die "raw_transport: login error, exiting";
143 } elsif (!$self->{account}) {
144 syslog("LOG_ERR", "raw_transport: LOGIN FAILED");
145 die "raw_transport: Login failed, exiting";
148 syslog("LOG_DEBUG", "raw_transport: uname/inst: '%s/%s'",
149 $self->{account}->{id},
150 $self->{account}->{institution});
152 $self->sip_protocol_loop();
154 syslog("LOG_INFO", "raw_transport: shutting down");
157 sub telnet_transport {
163 my $config = $self->{config};
165 # Until the terminal has logged in, we don't trust it
166 # so use a timeout to protect ourselves from hanging.
168 local $SIG{ALRM} = sub { die "alarm\n"; };
171 $| = 1; # Unbuffered output
172 $timeout = $config->{timeout} if (exists($config->{timeout}));
185 $uid =~ s/[\r\n]+$//;
186 $pwd =~ s/[\r\n]+$//;
188 if (exists($config->{accounts}->{$uid})
189 && ($pwd eq $config->{accounts}->{$uid}->password())) {
190 $account = $config->{accounts}->{$uid};
193 syslog("LOG_WARNING", "Invalid login attempt: '%s'", $uid);
194 print("Invalid login\n");
200 syslog("LOG_ERR", "telnet_transport: Login timed out");
201 die "Telnet Login Timed out";
202 } elsif (!defined($account)) {
203 syslog("LOG_ERR", "telnet_transport: Login Failed");
206 print "Login OK. Initiating SIP\n";
209 $self->{account} = $account;
211 $self->sip_protocol_loop();
212 syslog("LOG_INFO", "telnet_transport: shutting down");
220 # The terminal has logged in, using either the SIP login process
221 # over a raw socket, or via the pseudo-unix login provided by the
222 # telnet transport. From that point on, both the raw and the telnet
223 # processes are the same:
224 sub sip_protocol_loop {
227 my $service = $self->{service};
228 my $config = $self->{config};
230 # Now that the terminal has logged in, the first message
231 # we recieve must be an SC_STATUS message. But it might be
232 # an SC_REQUEST_RESEND. So, as long as we keep receiving
233 # SC_REQUEST_RESEND, we keep waiting for an SC_STATUS
235 # Comprise reports that no other ILS actually enforces this
236 # constraint, so we'll relax about it too. As long as everybody
237 # uses the SIP "raw" login process, rather than telnet, this
238 # will be fine, becaues the LOGIN protocol exchange will force
239 # us into SIP 2.00 anyway. Machines that want to log in using
240 # telnet MUST send an SC Status message first, even though we're
243 #$expect = SC_STATUS;
246 while ($input = Sip::read_SIP_packet(*STDIN)) {
249 $input =~ s/[\r\n]+$//sm; # Strip off any trailing line ends
251 $status = Sip::MsgType::handle($input, $self, $expect);
252 next if $status eq REQUEST_ACS_RESEND;
253 #### stopped here rch
255 syslog("LOG_ERR", "raw_transport: failed to handle %s",
256 substr($input, 0, 2));
257 die "raw_transport: dying";
258 } elsif ($expect && ($status ne $expect)) {
259 # We received a non-"RESEND" that wasn't what we were
262 "raw_transport: expected %s, received %s, exiting",
264 die "raw_transport: exiting: expected '$expect', received '$status'";
266 # We successfully received and processed what we were expecting