/[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

Annotation of /google/trunk/lib/CWMP/Session.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (hide annotations)
Tue Jun 19 17:29:07 2007 UTC (16 years, 11 months ago) by dpavlin
Original Path: google/lib/CWMP/Server.pm
File size: 4714 byte(s)
skeleton of very simple IO::Socket::INET-based server
1 dpavlin 30 # Dobrica Pavlinusic, <dpavlin@rot13.org> 06/18/07 10:19:50 CEST
2     package CWMP::Server;
3    
4     use strict;
5     use warnings;
6    
7 dpavlin 40 use base qw/Class::Accessor/;
8 dpavlin 30 __PACKAGE__->mk_accessors( qw/
9     debug
10 dpavlin 40 port
11 dpavlin 30 / );
12    
13 dpavlin 40 use IO::Socket::INET;
14 dpavlin 30 use Data::Dump qw/dump/;
15 dpavlin 35 use CWMP::Request;
16     use CWMP::Response;
17 dpavlin 40 use Carp qw/confess cluck/;
18 dpavlin 30
19 dpavlin 34 =head1 NAME
20    
21     CWMP::Server - implement logic of CWMP protocol
22    
23     =head1 METHODS
24    
25 dpavlin 40 =head2 new
26 dpavlin 34
27 dpavlin 40 my $server = CWMP::Server->new({ port => 3333 });
28 dpavlin 34
29 dpavlin 40 =head2 run
30    
31     $server->run();
32    
33 dpavlin 34 =cut
34    
35 dpavlin 40 sub run {
36     my $self = shift;
37 dpavlin 30
38 dpavlin 40 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 dpavlin 30 my $chunk;
91     my $transfer_encoding = $self->header('Transfer-Encoding');
92    
93     if ( $transfer_encoding && $transfer_encoding =~ qr/^chunked/i ) {
94    
95 dpavlin 31 my $len = 0;
96 dpavlin 40
97 dpavlin 30 do {
98    
99 dpavlin 40 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 dpavlin 30
107 dpavlin 40 die "chunk size not valid hex: $hex" unless ( $hex =~ m/^[0-9a-f]+$/i);
108     $len = hex( $hex );
109 dpavlin 30
110 dpavlin 40 warn "getting chunk of $len bytes\n" if $self->debug;
111 dpavlin 30
112 dpavlin 40 $sock->read( my $buff, $len );
113     $chunk .= $buff;
114 dpavlin 30
115 dpavlin 40 warn "--- $len bytes: --=>||$buff||<=--\n";
116 dpavlin 30
117 dpavlin 40 } while ( $len > 0 );
118 dpavlin 30
119 dpavlin 40 } else {
120     die "right now, we support only Transfer-Encoding: chunked";
121     }
122 dpavlin 34
123 dpavlin 40 warn "handler got ", length($chunk), " bytes\n" if $self->debug;
124 dpavlin 34
125 dpavlin 40 warn "<<< " . localtime() . " " . $sock->peerhost . "\n";
126 dpavlin 34
127 dpavlin 40 die "not SOAP request" unless defined ( $self->header('SOAPAction') );
128 dpavlin 30
129 dpavlin 36 my $state;
130    
131 dpavlin 40 if ( $chunk ) {
132     warn "## request chunk: ",length($chunk)," bytes\n$chunk\n" if $self->debug;
133 dpavlin 30
134 dpavlin 40 $state = CWMP::Request->parse( $chunk );
135 dpavlin 34
136 dpavlin 40 warn "acquired state = ", dump( $state ), "\n";
137 dpavlin 34
138 dpavlin 36 } else {
139     warn "empty request\n";
140 dpavlin 34 }
141    
142 dpavlin 40
143 dpavlin 35 my $response = CWMP::Response->new({ debug => $self->debug });
144 dpavlin 34
145 dpavlin 40 print $self->status(200), $self->content_type('text/xml; charset="utf-8"'), "\r\n";
146 dpavlin 30
147 dpavlin 40 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 dpavlin 36 if ( my $dispatch = $state->{_dispatch} ) {
154     if ( $response->can( $dispatch ) ) {
155     warn ">>> dispatching to $dispatch\n";
156 dpavlin 40 $xml = $response->$dispatch( $state ) . "\r\n";
157     warn "## response payload: ",length($xml)," bytes\n$xml\n";
158 dpavlin 36 } else {
159     confess "can't dispatch to $dispatch";
160     }
161     } else {
162     warn ">>> empty response\n";
163     }
164 dpavlin 40
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 dpavlin 30 };
171    
172 dpavlin 40
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 dpavlin 30 1;

  ViewVC Help
Powered by ViewVC 1.1.26