home *** CD-ROM | disk | FTP | other *** search
- # ======================================================================
- #
- # Copyright (C) 2000-2001 Paul Kulchenko (paulclinger@yahoo.com)
- # SOAP::Lite is free software; you can redistribute it
- # and/or modify it under the same terms as Perl itself.
- #
- # $Id: TCP.pm,v 1.4 2002/04/15 19:09:57 paulk Exp $
- #
- # ======================================================================
-
- package SOAP::Transport::TCP;
-
- use strict;
- use vars qw($VERSION);
- $VERSION = sprintf("%d.%s", map {s/_//g; $_} q$Name: release-0_55-public $ =~ /-(\d+)_([\d_]+)/);
-
- use URI;
- use IO::Socket;
- use IO::Select;
- use IO::SessionData;
- use SOAP::Lite;
-
- # ======================================================================
-
- package URI::tcp; # ok, let's do 'tcp://' scheme
- require URI::_server;
- @URI::tcp::ISA=qw(URI::_server);
-
- # ======================================================================
-
- package SOAP::Transport::TCP::Client;
-
- use vars qw(@ISA);
- @ISA = qw(SOAP::Client);
-
- sub DESTROY { SOAP::Trace::objects('()') }
-
- sub new {
- my $self = shift;
-
- unless (ref $self) {
- my $class = ref($self) || $self;
- my(@params, @methods);
- while (@_) { $class->can($_[0]) ? push(@methods, shift() => shift) : push(@params, shift) }
- $self = bless {@params} => $class;
- while (@methods) { my($method, $params) = splice(@methods,0,2);
- $self->$method(ref $params eq 'ARRAY' ? @$params : $params)
- }
- # use SSL if there is any parameter with SSL_* in the name
- $self->SSL(1) if !$self->SSL && grep /^SSL_/, keys %$self;
- SOAP::Trace::objects('()');
- }
- return $self;
- }
-
- sub SSL {
- my $self = shift->new;
- @_ ? ($self->{_SSL} = shift, return $self) : return $self->{_SSL};
- }
-
- sub io_socket_class { shift->SSL ? 'IO::Socket::SSL' : 'IO::Socket::INET' }
-
- sub syswrite {
- my($self, $sock, $data) = @_;
-
- my $timeout = $sock->timeout;
-
- my $select = IO::Select->new($sock);
-
- my $len = length $data;
- while (length $data > 0) {
- return unless $select->can_write($timeout);
- local $SIG{PIPE} = 'IGNORE';
- # added length() to make it work on Mac. Thanks to Robin Fuller <rfuller@broadjump.com>
- my $wc = syswrite($sock, $data, length($data));
- if (defined $wc) {
- substr($data, 0, $wc) = '';
- } elsif (!IO::SessionData::WOULDBLOCK($!)) {
- return;
- }
- }
- return $len;
- }
-
- sub sysread {
- my($self, $sock) = @_;
-
- my $timeout = $sock->timeout;
- my $select = IO::Select->new($sock);
-
- my $result = '';
- my $data;
- while (1) {
- return unless $select->can_read($timeout);
- my $rc = sysread($sock, $data, 4096);
- if ($rc) {
- $result .= $data;
- } elsif (defined $rc) {
- return $result;
- } elsif (!IO::SessionData::WOULDBLOCK($!)) {
- return;
- }
- }
- }
-
- sub send_receive {
- my($self, %parameters) = @_;
- my($envelope, $endpoint, $action) =
- @parameters{qw(envelope endpoint action)};
-
- $endpoint ||= $self->endpoint;
- warn "URLs with 'tcp:' scheme are deprecated. Use 'tcp://'. Still continue\n"
- if $endpoint =~ s!^tcp:(//)?!tcp://!i && !$1;
- my $uri = URI->new($endpoint);
-
- local($^W, $@, $!);
- my $socket = $self->io_socket_class;
- eval "require $socket" or Carp::croak $@ unless UNIVERSAL::can($socket => 'new');
- my $sock = $socket->new (
- PeerAddr => $uri->host, PeerPort => $uri->port, Proto => $uri->scheme, %$self
- );
-
- SOAP::Trace::debug($envelope);
-
- # bytelength hack. See SOAP::Transport::HTTP.pm for details.
- my $bytelength = SOAP::Utils::bytelength($envelope);
- $envelope = pack('C0A*', $envelope)
- if !$SOAP::Constants::DO_NOT_USE_LWP_LENGTH_HACK && length($envelope) != $bytelength;
-
- my $result;
- if ($sock) {
- $sock->blocking(0);
- $self->syswrite($sock, $envelope) and
- $sock->shutdown(1) and # stop writing
- $result = $self->sysread($sock);
- }
-
- SOAP::Trace::debug($result);
-
- my $code = $@ || $!;
-
- $self->code($code);
- $self->message($code);
- $self->is_success(!defined $code || $code eq '');
- $self->status($code);
-
- return $result;
- }
-
- # ======================================================================
-
- package SOAP::Transport::TCP::Server;
-
- use IO::SessionSet;
-
- use Carp ();
- use vars qw($AUTOLOAD @ISA);
- @ISA = qw(SOAP::Server);
-
- sub DESTROY { SOAP::Trace::objects('()') }
-
- sub new {
- my $self = shift;
-
- unless (ref $self) {
- my $class = ref($self) || $self;
-
- my(@params, @methods);
- while (@_) { $class->can($_[0]) ? push(@methods, shift() => shift) : push(@params, shift) }
- $self = $class->SUPER::new(@methods);
-
- # use SSL if there is any parameter with SSL_* in the name
- $self->SSL(1) if !$self->SSL && grep /^SSL_/, @params;
-
- my $socket = $self->io_socket_class;
- eval "require $socket" or Carp::croak $@ unless UNIVERSAL::can($socket => 'new');
- $self->{_socket} = $socket->new(Proto => 'tcp', @params)
- or Carp::croak "Can't open socket: $!";
-
- SOAP::Trace::objects('()');
- }
- return $self;
- }
-
- sub SSL {
- my $self = shift->new;
- @_ ? ($self->{_SSL} = shift, return $self) : return $self->{_SSL};
- }
-
- sub io_socket_class { shift->SSL ? 'IO::Socket::SSL' : 'IO::Socket::INET' }
-
- sub AUTOLOAD {
- my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::') + 2);
- return if $method eq 'DESTROY';
-
- no strict 'refs';
- *$AUTOLOAD = sub { shift->{_socket}->$method(@_) };
- goto &$AUTOLOAD;
- }
-
- sub handle {
- my $self = shift->new;
- my $sock = $self->{_socket};
- my $session_set = IO::SessionSet->new($sock);
- my %data;
- while (1) {
- my @ready = $session_set->wait($sock->timeout);
- for my $session (@ready) {
- my $data;
- if (my $rc = $session->read($data, 4096)) {
- $data{$session} .= $data if $rc > 0;
- } else {
- $session->write($self->SUPER::handle(delete $data{$session}));
- $session->close;
- }
- }
- }
- }
-
- # ======================================================================
-
- 1;
-
- __END__
-
- =head1 NAME
-
- SOAP::Transport::TCP - Server/Client side TCP support for SOAP::Lite
-
- =head1 SYNOPSIS
-
- use SOAP::Transport::TCP;
-
- my $daemon = SOAP::Transport::TCP::Server
- -> new (LocalAddr => 'localhost', LocalPort => 82, Listen => 5, Reuse => 1)
- -> objects_by_reference(qw(My::PersistentIterator My::SessionIterator My::Chat))
- -> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method')
- ;
- print "Contact to SOAP server at ", join(':', $daemon->sockhost, $daemon->sockport), "\n";
- $daemon->handle;
-
- =head1 DESCRIPTION
-
- =head1 COPYRIGHT
-
- Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
-
- This library is free software; you can redistribute it and/or modify
- it under the same terms as Perl itself.
-
- =head1 AUTHOR
-
- Paul Kulchenko (paulclinger@yahoo.com)
-
- =cut
-