File Coverage

blib/lib/Net/Socket/NonBlock.pm
Criterion Covered Total %
statement 158 316 50.0
branch 43 164 26.2
condition 20 149 13.4
subroutine 23 43 53.4
pod 15 15 100.0
total 259 687 37.7


line stmt bran cond sub pod time code
1             package Net::Socket::NonBlock;
2              
3 1     1   610055 use strict;
  1         3  
  1         43  
4              
5             #$^W++;
6              
7 1     1   4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         3  
  1         215  
8              
9             require Exporter;
10              
11             @ISA = qw(Exporter);
12              
13             %EXPORT_TAGS = ();
14              
15             foreach (keys(%EXPORT_TAGS))
16             { push(@{$EXPORT_TAGS{'all'}}, @{$EXPORT_TAGS{$_}}); };
17              
18             $EXPORT_TAGS{'all'}
19             and @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
20              
21             @EXPORT = qw(
22             );
23              
24             $VERSION = '0.15';
25              
26 1     1   5 use Carp;
  1         6  
  1         70  
27 1     1   1018 use IO::Select;
  1         2278  
  1         63  
28 1     1   1142 use IO::Socket;
  1         43015  
  1         5  
29              
30             # Preloaded methods go here.
31              
32             my $ThrowMsg = sub($$$)
33             {
34             my ($Nest, $CarpCond, $Msg) = @_;
35              
36             $CarpCond
37             and Carp::carp $Msg;
38              
39             ($Nest && $Nest->{'ErrArray'})
40             and push(@{$Nest->{'ErrArray'}}, $Msg);
41              
42             return 1;
43             };
44              
45             sub newNest
46 0     0 1 0 { shift; return Net::Socket::NonBlock::Nest->new(@_); };
  0         0  
47             sub new
48 1     1 1 153 { shift; return Net::Socket::NonBlock::Nest->new(@_); };
  1         10  
49              
50             my $Die = sub($)
51             { Carp::confess $_[0]; };
52              
53             my $BuffSize = sub($$)
54             {
55             my ($SRec, $BuffName) = @_;
56             ($SRec->{$BuffName})
57             or &{$Die}("$SRec: buffer '$BuffName' does not exists");
58              
59             my $Result = 0;
60             foreach (@{$SRec->{$BuffName}})
61             { $Result += length($_->{'Data'}); };
62              
63             return $Result;
64             };
65              
66             my $BuffEmpty = sub($$)
67             {
68             my ($SRec, $BuffName) = @_;
69             ($SRec->{$BuffName})
70             or &{$Die}("$SRec: buffer '$BuffName' does not exists");
71              
72             if ($SRec->{'TCP'})
73             { return (!length($SRec->{$BuffName}->[0]->{'Data'})); };
74              
75             return (!scalar(@{$SRec->{$BuffName}}));
76             };
77              
78             my $SockAvail = sub($)
79             {
80             my ($SRec) = @_;
81              
82             ($SRec->{'Close'} || ($SRec->{'EOF'} && &{$BuffEmpty}($SRec, 'Input')))
83             or return $SRec;
84            
85             $@ = $SRec->{'Error'};
86             return;
87             };
88              
89             my $CloseSR = sub($)
90             {
91             my ($SRec) = @_;
92              
93             $SRec->{'Socket'}
94             and $SRec->{'Socket'}->close();
95             delete($SRec->{'Socket'});
96              
97             $SRec->{'Parent'}
98             and $SRec->{'Parent'}{'Clients'}--;
99             delete($SRec->{'Parent'});
100              
101             return 1;
102             };
103              
104             my $Close = sub($$)
105             {
106             my ($Nest, $SRec) = @_;
107              
108             $SRec->{'Socket'}
109             and $Nest->{'Select'}->remove($SRec->{'Socket'});
110             delete($Nest->{'S2Rec'}{$SRec->{'Socket'}});
111             delete($Nest->{'Pool'}{$SRec});
112             &{$CloseSR}($SRec);
113              
114             return 1;
115             };
116              
117             my $EOF = sub($$$)
118             {
119             my ($Nest, $SRec, $Error) = @_;
120             $SRec->{'EOF'}++;
121             if (length($Error))
122             {
123             $SRec->{'Error'} = $Error;
124             $@ = $Error;
125             &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: $Error");
126             };
127             $Nest->{'Select'}->remove($SRec->{'Socket'});
128             return;
129             };
130              
131             sub Gets
132             {
133 4     4 1 7 my ($SRec, $BufLen) = @_;
134              
135 4 50       8 &{$SockAvail}($SRec)
  4         15  
136             or return;
137              
138 4 50 33     34 ($BufLen && $BufLen > 0 && $BufLen < 32767 && $BufLen < $SRec->{'BuffSize'})
    0 33        
      0        
139             or $BufLen = ($SRec->{'BuffSize'} < 32767) ? $SRec->{'BuffSize'} : 32766;
140              
141 4         8 $BufLen--;
142              
143 4         28 my @Result = ('', '', '');
144              
145 4 50       20 if ($SRec->{'Input'}->[0])
146             {
147 4 50 66     170 if (($SRec->{'Input'}->[0]->{'Data'} =~ s/\A(.{0,$BufLen}\n)//m) ||
      33        
      66        
148             ($SRec->{'Input'}->[0]->{'Data'} =~ s/\A(.{$BufLen}.)//m ) ||
149             ($SRec->{'EOF'} && ($SRec->{'Input'}->[0]->{'Data'} =~ s/\A([.\n]+)//m)))
150             {
151 2         10 $SRec->{'PeerAddr'} = $SRec->{'Input'}->[0]->{'PeerAddr'};
152 2         7 $SRec->{'PeerPort'} = $SRec->{'Input'}->[0]->{'PeerPort'};
153 2         20 @Result = ($1, $SRec->{'PeerAddr'}, $SRec->{'PeerPort'});
154             };
155              
156 4 0 33     33 if (!$SRec->{'TCP'} &&
157             !length($SRec->{'Input'}->[0]->{'Data'}))
158             {
159 0         0 shift(@{$SRec->{'Input'}});
  0         0  
160             };
161             };
162              
163 4 50       36 return wantarray ? @Result : $Result[0];
164             };
165              
166             sub Read
167             {
168 0     0 1 0 my ($SRec, $BufLen) = @_;
169              
170 0 0       0 &{$SockAvail}($SRec)
  0         0  
171             or return;
172              
173 0 0 0     0 ($BufLen && $BufLen > 0 && $BufLen < 32767 && $BufLen < $SRec->{'BuffSize'})
    0 0        
      0        
174             or $BufLen = ($SRec->{'BuffSize'} < 32767) ? $SRec->{'BuffSize'} : 32766;
175              
176 0         0 $BufLen--;
177              
178 0         0 my @Result = ('', '', '');
179              
180 0 0       0 if ($SRec->{'Input'}->[0])
181             {
182 0 0 0     0 if (($SRec->{'Input'}->[0]->{'Data'} =~ s/\A(.{0,$BufLen}\n)//m) ||
183             ($SRec->{'Input'}->[0]->{'Data'} =~ s/\A(.{0,$BufLen}.)//m ))
184             {
185 0         0 $SRec->{'PeerAddr'} = $SRec->{'Input'}->[0]->{'PeerAddr'};
186 0         0 $SRec->{'PeerPort'} = $SRec->{'Input'}->[0]->{'PeerPort'};
187 0         0 @Result = ($1, $SRec->{'PeerAddr'}, $SRec->{'PeerPort'});
188             };
189              
190 0 0 0     0 if (!$SRec->{'TCP'} &&
191             !length($SRec->{'Input'}->[0]->{'Data'}))
192             {
193 0         0 shift(@{$SRec->{'Input'}});
  0         0  
194             };
195             };
196              
197 0 0       0 return wantarray ? @Result : $Result[0];
198             };
199              
200             sub Recv
201             {
202 0     0 1 0 my ($SRec, $BufLen) = @_;
203              
204 0 0       0 &{$SockAvail}($SRec)
  0         0  
205             or return;
206              
207 0 0 0     0 ($BufLen && $BufLen > 0 && $BufLen < $SRec->{'BuffSize'})
      0        
208             or $BufLen = $SRec->{'BuffSize'};
209            
210 0         0 my @Result = ('', '', '');
211              
212 0 0       0 if ($SRec->{'Input'}->[0])
213             {
214 0         0 $SRec->{'PeerAddr'} = $SRec->{'Input'}->[0]->{'PeerAddr'};
215 0         0 $SRec->{'PeerPort'} = $SRec->{'Input'}->[0]->{'PeerPort'};
216 0         0 @Result = (substr($SRec->{'Input'}->[0]->{'Data'}, 0, $BufLen),
217             $SRec->{'PeerAddr'}, $SRec->{'PeerPort'});
218 0         0 substr($SRec->{'Input'}->[0]->{'Data'}, 0, $BufLen) = '';
219              
220 0 0 0     0 if (!$SRec->{'TCP'} &&
221             !length($SRec->{'Input'}->[0]->{'Data'}))
222             {
223 0         0 shift(@{$SRec->{'Input'}});
  0         0  
224             };
225             };
226              
227 0 0       0 return wantarray ? @Result : $Result[0];
228             };
229              
230             sub Puts
231             {
232 2     2 1 36 my ($SRec, $Data, $PeerAddr, $PeerPort) = @_;
233              
234 2 50       5 &{$SockAvail}($SRec)
  2         7  
235             or return;
236              
237 2 50       9 if ($SRec->{'TCP'})
238             {
239 2 50       9 defined($SRec->{'Output'}->[0]->{'Data'})
240             or $SRec->{'Output'}->[0]->{'Data'} = '';
241 2 50       11 $SRec->{'Output'}->[0]->{'Data'} .= ((ref($Data) eq 'ARRAY') ? join('', @{$Data}) : $Data);
  0         0  
242 2         8 $SRec->{'Output'}->[0]->{'Dest'} = undef;
243             }
244             else
245             {
246 0 0       0 defined($PeerAddr)
247             or $PeerAddr = $SRec->{'PeerAddr'};
248 0 0       0 defined($PeerPort)
249             or $PeerPort = $SRec->{'PeerPort'};
250            
251 0         0 my $PeerIP = inet_aton($PeerAddr);
252 0         0 my $Dest = pack_sockaddr_in($PeerPort, $PeerIP);
253 0 0 0     0 (defined($PeerIP) && defined($Dest))
      0        
254             or $@ = "$SRec: invalid destination address '$PeerAddr:$PeerPort'"
255             and return;
256 0 0       0 push(@{$SRec->{'Output'}}, {'Data' => ((ref($Data) eq 'ARRAY') ? join('', @{$Data}) : $Data), 'Dest' => $Dest});
  0         0  
  0         0  
257             };
258 2         6 return 1;
259             };
260              
261             sub Send
262 0     0 1 0 { return Puts(@_); };
263              
264             sub PeerAddr
265             {
266 0     0 1 0 my ($SRec) = @_;
267              
268 0 0       0 &{$SockAvail}($SRec)
  0         0  
269             or return;
270 0         0 return $SRec->{'PeerAddr'};
271             };
272              
273             sub PeerPort
274             {
275 0     0 1 0 my ($SRec) = @_;
276              
277 0 0       0 &{$SockAvail}($SRec)
  0         0  
278             or return;
279            
280 0         0 return $SRec->{'PeerPort'};
281             };
282              
283             sub LocalAddr
284             {
285 0     0 1 0 my ($SRec) = @_;
286              
287 0 0       0 &{$SockAvail}($SRec)
  0         0  
288             or return;
289            
290 0         0 return $SRec->{'LocalAddr'};
291             };
292              
293             sub LocalPort
294             {
295 1     1 1 2 my ($SRec) = @_;
296              
297 1 50       2 &{$SockAvail}($SRec)
  1         7  
298             or return;
299            
300 1         7 return $SRec->{'LocalPort'};
301             };
302              
303             sub Handle
304             {
305 0     0 1 0 my ($SRec) = @_;
306              
307 0 0       0 &{$SockAvail}($SRec)
  0         0  
308             or return;
309            
310 0         0 return $SRec->{'Socket'};
311             };
312              
313             sub Properties
314             {
315 0     0 1 0 my ($SRec, %Params) = @_;
316              
317 0 0       0 &{$SockAvail}($SRec)
  0         0  
318             or return;
319              
320 0         0 my %Result = ();
321              
322 0         0 $Result{'Handle'} = $SRec->{'Socket'};
323              
324 0         0 my $Key = undef;
325 0         0 foreach $Key ('Socket', 'SilenceT', 'BuffSize', 'MaxClients',
326             'ClientsST', 'Clients', 'Parent',
327             'BytesOut', 'CTime', 'ATime', 'Proto',
328             'BytesIn', 'Accept', 'PeerAddr', 'PeerPort',
329             'LocalAddr', 'LocalPort', 'Error', 'DiscEmpty')
330             {
331 0 0       0 defined($SRec->{$Key})
332             and $Result{$Key} = $SRec->{$Key};
333             };
334              
335 0         0 foreach $Key ('Input', 'Output')
336 0         0 { $Result{$Key} = &{$BuffSize}($SRec, $Key); };
  0         0  
337              
338 0 0       0 $Result{'Broadcast'} = ($SRec->{'Socket'}->sockopt(SO_BROADCAST) ? 1 : 0);
339              
340 0         0 foreach $Key ('SilenceT', 'BuffSize', 'MaxClients', 'ClientsST', 'ATime', 'Accept', 'DiscEmpty')
341             {
342 0 0 0     0 (defined($Params{$Key}) && defined($SRec->{$Key}))
343             and $SRec->{$Key} = $Params{$Key};
344             };
345              
346 0 0       0 defined($Params{'Broadcast'})
    0          
347             and $SRec->{'Socket'}->sockopt(SO_BROADCAST, ($Params{'Broadcast'} ? 1 : 0));
348            
349 0 0       0 return wantarray ? %Result : \%Result;
350             };
351              
352             sub Close
353             {
354 3     3 1 6 my ($SRec, $Flush, $Timeout) = @_;
355              
356 3         4 $SRec->{'Close'}++;
357 3         7 $SRec->{'Flush'} = $Flush;
358 3 50 33     10 ($Flush && $Timeout)
359             and $SRec->{'CloseAt'} = time() + $Timeout;
360 3         10 return;
361             };
362              
363             sub close
364 0     0 1 0 { Net::Socket::NonBlock::Close(@_); };
365              
366             #################################################################################
367             #################################################################################
368             #################################################################################
369             #################################################################################
370              
371             package Net::Socket::NonBlock::Nest;
372              
373 1     1   16506 use IO::Socket;
  1         2  
  1         8  
374 1     1   2667 use POSIX;
  1         12194  
  1         8  
375              
376             sub new($%)
377             {
378 1     1   5 my ($class, %Params) = @_;
379              
380 1         3 my $Nest = {};
381              
382 1 50       9 $Nest->{'Select'} = IO::Select->new()
383             or return;
384 1         17 $Nest->{'Pool'} = {};
385 1 50       5 $Nest->{'SelectT'} = (defined($Params{'SelectT'}) ? $Params{'SelectT'} : 0.05);
386 1 50       4 $Nest->{'SilenceT'} = (defined($Params{'SilenceT'}) ? $Params{'SilenceT'} : 0);
387 1 50       8 $Nest->{'BuffSize'} = (defined($Params{'BuffSize'}) ? $Params{'BuffSize'} : POSIX::BUFSIZ);
388 1 50       4 $Nest->{'MaxClients'} = (defined($Params{'MaxClients'}) ? $Params{'MaxClients'} : 9999999999);
389 1 50       4 $Nest->{'debug'} = (defined($Params{'debug'}) ? $Params{'debug'} : 0);
390 1         4 $Nest->{'class'} = $class;
391 1         5 return bless $Nest => $class;
392             };
393              
394             sub newNest
395 0     0   0 { shift; return Net::Socket::NonBlock::Nest->new(@_); };
  0         0  
396              
397             sub Properties
398             {
399 2 50 33 2   14 if (!(scalar(@_) & 1) &&
400             ($_[1] =~ m/\ANet\:\:Socket\:\:NonBlock\=HASH\(\w+\)\Z/ois))
401             {
402 0         0 my $Nest = shift;
403 0         0 my $SRec = shift;
404 0         0 $SRec = $Nest->{'Pool'}{$SRec}
405 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
406             and return;
407 0 0       0 return wantarray ? %{scalar($SRec->Properties(@_))} :
  0         0  
408             scalar($SRec->Properties(@_));
409             };
410            
411 2         5 my ($Nest, %Params) = @_;
412              
413 2         5 my %Result = ();
414              
415 2         4 my $Key = undef;
416 2         4 foreach $Key ('SelectT', 'SilenceT', 'BuffSize', 'debug')
417 8 50       25 { $Result{$Key} = defined($Nest->{$Key}) ? $Nest->{$Key} : ''; };
418              
419 2         9 $Result{'Sockets'} = $Nest->{'Select'}->count();
420              
421 2         11 foreach $Key ('SelectT', 'SilenceT', 'BuffSize', 'debug')
422             {
423 8 50       17 defined($Params{$Key})
424             and $Nest->{$Key} = $Params{$Key};
425             };
426              
427 2 50       10 return wantarray ? %Result : \%Result;
428             };
429              
430             sub NestProperties
431 2 50   2   89 { return wantarray ? %{scalar(Properties(@_))} : scalar(Properties(@_)); };
  0         0  
432              
433             my $Cleanup = sub($$)
434             {
435             my ($Nest, $SRec) = @_;
436              
437             ($SRec->{'Socket'} && $Nest->{'Pool'}{$SRec})
438             or &{$Die}("$SRec: bad socket");
439              
440             my $CurTime = time();
441              
442             if ($SRec->{'Close'})
443             {
444             if (!$SRec->{'Flush'})
445             {
446             &{$ThrowMsg}($Nest, $Nest->{'debug'}, $SRec->{'Proto'}." socket $SRec closed by request");
447             &{$Close}($Nest, $SRec);
448             return;
449             }
450             elsif (&{$BuffEmpty}($SRec, 'Output'))
451             {
452             &{$ThrowMsg}($Nest, $Nest->{'debug'}, $SRec->{'Proto'}." socket $SRec closed after flush");
453             &{$Close}($Nest, $SRec);
454             return;
455             }
456             elsif ($SRec->{'CloseAt'} && ($SRec->{'CloseAt'} < $CurTime))
457             {
458             &{$ThrowMsg}($Nest, $Nest->{'debug'}, $SRec->{'Proto'}." socket $SRec closed by flush timeout");
459             &{$Close}($Nest, $SRec);
460             return;
461             };
462             }
463             elsif ($SRec->{'SilenceT'} &&
464             ($SRec->{'SilenceT'} < ($CurTime - $SRec->{'ATime'})) &&
465             &{$BuffEmpty}($SRec, 'Input') &&
466             &{$BuffEmpty}($SRec, 'Output'))
467             {
468             &{$EOF}($Nest, $SRec, "silence timeout occurred");
469             return;
470             };
471             return sprintf("$SRec: %d in, %d out", &{$BuffSize}($SRec, 'Input'), &{$BuffSize}($SRec, 'Output'));
472             };
473              
474             my $NonBlock = sub($)
475             {
476             #if ( $^O ne 'MSWin32')
477             # {
478             # my $Flags = fcntl($_[0], F_GETFL(), 0)
479             # or &{$Die}("Can not get flags for socket: $!");
480             # fcntl($_[0], F_SETFL(), $Flags | O_NONBLOCK())
481             # or &{$Die}("Can not make socket non-blocking: $!");
482             # };
483             return $_[0];
484             };
485              
486             my $UpdatePeer = sub($$)
487             {
488             my ($SRec, $Sock) = @_;
489             my $PeerName = $Sock->peername;
490             if (defined($PeerName))
491             {
492             ($SRec->{'PeerPort'}, $SRec->{'PeerAddr'}) = unpack_sockaddr_in($PeerName);
493             $SRec->{'PeerAddr'} = inet_ntoa($SRec->{'PeerAddr'});
494             }
495             else
496             {
497             $SRec->{'PeerAddr'} = '';
498             $SRec->{'PeerPort'} = '';
499             };
500             return;
501             };
502              
503             my $NewSRec = sub($$$%)
504             {
505             my ($Nest, $Socket, $CTime, $Params) = @_;
506              
507             $Params->{'Proto'} =~ m/\A\s*(.*)\s*\Z/;
508             $Params->{'Proto'} = "\U$1";
509             my $SRec = {'Socket' => $Socket,
510             'SilenceT' => (defined($Params->{'SilenceT'}) ? $Params->{'SilenceT'} : $Nest->{'SilenceT'}),
511             'BuffSize' => (defined($Params->{'BuffSize'}) ? $Params->{'BuffSize'} : $Nest->{'BuffSize'}),
512             'MaxClients' => (defined($Params->{'MaxClients'}) ? $Params->{'MaxClients'} : $Nest->{'MaxClients'}),
513             'ClientsST' => (defined($Params->{'ClientsST'}) ? $Params->{'ClientsST'} : $Nest->{'SilenceT'}),
514             'Clients' => 0,
515             'Parent' => '',
516             'BytesIn' => 0,
517             'BytesOut' => 0,
518             'CTime' => $CTime,
519             'ATime' => $CTime,
520             'Proto' => $Params->{'Proto'},
521             'TCP' => ($Params->{'Proto'} eq 'TCP'),
522             'Accept' => $Params->{'Accept'},
523             'PeerAddr' => '',
524             'PeerPort' => '',
525             'LocalAddr' => '',
526             'LocalPort' => '',
527             'Input' => [],
528             'Output' => [],
529             'Close' => 0,
530             'Flush' => 0,
531             'CloseAt' => 0,
532             'Error' => '',
533             'DiscEmpty' => $Params->{'DiscEmpty'},
534             };
535              
536             &{$UpdatePeer}($SRec, $Socket);
537              
538             my $SockName = $Socket->sockname;
539             if (defined($SockName))
540             {
541             ($SRec->{'LocalPort'}, $SRec->{'LocalAddr'}) = unpack_sockaddr_in($SockName);
542             $SRec->{'LocalAddr'} = inet_ntoa($SRec->{'LocalAddr'});
543             };
544              
545             if ($SRec->{'TCP'})
546             {
547             $SRec->{'Output'}->[0]->{'Data'} = '';
548             $SRec->{'Input'}->[0]->{'Data'} = '';
549             $SRec->{'Input'}->[0]->{'PeerAddr'} = $SRec->{'PeerAddr'};
550             $SRec->{'Input'}->[0]->{'PeerPort'} = $SRec->{'PeerPort'};
551             };
552              
553             defined($Params->{'Broadcast'})
554             and $SRec->{'Socket'}->sockopt(SO_BROADCAST, ($Params->{'Broadcast'} ? 1 : 0));
555              
556             #return wantarray ? %{$SRec} : $SRec;
557             return bless $SRec => 'Net::Socket::NonBlock';
558             };
559              
560             my $AddSock = sub
561             {
562             my ($Nest, $newSock, $Params) = @_;
563              
564             $newSock or return;
565              
566             my $newSRec = &{$NewSRec}($Nest, $newSock, time(), $Params);
567            
568             ($Nest->{'Pool'}{$newSRec} || $Nest->{'S2Rec'}{$newSock})
569             and &{$Die}("Socket '$newSRec' already in use");
570              
571             $Nest->{'Select'}->add(&{$NonBlock}($newSock))
572             or $newSock->close()
573             and $@ = "Can not add socket to select: $@"
574             and return;
575            
576             $Nest->{'Pool'}{$newSRec} = $newSRec;
577              
578             $Nest->{'S2Rec'}{$newSock} = $newSRec;
579              
580             return $newSRec;
581             };
582              
583             my $Accept = sub($$)
584             {
585             my ($Nest, $PRec) = @_;
586              
587             ($PRec->{'Socket'} && $Nest->{'Pool'}{$PRec})
588             or &{$Die}("$PRec: bad socket");
589              
590             if (!($PRec->{'Clients'} < $PRec->{'MaxClients'}))
591             {
592             $@ = "maximum number of clients exceeded";
593             return;
594             };
595              
596             my $newSRec = &{$AddSock}($Nest, scalar($PRec->{'Socket'}->accept()), $PRec)
597             or return;
598              
599             $PRec->{'Clients'}++;
600             $Nest->{'Pool'}{$newSRec} = $newSRec;
601             $Nest->{'S2Rec'}{$newSRec->{'Socket'}} = $newSRec;
602             $newSRec->{'Accept'} = undef;
603             $newSRec->{'SilenceT'} = $PRec->{'ClientsST'};
604             $newSRec->{'Parent'} = $PRec;
605              
606             if(!&{$PRec->{'Accept'}}($newSRec))
607             {
608             $newSRec->{'Close'}++;
609             $@ = "external accept function returned a FALSE value";
610             return;
611             };
612              
613             return $newSRec;
614             };
615              
616             my $RecvTCP = sub($$$)
617             {
618             my ($Nest, $SRec, $ATime) = @_;
619              
620             ($SRec->{'Socket'} && $Nest->{'Pool'}{$SRec})
621             or &{$Die}("$SRec: bad socket");
622              
623             my $BufAvail = $SRec->{'BuffSize'} - &{$BuffSize}($SRec, 'Input');
624              
625             ($BufAvail > 0)
626             or return 0;
627              
628             my $Buf = '';
629             my $Res = $SRec->{'Socket'}->recv($Buf, $BufAvail, 0);
630            
631             if (!defined($Res))
632             {
633             &{$EOF}($Nest, $SRec, 'recv() fatal error');
634             return;
635             };
636              
637             if (!length($Buf))
638             {
639             &{$EOF}($Nest, $SRec, 'EOF');
640             return;
641             };
642              
643             $SRec->{'Input'}->[0]->{'Data'} .= $Buf;
644              
645             $SRec->{'ATime'} = $ATime;
646             $SRec->{'BytesIn'} += length($Buf);
647              
648             return length($Buf);
649             };
650              
651             my $RecvUDP = sub($$$)
652             {
653             my ($Nest, $SRec, $ATime) = @_;
654              
655             ($SRec->{'Socket'} && $Nest->{'Pool'}{$SRec})
656             or &{$Die}("$SRec: bad socket");
657              
658             my $BufAvail = $SRec->{'BuffSize'} - &{$BuffSize}($SRec, 'Input');
659             my $Received = 0;
660              
661             my $Sel = IO::Select->new($SRec->{'Socket'});
662             while($Sel->can_read(0) && ($BufAvail > $Received))
663             {
664             my $Buf = '';
665             my $Res = $SRec->{'Socket'}->recv($Buf, $SRec->{'BuffSize'});
666            
667             if (!defined($Res))
668             {
669             &{$EOF}($Nest, $SRec, 'recv() fatal error');
670             return;
671             }
672            
673             (length($Buf) || !$SRec->{'DiscEmpty'})
674             or next;
675              
676             $Received += (length($Buf) + 20);
677             my $tmpHash = {'Data' => $Buf};
678             &{$UpdatePeer}($tmpHash, $SRec->{'Socket'});
679             push(@{$SRec->{'Input'}}, $tmpHash);
680             };
681              
682             $Received
683             and $SRec->{'ATime'} = $ATime;
684              
685             $SRec->{'BytesIn'} += $Received;
686              
687             return $Received;
688             };
689              
690             sub IO($$)
691             {
692 6     6   120 my ($Nest, $ErrArray) = @_;
693              
694 6         13 my $Result = '0 but true';
695              
696 6 50       21 $ErrArray and @{$ErrArray} = ();
  6         14  
697              
698 6         16 $Nest->{'ErrArray'} = $ErrArray;
699              
700 6         11 my $CurTime = time();
701              
702 6         12 my $SRec = undef;
703              
704 6         10 foreach $SRec (values(%{$Nest->{'Pool'}}))
  6         26  
705 17         29 { &{$Cleanup}($Nest, $SRec); };
  17         45  
706              
707 6         14 my $Socket = undef;
708              
709 6         35 my @SockArray = $Nest->{'Select'}->can_read($Nest->{'SelectT'});
710 6         101729 foreach $Socket (@SockArray)
711             {
712 3         13 $SRec = $Nest->{'S2Rec'}{$Socket};
713            
714 3 50 33     28 if ($SRec->{'EOF'} || $SRec->{'Close'} ||
  3   33     9  
715             (&{$BuffSize}($SRec, 'Input') >= $SRec->{'BuffSize'}))
716 0         0 { next; };
717            
718 3 100 66     21 if ($SRec->{'Accept'} && $SRec->{'TCP'})
719             {
720 1         3 $Result++;
721 1         27 &{$Accept}($Nest, $SRec)
  1         3  
722 0         0 and &{$ThrowMsg}(undef, $Nest->{'debug'}, "$SRec: incoming connection accepted")
723 1 50 0     2 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: Can not accept incoming connection: $@");
      33        
724 1         3 $SRec->{'ATime'} = $CurTime;
725 1         4 next;
726             };
727            
728            
729 2 50       6 my ($Res) = &{$SRec->{'TCP'} ? $RecvTCP : $RecvUDP}($Nest, $SRec, $CurTime)
  2 50       17  
730             or next;
731            
732 2         14 &{$ThrowMsg}(undef, $Nest->{'debug'}, "$SRec: recv $Res bytes");
  2         20  
733            
734 2         19 $Result++;
735             };
736              
737 6         21 my $Continue = 1;
738 6         31 while ($Continue)
739             {
740 8         14 $Continue = 0;
741 8         15 my $Socket = undef;
742              
743 8         73 @SockArray = $Nest->{'Select'}->can_write($Nest->{'SelectT'});
744 8         1069 foreach $Socket (@SockArray)
745             {
746 14         57 $SRec = $Nest->{'S2Rec'}{$Socket};
747              
748 14         38 my $OutRec = $SRec->{'Output'}->[0];
749              
750 14 50 33     99 (defined($OutRec) && !$SRec->{'EOF'})
751             or next;
752            
753 14         34 my $DataLen = length($OutRec->{'Data'});
754            
755 14 100 66     82 if (!$DataLen && $SRec->{'TCP'})
756 12         46 { next; }
757              
758 2         8 $Continue++;
759              
760 2         52 my $Res = $Socket->send($OutRec->{'Data'}, 0, $OutRec->{'Dest'});
761              
762 2 50       379 if (!defined($Res))
763             {
764 0         0 &{$EOF}($Nest, $SRec, "send() fatal error");
  0         0  
765 0         0 next;
766             };
767              
768 2 50 33     14 if (!(($Res == $DataLen) || ($! == POSIX::EWOULDBLOCK)))
769             {
770 0 0       0 if ($SRec->{'TCP'})
771             {
772 0         0 &{$EOF}($Nest, $SRec, "send() fatal error");
  0         0  
773 0         0 next;
774             };
775            
776 0         0 my ($DP, $DA) = unpack_sockaddr_in($OutRec->{'Dest'});
777 0         0 $DA = inet_ntoa($DA);
778 0         0 $SRec->{'Error'} = "$SRec: send() error: ".($DataLen - $Res)." bytes were not sent to $DA:$DP";
779 0   0     0 &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), $SRec->{'Error'});
  0         0  
780            
781 0         0 shift(@{$SRec->{'Output'}});
  0         0  
782 0         0 $SRec->{'BytesOut'} += $Res;
783 0         0 next;
784             };
785              
786 2         9 $SRec->{'ATime'} = $CurTime;
787 2         9 $SRec->{'BytesOut'} += $Res;
788            
789 2 50       12 if ($SRec->{'TCP'})
790             {
791 2         14 substr($OutRec->{'Data'}, 0, $Res) = '';
792             }
793             else
794             {
795 0         0 shift(@{$SRec->{'Output'}});
  0         0  
796 0         0 &{$UpdatePeer}($SRec, $Socket);
  0         0  
797             };
798              
799 2         30 &{$ThrowMsg}(undef, ($Nest->{'debug'}), "$SRec: $Res bytes sent to ".$SRec->{'PeerAddr'}.':'.$SRec->{'PeerPort'});
  2         14  
800             };
801             };
802 6         30 return $Result;
803             };
804              
805              
806             sub SelectT
807             {
808 0     0   0 my ($Nest, $SelectT) = @_;
809 0         0 my $Return = $Nest->{'SelectT'};
810 0 0       0 $SelectT and $Nest->{'SelectT'} = $SelectT;
811 0         0 return $Return;
812             };
813              
814             sub SilenceT
815             {
816 0     0   0 my ($Nest, $SilenceT) = @_;
817 0         0 my $Return = $Nest->{'SilenceT'};
818 0 0       0 $SilenceT and $Nest->{'SilenceT'} = $SilenceT;
819 0         0 return $Return;
820             };
821              
822             sub Listen
823             {
824 1     1   23 my ($Nest, %Params) = @_;
825              
826 1 50 33     15 if (($Params{'Proto'} =~ m/\A\s*tcp\s*\Z/io) &&
827             (ref($Params{'Accept'}) ne 'CODE'))
828             {
829 0         0 $@ = "'Accept' have to be a 'CODE' reference";
830 0         0 return;
831             };
832            
833 1 50       14 my $newSRec = &{$AddSock}($Nest, IO::Socket::INET->new(%Params), \%Params)
  1         931  
834             or return;
835              
836 1         6 return $newSRec;
837             };
838              
839             sub Connect
840             {
841 1     1   4 my ($Nest, %Params) = @_;
842            
843 1 50       9 my $newSRec = &{$AddSock}($Nest, IO::Socket::INET->new(%Params), \%Params)
  1         384  
844             or return;
845              
846 1         3 $newSRec->{'Accept'} = undef;
847              
848 1         3 return $newSRec;
849             };
850              
851             sub Gets
852             {
853 4     4   30 my $Nest = shift;
854 4         7 my $SRec = shift;
855 0         0 $Nest->{'Pool'}{$SRec}
856 4 50 0     35 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
857             and return;
858 4         25 return $Nest->{'Pool'}{$SRec}->Gets(@_);
859             };
860             sub Read
861             {
862 0     0   0 my $Nest = shift;
863 0         0 my $SRec = shift;
864 0         0 $Nest->{'Pool'}{$SRec}
865 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
866             and return;
867 0         0 return $Nest->{'Pool'}{$SRec}->Read(@_);
868             };
869             sub Recv
870             {
871 0     0   0 my $Nest = shift;
872 0         0 my $SRec = shift;
873 0         0 $Nest->{'Pool'}{$SRec}
874 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
875             and return;
876 0         0 return $Nest->{'Pool'}{$SRec}->Recv(@_);
877             };
878             sub Puts
879             {
880 2     2   293 my $Nest = shift;
881 2         4 my $SRec = shift;
882 0         0 $Nest->{'Pool'}{$SRec}
883 2 50 0     12 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
884             and return;
885 2         20 return $Nest->{'Pool'}{$SRec}->Puts(@_);
886             };
887             sub Send
888             {
889 0     0   0 my $Nest = shift;
890 0         0 my $SRec = shift;
891 0         0 $Nest->{'Pool'}{$SRec}
892 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
893             and return;
894 0         0 return $Nest->{'Pool'}{$SRec}->Send(@_);
895             };
896             sub PeerAddr
897             {
898 0     0   0 my $Nest = shift;
899 0         0 my $SRec = shift;
900 0         0 $Nest->{'Pool'}{$SRec}
901 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
902             and return;
903 0         0 return $Nest->{'Pool'}{$SRec}->PeerAddr(@_);
904             };
905             sub PeerPort
906             {
907 0     0   0 my $Nest = shift;
908 0         0 my $SRec = shift;
909 0         0 $Nest->{'Pool'}{$SRec}
910 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
911             and return;
912 0         0 return $Nest->{'Pool'}{$SRec}->PeerPort(@_);
913             };
914             sub LocalAddr
915             {
916 0     0   0 my $Nest = shift;
917 0         0 my $SRec = shift;
918 0         0 $Nest->{'Pool'}{$SRec}
919 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
920             and return;
921 0         0 return $Nest->{'Pool'}{$SRec}->LocalAddr(@_);
922             };
923             sub LocalPort
924             {
925 1     1   76 my $Nest = shift;
926 1         2 my $SRec = shift;
927 0         0 $Nest->{'Pool'}{$SRec}
928 1 50 0     4 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
929             and return;
930 1         5 return $Nest->{'Pool'}{$SRec}->LocalPort(@_);
931             };
932             sub Handle
933             {
934 0     0   0 my $Nest = shift;
935 0         0 my $SRec = shift;
936 0         0 $Nest->{'Pool'}{$SRec}
937 0 0 0     0 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
938             and return;
939 0         0 return $Nest->{'Pool'}{$SRec}->Handle(@_);
940             };
941             sub Close
942             {
943 3     3   179 my $Nest = shift;
944 3         5 my $SRec = shift;
945 0         0 $Nest->{'Pool'}{$SRec}
946 3 50 0     14 or &{$ThrowMsg}($Nest, ($^W || $Nest->{'debug'}), "$SRec: bad socket name")
      0        
947             and return;
948 3         15 return $Nest->{'Pool'}{$SRec}->Close(@_);
949             };
950              
951             sub DESTROY
952             {
953 1     1   252 my ($Nest) = @_;
954 1         2 foreach my $SRec (values(%{$Nest->{'Pool'}}))
  1         5  
955 0         0 { &{$Close}($Nest, $SRec); };
  0         0  
956 1         12 delete($Nest->{'Select'});
957 1 50       121 $Nest->{'debug'}
958             and warn "Socket nest $Nest destroyed";
959             };
960              
961             1;
962             __END__