/[cwmp]/google/trunk/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/trunk/lib/CWMP/Session.pm

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

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

Legend:
Removed from v.30  
changed lines
  Added in v.40

  ViewVC Help
Powered by ViewVC 1.1.26