File Coverage

blib/lib/IO/SessionSet.pm
Criterion Covered Total %
statement 36 77 46.7
branch 5 40 12.5
condition 1 6 16.6
subroutine 11 15 73.3
pod 0 9 0.0
total 53 147 36.0


line stmt bran cond sub pod time code
1             # ======================================================================
2             #
3             # Copyright (C) 2000 Lincoln D. Stein
4             # Formatting changed to match the layout layed out in Perl Best Practices
5             # (by Damian Conway) by Martin Kutter in 2008
6             #
7             # ======================================================================
8              
9             package IO::SessionSet;
10              
11 2     2   711 use strict;
  2         4  
  2         68  
12 2     2   11 use Carp;
  2         4  
  2         138  
13 2     2   2295 use IO::Select;
  2         4126  
  2         109  
14 2     2   2650 use IO::Handle;
  2         20878  
  2         118  
15 2     2   654 use IO::SessionData;
  2         6  
  2         52  
16              
17 2     2   12 use vars '$DEBUG';
  2         4  
  2         1946  
18             $DEBUG = 0;
19              
20             # Class method new()
21             # Create a new Session set.
22             # If passed a listening socket, use that to
23             # accept new IO::SessionData objects automatically.
24             sub new {
25 1     1 0 4 my $pack = shift;
26 1         2 my $listen = shift;
27 1         11 my $self = bless {
28             sessions => {},
29             readers => IO::Select->new(),
30             writers => IO::Select->new(),
31             }, $pack;
32             # if initialized with an IO::Handle object (or subclass)
33             # then we treat it as a listening socket.
34 1 50 33     25 if ( defined($listen) and $listen->can('accept') ) {
35 0         0 $self->{listen_socket} = $listen;
36 0         0 $self->{readers}->add($listen);
37             }
38 1         9 return $self;
39             }
40              
41             # Object method: sessions()
42             # Return list of all the sessions currently in the set.
43             sub sessions {
44 1     1 0 3 return values %{shift->{sessions}}
  1         6  
45             };
46              
47             # Object method: add()
48             # Add a handle to the session set. Will automatically
49             # create a IO::SessionData wrapper around the handle.
50             sub add {
51 0     0 0 0 my $self = shift;
52 0         0 my ($handle,$writeonly) = @_;
53 0 0       0 warn "Adding a new session for $handle.\n" if $DEBUG;
54 0         0 return $self->{sessions}{$handle} =
55             $self->SessionDataClass->new($self,$handle,$writeonly);
56             }
57              
58             # Object method: delete()
59             # Remove a session from the session set. May pass either a handle or
60             # a corresponding IO::SessionData wrapper.
61             sub delete {
62 0     0 0 0 my $self = shift;
63 0         0 my $thing = shift;
64 0         0 my $handle = $self->to_handle($thing);
65 0         0 my $sess = $self->to_session($thing);
66 0 0       0 warn "Deleting session $sess handle $handle.\n" if $DEBUG;
67 0         0 delete $self->{sessions}{$handle};
68 0         0 $self->{readers}->remove($handle);
69 0         0 $self->{writers}->remove($handle);
70             }
71              
72             # Object method: to_handle()
73             # Return a handle, given either a handle or a IO::SessionData object.
74             sub to_handle {
75 1     1 0 2 my $self = shift;
76 1         3 my $thing = shift;
77 1 50       11 return $thing->handle if $thing->isa('IO::SessionData');
78 1 50       29 return $thing if defined (fileno $thing);
79 1         5 return; # undefined value
80             }
81              
82             # Object method: to_session
83             # Return a IO::SessionData object, given either a handle or the object itself.
84             sub to_session {
85 1     1 0 3 my $self = shift;
86 1         2 my $thing = shift;
87 1 50       11 return $thing if $thing->isa('IO::SessionData');
88 1 50       8 return $self->{sessions}{$thing} if defined (fileno $thing);
89 1         4 return; # undefined value
90             }
91              
92             # Object method: activate()
93             # Called with parameters ($session,'read'|'write' [,$activate])
94             # If called without the $activate argument, will return true
95             # if the indicated handle is on the read or write IO::Select set.
96             # May use either a session object or a handle as first argument.
97             sub activate {
98 0     0 0 0 my $self = shift;
99 0         0 my ($thing,$rw,$act) = @_;
100 0 0       0 croak 'Usage $obj->activate($session,"read"|"write" [,$activate])'
101             unless @_ >= 2;
102 0         0 my $handle = $self->to_handle($thing);
103 0 0       0 my $select = lc($rw) eq 'read' ? 'readers' : 'writers';
104 0         0 my $prior = defined $self->{$select}->exists($handle);
105 0 0 0     0 if (defined $act && $act != $prior) {
106 0 0       0 $self->{$select}->add($handle) if $act;
107 0 0       0 $self->{$select}->remove($handle) unless $act;
108 0 0       0 warn $act ? 'Activating' : 'Inactivating',
    0          
    0          
109             " handle $handle for ",
110             $rw eq 'read' ? 'reading':'writing',".\n" if $DEBUG;
111             }
112 0         0 return $prior;
113             }
114              
115             # Object method: wait()
116             # Wait for I/O. Handles writes automatically. Returns a list of
117             # IO::SessionData objects ready for reading.
118             # If there is a listen socket, then will automatically do an accept()
119             # and return a new IO::SessionData object for that.
120             sub wait {
121 0     0 0 0 my $self = shift;
122 0         0 my $timeout = shift;
123              
124             # Call select() to get the list of sessions that are ready for
125             # reading/writing.
126 0 0       0 warn "IO::Select->select() returned error: $!"
127             unless my ($read,$write) =
128             IO::Select->select($self->{readers},$self->{writers},undef,$timeout);
129              
130             # handle queued writes automatically
131 0         0 foreach (@$write) {
132 0         0 my $session = $self->to_session($_);
133 0 0       0 warn "Writing pending data (",$session->pending+0," bytes) for $_.\n"
134             if $DEBUG;
135 0         0 my $rc = $session->write;
136             }
137              
138             # Return list of sessions that are ready for reading.
139             # If one of the ready handles is the listen socket, then
140             # create a new session.
141             # Otherwise return the ready handles as a list of IO::SessionData objects.
142 0         0 my @sessions;
143 0         0 foreach (@$read) {
144 0 0       0 if ($_ eq $self->{listen_socket}) {
145 0         0 my $newhandle = $_->accept;
146 0 0       0 warn "Accepting a new handle $newhandle.\n" if $DEBUG;
147 0 0       0 my $newsess = $self->add($newhandle) if $newhandle;
148 0         0 push @sessions,$newsess;
149             }
150             else {
151 0         0 push @sessions,$self->to_session($_);
152             }
153             }
154 0         0 return @sessions;
155             }
156              
157             # Class method: SessionDataClass
158             # Return the string containing the name of the session data
159             # wrapper class. Subclass and override to use a different
160             # session data class.
161 1     1 0 766 sub SessionDataClass { return 'IO::SessionData'; }
162              
163             1;