File Coverage

lib/Devel/Trepan/IO/FIFOServer.pm
Criterion Covered Total %
statement 27 77 35.0
branch 0 26 0.0
condition 0 3 0.0
subroutine 9 18 50.0
pod 0 9 0.0
total 36 133 27.0


line stmt bran cond sub pod time code
1             # -*- coding: utf-8 -*-
2             # Copyright (C) 2014 Rocky Bernstein <rocky@cpan.org>
3             # Debugger Server Input/Output FIFO interface.
4              
5 12     12   5234 use warnings; use strict;
  12     12   35  
  12         368  
  12         65  
  12         26  
  12         377  
6              
7 12     12   61 use rlib '../../..';
  12         29  
  12         66  
8              
9             package Devel::Trepan::IO::FIFOServer;
10              
11 12     12   3808 use English qw ( -no_match_vars );
  12         28  
  12         103  
12 12     12   4457 use Fcntl;
  12         35  
  12         3072  
13 12     12   86 use Devel::Trepan::IO::TCPPack;
  12         31  
  12         651  
14 12     12   73 use Devel::Trepan::Util qw(hash_merge);
  12         33  
  12         599  
15              
16             # use File::Temp qw(tempdir);
17             # use File::Spec::Functions qw(catfile);
18 12     12   74 use POSIX qw(mkfifo);
  12         29  
  12         79  
19              
20 12         12676 use constant DEFAULT_INIT_OPTS => {
21             open => 1,
22             logger => undef, # Complaints should be sent here.
23              
24             # input and output names are the reverse of the client
25             input_name => '/tmp/trepanpl.inputfifo',
26             input_mode => 0777,
27             input => undef,
28             output_name => '/tmp/trepanpl.outputfifo',
29             output_mode => 0777,
30             output => undef,
31              
32             reuse => 1,
33              
34             # name_pat pattern to go into tmmname
35 12     12   1090 };
  12         35  
36              
37             sub new($;$)
38             {
39 0     0 0   my ($class, $opts) = @_;
40 0           $opts = hash_merge($opts, DEFAULT_INIT_OPTS);
41             my $self = {
42             input => undef,
43             input_name => $opts->{input_name},
44             input_mode => $opts->{input_mode},
45             output => undef,
46             output_name => $opts->{output_name},
47             output_mode => $opts->{output_mode},
48             state => 'uninit',
49             logger => $opts->{logger},
50 0           line_edit => 0
51             };
52 0           bless $self, $class;
53 0 0         $self->open($opts) if $opts->{open};
54 0           return $self;
55             }
56              
57             sub is_connected($)
58             {
59 0     0 0   my $self = shift;
60             $self->{state} = 'connected' if
61 0 0 0       $self->{input} and $self->{output};
62 0           return $self->{state} eq 'connected';
63             }
64              
65             sub is_interactive($) {
66 0     0 0   0;
67             }
68              
69              
70             sub have_term_readline($)
71             {
72 0     0 0   return 0;
73             }
74              
75             # Closes server connection.
76             # FIXME dry with FIFOClient by making a common FIFO routine
77             sub close
78             {
79 0     0 0   my $self = shift;
80 0           $self->{state} = 'closing';
81 0           foreach my $FIFO ( $self->{input}, $self->{output} ) {
82 0 0         close($FIFO) if $FIFO;
83             }
84 0           $self->{state} = 'uninit';
85 0           $self->{input} = $self->{output} = undef;
86 0 0         print {$self->{logger}} "Disconnected FIFO server\n" if $self->{logger};
  0            
87             }
88              
89             sub open($;$)
90             {
91 0     0 0   my ($self, $opts) = @_;
92 0           $opts = hash_merge($self, $opts);
93              
94 0           foreach my $tuple ( [$opts->{input_name}, $opts->{input_mode}],
95             [$opts->{output_name}, $opts->{output_mode}] ) {
96 0           my ($named_pipe, $create_mode) = @$tuple;
97 0 0         if ( -p $named_pipe ) {
98 0 0         die "FIFO $named_pipe already exists" unless $opts->{reuse};
99             } else {
100 0 0         POSIX::mkfifo($named_pipe, $create_mode)
101             or die "mkfifo($named_pipe) failed: $!";
102             }
103             }
104 0 0         sysopen($self->{output}, $self->{output_name}, O_RDWR) or
105             die "Can't open $self->{output_name} for writing; $!";
106              
107             # Flush output as soon as possbile (autoflush).
108 0           my $oldfh = select($self->{output});
109 0           $OUTPUT_AUTOFLUSH = 1;
110 0           select($oldfh);
111              
112 0           $self->{state} = 'listening';
113             }
114              
115             # Read one message unit.
116             # EOFError will be raised on EOF.
117             sub read_msg($)
118             {
119 0     0 0   my($self) = @_;
120 0           my $fh = $self->{input};
121 0 0         unless ($fh) {
122 0 0         print {$self->{logger}} "read on disconnected input\n" if $self->{logger};
  0            
123 0           return '';
124             }
125             # print "+++ server self input ($self->{input_name}) ", $fh, "\n";
126 0           my $msg;
127 0 0         unless (eof($fh)) {
128 0           $msg = <$fh>;
129             }
130 0 0         if ($msg ne '-1') {
131 0           return unpack_msg($msg);
132             } else {
133 0 0         print {$self->{logger}} "Client disconnected\n" if $self->{logger};
  0            
134 0           return unpack_msg('');
135 0           die "Remote has closed connection";
136             }
137             }
138              
139             # This method the debugger uses to write. In contrast to
140             # writeline, no newline is added to the } to `str'. Also
141             # msg doesn't have to be a string.
142             # FIXME dry with FIFOClient by making a common FIFO routine
143             sub write($$)
144             {
145 0     0 0   my($self, $msg) = @_;
146             # print "+++ server self output ($self->{output_name})\n";
147 0           syswrite($self->{output}, pack_msg($msg) . "\n");
148             }
149              
150             # FIXME dry with FIFOClient by making a common FIFO routine
151             sub writeline($$)
152             {
153 0     0 0   my($self, $msg) = @_;
154 0           $self->write($msg . "\n");
155             }
156              
157             # Demo
158             unless (caller) {
159             my $server = __PACKAGE__->new({open => 1, logger=>*STDOUT});
160             if (scalar @ARGV) {
161             require Devel::Trepan::IO::FIFOClient;
162             my $pid = fork();
163             if (scalar @ARGV) {
164             my $pid = fork();
165             if ($pid) {
166             print "Server pid $$...\n";
167             my $client = __PACKAGE__->new({'open' => 1});
168             print "server before write\n";
169             $server->writeline("server to client");
170             print "server before read\n";
171             my $msg = $server->read_msg();
172             print "Server read from client message: $msg\n";
173             print "server before second write\n";
174             $server->write("server to client nocr");
175             print "Server $$ is done but waiting on client $pid\n";
176             waitpid($pid, 0);
177             $server->close();
178             print "Server is leaving\n";
179             } else {
180             print "Client pid $$...\n";
181             my $client = Devel::Trepan::IO::FIFOClient->new({'open'=> 1});
182             print "client before read\n";
183             my $msg = $client->read_msg();
184             print "Client read from server message: $msg\n";
185             $client->writeline("client to server");
186             print "client before second read\n";
187             $msg = $client->read_msg();
188             print "Client read from server message: $msg\n";
189             print "Client is leaving\n";
190             $client->close();
191             }
192             } else {
193             my $client = __PACKAGE__->new({'open' => 1});
194             $client->close();
195             }
196             }
197             }
198              
199             1;