File Coverage

blib/lib/Net/XMPP3/Connection.pm
Criterion Covered Total %
statement 30 163 18.4
branch 1 70 1.4
condition 0 27 0.0
subroutine 6 16 37.5
pod 0 8 0.0
total 37 284 13.0


line stmt bran cond sub pod time code
1             ##############################################################################
2             #
3             # This library is free software; you can redistribute it and/or
4             # modify it under the terms of the GNU Library General Public
5             # License as published by the Free Software Foundation; either
6             # version 2 of the License, or (at your option) any later version.
7             #
8             # This library is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11             # Library General Public License for more details.
12             #
13             # You should have received a copy of the GNU Library General Public
14             # License along with this library; if not, write to the
15             # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16             # Boston, MA 02111-1307, USA.
17             #
18             # Copyright (C) 1998-2004 Jabber Software Foundation http://jabber.org/
19             #
20             ##############################################################################
21              
22             package Net::XMPP3::Connection;
23              
24             =head1 NAME
25              
26             Net::XMPP3::Connection - XMPP Connection Module
27              
28             =head1 SYNOPSIS
29              
30             Net::XMPP3::Connection is a private package that serves as a basis
31             for anything wanting to open a socket connection to a server.
32              
33             =head1 DESCRIPTION
34              
35             This module is not meant to be used directly. You should be using
36             either Net::XMPP3::Client, or another package that inherits from
37             Net::XMPP3::Connection.
38              
39             =head1 AUTHOR
40              
41             Ryan Eatmon
42              
43             =head1 COPYRIGHT
44              
45             This module is free software, you can redistribute it and/or modify it
46             under the LGPL.
47              
48             =cut
49              
50 11     11   61 use strict;
  11         24  
  11         357  
51 11     11   58 use Carp;
  11         24  
  11         694  
52 11     11   80 use base qw( Net::XMPP3::Protocol );
  11         31  
  11         24116  
53              
54              
55             sub new
56             {
57 0     0 0 0 my $proto = shift;
58 0         0 my $self = { };
59              
60 0         0 bless($self, $proto);
61              
62 0         0 $self->init(@_);
63              
64 0         0 $self->{SERVER}->{namespace} = "unknown";
65              
66 0         0 return $self;
67             }
68              
69              
70             ##############################################################################
71             #
72             # init - do all of the heavy lifting for a generic connection.
73             #
74             ##############################################################################
75             sub init
76             {
77 1     1 0 5 my $self = shift;
78              
79 1         13 $self->{ARGS} = {};
80 1         5 while($#_ >= 0) { $self->{ARGS}->{ lc(pop(@_)) } = pop(@_); }
  0         0  
81              
82 1         9 $self->{DEBUG} =
83             new Net::XMPP3::Debug(level => $self->_arg("debuglevel",-1),
84             file => $self->_arg("debugfile","stdout"),
85             time => $self->_arg("debugtime",0),
86             setdefault => 1,
87             header => "XMPP::Conn"
88             );
89              
90 1         3 $self->{SERVER} = {};
91 1         4 $self->{SERVER}->{hostname} = "localhost";
92 1         5 $self->{SERVER}->{tls} = $self->_arg("tls",0);
93 1         4 $self->{SERVER}->{ssl} = $self->_arg("ssl",0);
94 1         4 $self->{SERVER}->{connectiontype} = $self->_arg("connectiontype","tcpip");
95              
96 1         80 $self->{CONNECTED} = 0;
97 1         2 $self->{DISCONNECTED} = 0;
98              
99 1         8 $self->{STREAM} =
100             new XML::Stream(style => "node",
101             debugfh => $self->{DEBUG}->GetHandle(),
102             debuglevel => $self->{DEBUG}->GetLevel(),
103             debugtime => $self->{DEBUG}->GetTime(),
104             );
105              
106 1         1286 $self->{RCVDB}->{currentID} = 0;
107              
108 1         9 $self->InitCallbacks();
109              
110 1         4 return $self;
111             }
112              
113              
114             ##############################################################################
115             #
116             # Connect - Takes a has and opens the connection to the specified server.
117             # Registers CallBack as the main callback for all packets from
118             # the server.
119             #
120             # NOTE: Need to add some error handling if the connection is
121             # not made because the server hostname is wrong or whatnot.
122             #
123             ##############################################################################
124             sub Connect
125             {
126 0     0 0 0 my $self = shift;
127              
128 0         0 while($#_ >= 0) { $self->{SERVER}{ lc pop(@_) } = pop(@_); }
  0         0  
129              
130 0 0       0 $self->{SERVER}->{timeout} = 10 unless exists($self->{SERVER}->{timeout});
131              
132 0         0 $self->{DEBUG}->Log1("Connect: host($self->{SERVER}->{hostname}:$self->{SERVER}->{port}) namespace($self->{SERVER}->{namespace})");
133 0         0 $self->{DEBUG}->Log1("Connect: timeout($self->{SERVER}->{timeout})");
134              
135 0         0 delete($self->{SESSION});
136 0 0       0 $self->{SESSION} =
137             $self->{STREAM}->
138             Connect(hostname => $self->{SERVER}->{hostname},
139             port => $self->{SERVER}->{port},
140             namespace => $self->{SERVER}->{namespace},
141             connectiontype => $self->{SERVER}->{connectiontype},
142             timeout => $self->{SERVER}->{timeout},
143             ssl => $self->{SERVER}->{ssl}, #LEGACY
144             (defined($self->{SERVER}->{componentname}) ?
145             (to => $self->{SERVER}->{componentname}) :
146             ()
147             ),
148             );
149              
150 0 0       0 if ($self->{SESSION})
151             {
152 0         0 $self->{DEBUG}->Log1("Connect: connection made");
153              
154 0     0   0 $self->{STREAM}->SetCallBacks(node=>sub{ $self->CallBack(@_) });
  0         0  
155 0         0 $self->{CONNECTED} = 1;
156 0         0 $self->{RECONNECTING} = 0;
157              
158 0 0 0     0 if (exists($self->{SESSION}->{version}) &&
159             ($self->{SESSION}->{version} ne ""))
160             {
161 0         0 my $tls = $self->GetStreamFeature("xmpp-tls");
162 0 0 0     0 if (defined($tls) && $self->{SERVER}->{tls})
    0 0        
163             {
164 0         0 $self->{SESSION} =
165             $self->{STREAM}->StartTLS(
166             $self->{SESSION}->{id},
167             $self->{SERVER}->{timeout},
168             );
169             }
170             elsif (defined($tls) && ($tls eq "required"))
171             {
172 0         0 $self->SetErrorCode("The server requires us to use TLS, but you did not specify that\nTLS was an option.");
173 0         0 return;
174             }
175             }
176              
177 0         0 return 1;
178             }
179             else
180             {
181 0         0 $self->SetErrorCode($self->{STREAM}->GetErrorCode());
182 0         0 return;
183             }
184             }
185              
186              
187             ##############################################################################
188             #
189             # Connected - returns 1 if the Transport is connected to the server, 0
190             # otherwise.
191             #
192             ##############################################################################
193             sub Connected
194             {
195 0     0 0 0 my $self = shift;
196              
197 0         0 $self->{DEBUG}->Log1("Connected: ($self->{CONNECTED})");
198 0         0 return $self->{CONNECTED};
199             }
200              
201              
202             ##############################################################################
203             #
204             # Disconnect - Sends the string to close the connection cleanly.
205             #
206             ##############################################################################
207             sub Disconnect
208             {
209 0     0 0 0 my $self = shift;
210              
211 0 0       0 $self->{STREAM}->Disconnect($self->{SESSION}->{id})
212             if ($self->{CONNECTED} == 1);
213 0         0 $self->{STREAM}->SetCallBacks(node=>undef);
214 0         0 $self->{CONNECTED} = 0;
215 0         0 $self->{DISCONNECTED} = 1;
216 0         0 $self->{RECONNECTING} = 0;
217 0         0 $self->{DEBUG}->Log1("Disconnect: bye bye");
218             }
219              
220              
221             ##############################################################################
222             #
223             # Execute - generic inner loop to listen for incoming messages, stay
224             # connected to the server, and do all the right things. It
225             # calls a couple of callbacks for the user to put hooks into
226             # place if they choose to.
227             #
228             ##############################################################################
229             sub Execute
230             {
231 0     0 0 0 my $self = shift;
232 0         0 my %args;
233 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
234              
235 0 0       0 $args{connectiontype} = "tcpip" unless exists($args{connectiontype});
236 0 0       0 $args{connectattempts} = -1 unless exists($args{connectattempts});
237 0 0       0 $args{connectsleep} = 5 unless exists($args{connectsleep});
238 0 0       0 $args{register} = 0 unless exists($args{register});
239              
240 0         0 my %connect = $self->_connect_args(%args);
241              
242 0         0 $self->{DEBUG}->Log1("Execute: begin");
243              
244 0         0 my $connectAttempt = $args{connectattempts};
245              
246 0   0     0 while(($connectAttempt == -1) || ($connectAttempt > 0))
247             {
248              
249 0         0 $self->{DEBUG}->Log1("Execute: Attempt to connect ($connectAttempt)");
250              
251 0         0 my $status = $self->Connect(%connect);
252              
253 0 0       0 if (!(defined($status)))
254             {
255 0         0 $self->{DEBUG}->Log1("Execute: Server is not answering. (".$self->GetErrorCode().")");
256 0         0 $self->{CONNECTED} = 0;
257              
258 0 0       0 $connectAttempt-- unless ($connectAttempt == -1);
259 0         0 sleep($args{connectsleep});
260 0         0 next;
261             }
262              
263 0         0 $self->{DEBUG}->Log1("Execute: Connected...");
264 0 0       0 &{$self->{CB}->{onconnect}}() if exists($self->{CB}->{onconnect});
  0         0  
265              
266 0         0 my @result = $self->_auth(%args);
267              
268 0 0 0     0 if (@result && $result[0] ne "ok")
269             {
270 0         0 $self->{DEBUG}->Log1("Execute: Could not auth with server: ($result[0]: $result[1])");
271 0 0       0 &{$self->{CB}->{onauthfail}}()
  0         0  
272             if exists($self->{CB}->{onauthfail});
273              
274 0 0 0     0 if (!$self->{SERVER}->{allow_register} || $args{register} == 0)
275             {
276 0         0 $self->{DEBUG}->Log1("Execute: Register turned off. Exiting.");
277 0         0 $self->Disconnect();
278 0 0       0 &{$self->{CB}->{ondisconnect}}()
  0         0  
279             if exists($self->{CB}->{ondisconnect});
280 0         0 $connectAttempt = 0;
281             }
282             else
283             {
284 0         0 @result = $self->_register(%args);
285              
286 0 0       0 if ($result[0] ne "ok")
287             {
288 0         0 $self->{DEBUG}->Log1("Execute: Register failed. Exiting.");
289 0 0       0 &{$self->{CB}->{onregisterfail}}()
  0         0  
290             if exists($self->{CB}->{onregisterfail});
291              
292 0         0 $self->Disconnect();
293 0 0       0 &{$self->{CB}->{ondisconnect}}()
  0         0  
294             if exists($self->{CB}->{ondisconnect});
295 0         0 $connectAttempt = 0;
296             }
297             else
298             {
299 0 0       0 &{$self->{CB}->{onauth}}()
  0         0  
300             if exists($self->{CB}->{onauth});
301             }
302             }
303             }
304             else
305             {
306 0 0       0 &{$self->{CB}->{onauth}}()
  0         0  
307             if exists($self->{CB}->{onauth});
308             }
309              
310 0         0 while($self->Connected())
311             {
312              
313 0         0 while(defined($status = $self->Process($args{processtimeout})))
314             {
315 0 0       0 &{$self->{CB}->{onprocess}}()
  0         0  
316             if exists($self->{CB}->{onprocess});
317             }
318              
319 0 0       0 if (!defined($status))
320             {
321 0         0 $self->Disconnect();
322 0         0 $self->{RECONNECTING} = 1;
323 0         0 delete($self->{PROCESSERROR});
324 0         0 $self->{DEBUG}->Log1("Execute: Connection to server lost...");
325 0 0       0 &{$self->{CB}->{ondisconnect}}()
  0         0  
326             if exists($self->{CB}->{ondisconnect});
327              
328 0         0 $connectAttempt = $args{connectattempts};
329 0         0 next;
330             }
331             }
332              
333 0 0 0     0 last if (!$self->{RECONNECTING} && $self->{DISCONNECTED});
334             }
335              
336 0         0 $self->{DEBUG}->Log1("Execute: end");
337 0 0       0 &{$self->{CB}->{onexit}}() if exists($self->{CB}->{onexit});
  0         0  
338             }
339              
340              
341             ##############################################################################
342             #
343             # InitCallbacks - initialize the callbacks
344             #
345             ##############################################################################
346             sub InitCallbacks
347             {
348 1     1 0 4 my $self = shift;
349              
350 1         12 $self->xmppCallbackInit();
351             }
352              
353             ###############################################################################
354             #
355             # Process - If a timeout value is specified then the function will wait
356             # that long before returning. This is useful for apps that
357             # need to handle other processing while still waiting for
358             # packets. If no timeout is listed then the function waits
359             # until a packet is returned. Either way the function exits
360             # as soon as a packet is returned.
361             #
362             ###############################################################################
363             sub Process
364             {
365 0     0 0 0 my $self = shift;
366 0         0 my ($timeout) = @_;
367 0         0 my %status;
368              
369 0 0 0     0 if (exists($self->{PROCESSERROR}) && ($self->{PROCESSERROR} == 1))
370             {
371 0         0 croak("There was an error in the last call to Process that you did not check for and\nhandle. You should always check the output of the Process call. If it was\nundef then there was a fatal error that you need to check. There is an error\nin your program");
372             }
373              
374 0 0       0 $self->{DEBUG}->Log1("Process: timeout($timeout)") if defined($timeout);
375              
376 0 0 0     0 if (!defined($timeout) || ($timeout eq ""))
377             {
378 0         0 while(1)
379             {
380 0         0 %status = $self->{STREAM}->Process();
381 0         0 $self->{DEBUG}->Log1("Process: status($status{$self->{SESSION}->{id}})");
382 0 0       0 last if ($status{$self->{SESSION}->{id}} != 0);
383 0         0 select(undef,undef,undef,.25);
384             }
385 0         0 $self->{DEBUG}->Log1("Process: return($status{$self->{SESSION}->{id}})");
386 0 0       0 if ($status{$self->{SESSION}->{id}} == -1)
387             {
388 0         0 $self->{PROCESSERROR} = 1;
389 0         0 return;
390             }
391             else
392             {
393 0         0 return $status{$self->{SESSION}->{id}};
394             }
395             }
396             else
397             {
398 0         0 %status = $self->{STREAM}->Process($timeout);
399 0 0       0 if ($status{$self->{SESSION}->{id}} == -1)
400             {
401 0         0 $self->{PROCESSERROR} = 1;
402 0         0 return;
403             }
404             else
405             {
406 0         0 return $status{$self->{SESSION}->{id}};
407             }
408             }
409             }
410              
411              
412              
413              
414             ##############################################################################
415             #+----------------------------------------------------------------------------
416             #|
417             #| Overloadable Methods
418             #|
419             #+----------------------------------------------------------------------------
420             ##############################################################################
421              
422             ##############################################################################
423             #
424             # _auth - Overload this method to provide the authentication method for your
425             # type of connection.
426             #
427             ##############################################################################
428             sub _auth
429             {
430 0     0   0 my $self = shift;
431 0         0 croak("You must override the _auth method.");
432             }
433              
434              
435             ##############################################################################
436             #
437             # _connect_args - The Connect function that the Execute loop uses needs
438             # certain args. This method lets you map the Execute args
439             # into the Connect args for your Connection type.
440             #
441             ##############################################################################
442             sub _connect_args
443             {
444 0     0   0 my $self = shift;
445 0         0 my (%args) = @_;
446              
447 0         0 return %args;
448             }
449              
450              
451             ##############################################################################
452             #
453             # _register - overload this method if you need your connection to register
454             # with the server.
455             #
456             ##############################################################################
457             sub _register
458             {
459 0     0   0 my $self = shift;
460 0         0 return ( "ok" ,"" );
461             }
462              
463              
464              
465              
466             ##############################################################################
467             #+----------------------------------------------------------------------------
468             #|
469             #| Private Helpers
470             #|
471             #+----------------------------------------------------------------------------
472             ##############################################################################
473              
474             sub _arg
475             {
476 6     6   8 my $self = shift;
477 6         9 my $arg = shift;
478 6         7 my $default = shift;
479              
480 6 50       35 return exists($self->{ARGS}->{$arg}) ? $self->{ARGS}->{$arg} : $default;
481             }
482              
483              
484             1;