/[cwmp]/google/lib/CWMP/Session.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /google/lib/CWMP/Session.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 36 by dpavlin, Tue Jun 19 00:38:49 2007 UTC revision 43 by dpavlin, Tue Jun 19 18:50:28 2007 UTC
# Line 4  package CWMP::Server; Line 4  package CWMP::Server;
4  use strict;  use strict;
5  use warnings;  use warnings;
6    
7  use base qw/HTTP::Server::Simple::CGI Class::Accessor/;  use base qw/Class::Accessor/;
8  __PACKAGE__->mk_accessors( qw/  __PACKAGE__->mk_accessors( qw/
9  debug  debug
10    port
11    sock
12  / );  / );
13    
14    use IO::Socket::INET;
15  use Data::Dump qw/dump/;  use Data::Dump qw/dump/;
16  use CWMP::Request;  use CWMP::Request;
17  use CWMP::Response;  use CWMP::Response;
18  use Carp qw/confess/;  use Carp qw/confess cluck/;
19    
20  =head1 NAME  =head1 NAME
21    
# Line 20  CWMP::Server - implement logic of CWMP p Line 23  CWMP::Server - implement logic of CWMP p
23    
24  =head1 METHODS  =head1 METHODS
25    
26  =head2 handler  =head2 new
27    
28  We override L<HTTP::Server::Simple::CGI/handler> so that we can support    my $server = CWMP::Server->new({ port => 3333 });
29  chunked transfer encoding.  
30    =head2 run
31    
32      $server->run();
33    
34  =cut  =cut
35    
36  sub handler {  sub run {
37      my $self = shift;          my $self = shift;
38    
39      my $chunk;          my $listen = IO::Socket::INET->new(
40                    Listen    => 5,
41    #               LocalAddr => 'localhost',
42                    LocalPort => $self->port,
43                    Proto     => 'tcp',
44                    Blocking  => 1,
45                    ReuseAddr => 1,
46            );
47    
48            warn "waiting for request on port ", $self->port, $/;
49    
50            while ( my $sock = $listen->accept ) {
51                    $sock->autoflush(1);
52    
53                    warn "connection from ", $sock->peerhost, "\n";
54    
55                    $self->sock( $sock );   # FIXME this will not work for multiple clients
56                    while ( $self->process_request ) {
57                            warn "...another one bites a dust...\n";
58                    }
59    
60                    warn "...returning to accepting new connections\n";
61            }
62    }
63    
64    sub process_request {
65            my $self = shift;
66    
67            my $sock = $self->sock || die "no sock?";
68    
69            die "not IO::Socket::INET but ", ref( $sock ) unless ( ref($sock) eq 'IO::Socket::INET' );
70    
71            if ( ! $sock->connected ) {
72                    warn "SOCKET NOT CONNECTED";
73                    return 0;
74            }
75    
76            $sock->autoflush( 1 );
77            $sock->blocking( 1 );
78    
79            ### read the first line of response
80            my $line = $sock->getline || $self->error(400, "No Data");
81    
82            $line =~ s/[\r\n]+$//;
83            if ($line !~ /^ (\w+) \ + (\S+) \ + (HTTP\/1.\d) $ /x) {
84                    return $self->error(400, "Bad request");
85            }
86            my ($method, $req, $protocol) = ($1, $2, $3);
87            warn "<<<< ",join(" ", time, $method, $req)."\n";
88    
89            ### read in other headers
90            $self->read_headers || return $self->error(400, "Strange headers");
91    
92            ### do we support the type
93    #       if ($method !~ /GET|POST|HEAD/) {
94            if ($method !~ /POST/) {
95                    return $self->error(400, "Unsupported Method");
96            }
97    
98        my $chunk;
99          my $transfer_encoding = $self->header('Transfer-Encoding');          my $transfer_encoding = $self->header('Transfer-Encoding');
100    
101          if ( $transfer_encoding && $transfer_encoding =~ qr/^chunked/i ) {          if ( $transfer_encoding && $transfer_encoding =~ qr/^chunked/i ) {
102    
103                  my $len = 0;                  my $len = 0;
                 my $hex;  
                 do {  
                         $hex = <STDIN>;         # get chunk length  
                         $hex =~ s/[\n\r]*$//s;  
                         $len = hex( $hex );  
104    
105                          warn "getting chunk of 0x$hex $len bytes\n" if $self->debug;                  do {
   
                         while( $len > 0 ) {  
                                 my $line = <STDIN>;  
                                 $chunk .= $line;  
                                 $len -= length( $line );  
                         }  
106    
107                  } while ( hex( $hex ) != 0 );                          warn "get chunk len\n" if $self->debug;
108          }                          
109                            my $hex;
110                            do {
111                                    $hex = $sock->getline;
112                                    $hex =~ s/[\n\r]+$//;
113                            } until ( $hex ne '' );
114    
115          warn "handler got ", length($chunk), " bytes\n" if $self->debug;                          die "chunk size not valid hex: $hex" unless ( $hex =~ m/^[0-9a-f]+$/i);
116                            $len = hex( $hex );
117    
118      my $cgi  = new CGI( $chunk );                          warn "getting chunk of $len bytes\n" if $self->debug;
119    
120      eval { $self->handle_request($cgi) };                          $sock->read( my $buff, $len );
121      if ($@) {                          $chunk .= $buff;
         my $error = $@;  
         warn $error;  
     }  
 }  
122    
123  =head2 handle_request                          warn "--- $len bytes: --=>||$buff||<=--\n";
124    
125  Implementation of dispatch logic                  } while ( $len > 0 );
126    
127  =cut          } else {
128                    die "right now, we support only Transfer-Encoding: chunked";
129            }
130    
131  sub handle_request {          warn "handler got ", length($chunk), " bytes\n" if $self->debug;
         my ($self, $cgi) = @_;  
                                                                       
         #... do something, print output to default  
         # selected filehandle...  
132    
133          warn "<<< " . localtime() . " " . $ENV{REMOTE_ADDR} . "\n";          warn "<<< " . localtime() . " " . $sock->peerhost . "\n";
134    
135          warn "not SOAP request" unless defined ( $cgi->header('SOAPAction') );          die "not SOAP request" unless defined ( $self->header('SOAPAction') );
136    
137          my $state;          my $state;
138    
139          if ( my $payload = $cgi->param('POSTDATA') ) {          if ( $chunk ) {
140                  warn "request payload:\n$payload\n" if $self->debug;                  warn "## request chunk: ",length($chunk)," bytes\n$chunk\n" if $self->debug;
141    
142                  $state = CWMP::Request->parse( $payload );                  $state = CWMP::Request->parse( $chunk );
143    
144                  warn "acquired state = ", dump( $state );                  warn "acquired state = ", dump( $state ), "\n";
145                    
146          } else {          } else {
147                  warn "empty request\n";                  warn "empty request\n";
148          }          }
149    
150    
151          my $response = CWMP::Response->new({ debug => $self->debug });          my $response = CWMP::Response->new({ debug => $self->debug });
152    
153          print "Content-Type: text/xml\r\n\r\n";          $sock->send(join("",
154                    $self->status(200,'OK'),
155                    $self->content_type('text/xml; charset="utf-8"'),
156                    "Server: AcmeCWMP/42\r\n",
157                    "SOAPServer: AcmeCWMP/42\r\n"
158            ));
159    
160            $sock->send( "Set-Cookie: ID=" . $state->{ID} . "; path=/\r\n" ) if ( $state->{ID} );
161            
162            my $xml = '';
163    
164          if ( my $dispatch = $state->{_dispatch} ) {          if ( my $dispatch = $state->{_dispatch} ) {
165                  if ( $response->can( $dispatch ) ) {                  if ( $response->can( $dispatch ) ) {
166                          warn ">>> dispatching to $dispatch\n";                          warn ">>> dispatching to $dispatch\n";
167                          print $response->$dispatch;                          $xml = $response->$dispatch( $state ) . "\r\n";
168                            warn "## response payload: ",length($xml)," bytes\n$xml\n";
169                  } else {                  } else {
170                          confess "can't dispatch to $dispatch";                          confess "can't dispatch to $dispatch";
171                  }                  }
172          } else {          } else {
173                  warn ">>> empty response\n";                  warn ">>> empty response\n";
174          }          }
175            
176            $sock->send( "Content-Length: " . length( $xml ) . "\r\n\r\n" );
177            $sock->send( "$xml\r\n\r\n" ) or die "can't send response";
178    
179            warn "### request over";
180    
181  };  };
182    
 1;  
183    
184    sub read_headers {
185      my $self = shift;
186    
187      $self->{headers} = {};
188    
189      while (defined($_ = $self->sock->getline)) {
190        s/[\r\n]+$//;
191        last unless length $_;
192            warn "-- $_\n";
193        return 0 if ! /^ ([\w\-]+) :[\ \t]* (.*) $/x;
194        $self->{headers}->{$1} = $2;
195      }
196    
197      return 1;
198    }
199    
200    sub header {
201            my $self = shift;
202            my $header = shift || die "no header?";
203            if ( defined( $self->{headers}->{$header} )) {
204                    return $self->{headers}->{$header};
205            } else {
206                    return;
207            }
208    }
209    
210    sub content_type {
211      my ($self, $type) = @_;
212      $self->http_header;
213      return "Content-type: $type\r\n";
214    }
215    
216    sub error{
217      my ($self, $number, $msg) = @_;
218      $self->sock->send( $self->status($number, $msg) . "\r\n" );
219      warn "Error - $number - $msg\n";
220    }
221    
222    sub status {
223      my ($self, $number, $msg) = @_;
224      $msg = '' if ! defined $msg;
225      return if $self->http_header($number);
226      return "Status $number: $msg\r\n";
227    }
228    
229    sub http_header {
230      my $self = shift;
231      my $number = shift || 200;
232      return if ! delete $self->{needs_header};
233      $self->sock->send("HTTP/1.1 $number\r\n");
234      return 1;
235    }
236    
237    1;

Legend:
Removed from v.36  
changed lines
  Added in v.43

  ViewVC Help
Powered by ViewVC 1.1.26