?? x7229.htm
字號:
<HTML
><HEAD
><TITLE
>Dialup system watch</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"><LINK
REL="HOME"
TITLE="Programming Jabber"
HREF="book1.htm"><LINK
REL="UP"
TITLE="Messages, Presence, and Presence Subscription"
HREF="c6941.htm"><LINK
REL="PREVIOUS"
TITLE="CVS notification"
HREF="x6950.htm"><LINK
REL="NEXT"
TITLE="Presence-sensitive CVS notification"
HREF="x7499.htm"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming Jabber</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x6950.htm"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 7. Messages, Presence, and Presence Subscription</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x7499.htm"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="JABTDG-CH-7-SECT-2"
>Dialup system watch</A
></H1
><P
>When working from home, my Linux server, which acts as a file server
and router for the rest of the house, is connected to the Internet
for pretty much most of the time. To my wife, I can justify the
pay-per-minute dialup expense with work-related reasons. But when
I'm away, those reasons aren't relevant. So
for most of the time, the connection is down.
Now and again though, I do need access to things on the server
at home. After my wife grew tired of answering the phone and have
me talk her through going downstairs into the cellar, getting the
server to dial up, and finding out the IP address, I decided there
was a better way. I could take one step in the right direction by
getting the server to dial up at specified intervals and I would hop
on at the pre-ordained times if I needed to. But there was a problem
with this, which I'll describe in a second.</P
><P
>Most of the time at customer sites, I'm running a Jabber client of some
sort. Whether it's WinJab on Windows, or Jarl in <I
CLASS="EMPHASIS"
>cli</I
>
(command line) mode on a remote server over an <B
CLASS="COMMAND"
>ssh</B
>
connection, I can get my fix. This platform—my Jabber client—turns
out to be an ideal ready-made component for my solution. </P
><P
>Here's how it would work:</P
><P
></P
><UL
><LI
><P
>Get the server to dial up and connect to the Internet regularly</P
></LI
><LI
><P
>On connection, start a script that sends Jabber presence to me</P
></LI
><LI
><P
>On disconnection, get the script to end</P
></LI
></UL
><P
>While the Jabber client sits on my desktop screen, I am aware
of things going on in the Jabber-based conversation world; people would
send me messages, my email alert mechanism would punt the subject line
of important incoming mails to me, and I could see who (and what) was coming
and going in my roster—the collection of people and services I have in
my contact list. If I could somehow add to my roster a JID that represented
my server at home, I could subscribe to the server's presence and
know when it was available—connected to the Internet—and
when it wasn't.</P
><P
>This would solve the problem I'd previously had with the timing of the
automated dialup: I'd set the server to dial up every hour, or every
two hours, and to stay online for ten minutes or so each time, but
invariably due to timekeeping discrepancies, eddies in the space-time
continuum, and the fact that I don't wear a watch, the poor timing between
me and the server meant that I often missed the online window.</P
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-7-SECT-2.1"
>The preparation</A
></H2
><P
>Before diving into the script, it's necessary to do a bit of preparation.
We're going to be using the <I
CLASS="EMPHASIS"
>presence subscription</I
>
concept, which is is described in <A
HREF="c3612.htm"
>Chapter 5</A
>, and covered
in more detail in the next section in this chapter.
We're also going to have to get the script to run, and stay running, when
the dialup connection is made, and have it stop when the dialup connection
is ended.</P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-7-SECT-2.1.1"
>Presence</A
></H3
><P
>Rather than
get involved in the nitty gritty of presence subcriptions right now, let's
use the tools that are
around us to get things set up. In order for this to work, we need to be
subscribed to the presence of the script that will be invoked when the server
dials up and connects to the Internet. The script will connect to the
Jabber server using a JID with a username that represents the Linux
server: <TT
CLASS="LITERAL"
>myserver@gnu.pipetree.com</TT
>. My JID in this
case is <TT
CLASS="LITERAL"
>dj@gnu.pipetree.com</TT
>, so we just use whatever
Jabber client happens to be at hand, say Jabber Instant Messenger (JIM),
to effect both sides of the subscription. </P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>Step 1: Create JID <TT
CLASS="LITERAL"
>myserver@gnu.pipetree.com</TT
></DT
><DD
><P
>We need to create the script's JID if it doesn't already exist. We can
use the <B
CLASS="COMMAND"
>reguser</B
> script we wrote in
<A
HREF="x6787.htm"
>the section called <I
>User Registration Script</I
> in Chapter 6</A
> to do this:</P
><P
><PRE
CLASS="SCREEN"
>[dj@yak dj]$ <TT
CLASS="USERINPUT"
><B
>./reguser gnu.pipetree.com username=myserver password=secret</B
></TT
>
[Attempt] (myserver) Successful registration
[dj@yak dj]$ </PRE
></P
></DD
><DT
>Step 2: Subscribe to <I
CLASS="EMPHASIS"
>myserver</I
>'s presence</DT
><DD
><P
>We start JIM with the JID <TT
CLASS="LITERAL"
>dj@gnu.pipetree.com</TT
>, and add
<TT
CLASS="LITERAL"
>myserver@gnu.pipetree.com</TT
> to the
roster. This should automatically send a presence subscription request
to the JID. Adding the JID to the roster using JIM is shown in
<A
HREF="x7229.htm#JABTDG-CH-7-FIG-2"
>Figure 7-2</A
>.</P
></DD
><DT
>Step 3: Accept presence subscription as <I
CLASS="EMPHASIS"
>myserver</I
></DT
><DD
><P
>Now connecting with the <I
CLASS="EMPHASIS"
>myserver</I
> JID, again, using the
JIM client, we accept the presence subscription request from Step 2, so that
<TT
CLASS="LITERAL"
>dj@gnu.pipetree.com</TT
> will automatically receive
<TT
CLASS="LITERAL"
>myserver@gnu.pipetree.com</TT
>'s availability information.
Whether or not <I
CLASS="EMPHASIS"
>myserver</I
> subscribes to
<I
CLASS="EMPHASIS"
>dj</I
>'s presence is irrelevant in this case, as the script
itself is not interested in the availability of anyone at all.</P
></DD
></DL
></DIV
><DIV
CLASS="FIGURE"
><A
NAME="JABTDG-CH-7-FIG-2"
></A
><P
><B
>Figure 7-2. Adding <TT
CLASS="LITERAL"
>myserver@gnu.pipetree.com</TT
> to the roster</B
></P
><P
><IMG
SRC="CH-7-FIG-2.jpg"></P
></DIV
><P
>At this stage, the entry in <TT
CLASS="LITERAL"
>dj@gnu.pipetree.com</TT
>'s roster
that represents the Linux server will indicate whether the script run at
dialup time is active or not. If we continue to use the JIM client, we will
see that this is shown by a yellow bulb, or no icon at all, respectively.</P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-7-SECT-2.1.2"
>Starting and stopping the script</A
></H3
><P
>The dialup connection is set up using the Point to Point Protocol
daemon <B
CLASS="COMMAND"
>pppd</B
>. This uses a program such as
<B
CLASS="COMMAND"
>chat</B
> to talk to the modem and get it to dial
the ISP. The <B
CLASS="COMMAND"
>pppd</B
> mechanism
affords us an idea way to start and stop a script on the
respective connection and disconnection of the line. When the
connection has been made, the script <TT
CLASS="LITERAL"
>/etc/ppp/ip-up</TT
>
is invoked and passed a number of connection-related parameters.
Similarly <TT
CLASS="LITERAL"
>/etc/ppp/ip-down</TT
> is invoked when the
connection is closed. </P
><P
>Some implementations of <B
CLASS="COMMAND"
>pppd</B
> also offer
<TT
CLASS="LITERAL"
>/etc/ppp/ip-up.local</TT
> and
<TT
CLASS="LITERAL"
>/etc/ppp/ip-down.local</TT
> which should be used
in place of the <TT
CLASS="LITERAL"
>ip-up</TT
> and <TT
CLASS="LITERAL"
>ip-down</TT
>
scripts if they exist.</P
><P
>So what we want to do is start our script with
<TT
CLASS="LITERAL"
>ip-up[.local]</TT
> and stop it with
<TT
CLASS="LITERAL"
>ip-down[.local]</TT
>. What these starter and stopper
scripts might look like are shown in <A
HREF="x7229.htm#JABTDG-CH-7-EX-3"
>Example 7-3</A
>
and <A
HREF="x7229.htm#JABTDG-CH-7-EX-4"
>Example 7-4</A
>. They are simply shell scripts
that share the process id (PID) of the Jabber script via a temporary
file. The starter starts the Jabber script and writes the PID of that
script to a file. The stopper kills the script using the PID.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="JABTDG-CH-7-EX-3"
></A
><P
><B
>Example 7-3. An <TT
CLASS="LITERAL"
>ip-up</TT
> starter script</B
></P
><P
><PRE
CLASS="SCREEN"
>#!/bin/sh
# Change to working directory
cd /jabber/java/
# Call the Jabber script and put to background
/usr/java/jdk1.3.1/bin/java -classpath jabberbeans.jar:. HostAlive $5 &
# Write the running script's PID
echo $! > /tmp/HostAlive.pid</PRE
></P
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="JABTDG-CH-7-EX-4"
></A
><P
><B
>Example 7-4. An <TT
CLASS="LITERAL"
>ip-down</TT
> stopper script</B
></P
><P
><PRE
CLASS="SCREEN"
>#!/bin/sh
# Simply kill the process using the
# JID written by the starter script
/bin/kill `cat /tmp/HostAlive.pid`
# Remove the PID file
/bin/rm /tmp/HostAlive.pid </PRE
></P
></DIV
><P
><A
HREF="x7229.htm#JABTDG-CH-7-EX-3"
>Example 7-3</A
> shows that we're passing through
one of the parameters that <B
CLASS="COMMAND"
>pppd</B
> gives to the
<TT
CLASS="LITERAL"
>ip-up</TT
> script: the remote IP address—that
by which the server is known during its temporary connection to the
Internet—in the <TT
CLASS="LITERAL"
>$5</TT
> variable.
<A
NAME="AEN7325"
HREF="#FTN.AEN7325"
>[1]</A
>
This IP address can be passed along as part of the availability
information in the <TT
CLASS="LITERAL"
><presence/></TT
> element,
so that the recipient (<I
CLASS="EMPHASIS"
>dj</I
>) can see what IP address
has been assigned to the server.</P
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-7-SECT-2.2"
>The Jabber script</A
></H2
><P
>As you might have guessed from looking at <A
HREF="x7229.htm#JABTDG-CH-7-EX-3"
>Example 7-3</A
>,
we're going to write this script in Java. We'll use the Jabberbeans
library; see <A
HREF="x217.htm"
>the section called <I
>The Software</I
> in Chapter 1</A
> for details of where
to get this library and what the requirements are.</P
><P
>Let's start by importing the libraries (the classes) we would like to
use:</P
><P
><PRE
CLASS="SCREEN"
>import org.jabber.jabberbeans.*;
import org.jabber.jabberbeans.Extension.*;
import java.net.InetAddress; </PRE
></P
><P
>The Jabberbeans Jabber library is highly modular and designed so
we can pick only the features that we need; in this case, however,
we're just going to import the whole set of classes within the
<TT
CLASS="LITERAL"
>org.jabber.jabberbeans</TT
> and
<TT
CLASS="LITERAL"
>org.jabber.jabberbeans.Extension</TT
> packages,
for simplicity.</P
><P
>We're also going to be manipulating the Jabber server's hostname,
so we pull in the <TT
CLASS="LITERAL"
>InetAddress</TT
> class for convenience.</P
><P
>The script must connect to the Jabber server on
<TT
CLASS="LITERAL"
>gnu.pipetree.com</TT
> as the <I
CLASS="EMPHASIS"
>myserver</I
>
user. We define some constants for this:</P
><P
><PRE
CLASS="SCREEN"
>public class HostAlive
{
public static final String SERVER = "gnu.pipetree.com";
public static final String USER = "myserver";
public static final String PASSWORD = "secret";
public static final String RESOURCE = "alive"; </PRE
></P
><P
>In the same way as our Python-based CVS notification script earlier
in this chapter, we also start off by building a connection to the
Jabber server. As before, it's a two-stage process.
The first stage is to create the connection object:</P
><P
><PRE
CLASS="SCREEN"
> public static void main(String argv[])
{
ConnectionBean cb=new ConnectionBean(); </PRE
></P
><P
>A <TT
CLASS="LITERAL"
>ConnectionBean</TT
> object represents the connection
between your script and the Jabber server. All XML fragments;—Jabber
elements—pass through this object.</P
><P
>Then it's time to attempt the socket connection and the exchange of
XML stream headers:</P
><P
><PRE
CLASS="SCREEN"
> InetAddress addr;
try
{
cb.connect(addr=InetAddress.getByName(SERVER));
}
catch (java.net.UnknownHostException e)
{
//from getByName()
System.out.println("Cannot resolve " + SERVER + ":" + e.toString());
return;
}
catch (java.io.IOException e)
{
//from connect()
System.out.println("Cannot connect to " + SERVER);
return;
} </PRE
></P
><P
>We create an Internet address object in <TT
CLASS="LITERAL"
>addr</TT
>
from the hostname assigned to the <TT
CLASS="LITERAL"
>SERVER</TT
> constant.
As the creation of the <TT
CLASS="LITERAL"
>addr</TT
> instance may throw
an exception (<I
CLASS="EMPHASIS"
>unknown host</I
>), we combine the
instantiation with the <TT
CLASS="LITERAL"
>connection()</TT
> call on our
<TT
CLASS="LITERAL"
>ConnectionBean</TT
> object which may also throw an
exception of its own—if there is a problem connecting.</P
><P
>At this stage, we're connected and have successfully exchanged the
XML stream headers with the Jabber server. So now we must authenticate:</P
><P
><PRE
CLASS="SCREEN"
> InfoQueryBuilder iqb=new InfoQueryBuilder();
InfoQuery iq;
IQAuthBuilder iqAuthb=new IQAuthBuilder();
iqb.setType("set");
iqAuthb.setUsername(USER);
iqAuthb.setPassword(PASSWORD);
iqAuthb.setResource(RESOURCE);
try
{
iqb.addExtension(iqAuthb.build());
}
catch (InstantiationException e)
{
//building failed ?
System.out.println("Fatal Error on Auth object build:");
System.out.println(e.toString());
System.exit(0);
}
try
{
//build the full InfoQuery packet
iq=(InfoQuery)iqb.build();
}
catch (InstantiationException e)
{
//building failed ?
System.out.println("Fatal Error on IQ object build:");
System.out.println(e.toString());
return;
}
cb.send(iq); </PRE
></P
><P
>Yes, that's an awful lot. Let's take it piece by piece.</P
><P
><A
HREF="x7229.htm#JABTDG-CH-7-FIG-3"
>Figure 7-3</A
> shows how the objects in this
section of code interrelate and represent various parts of what
we're trying to do—which is to construct an authorization
element. This takes the form of an IQ-set containing a
<TT
CLASS="LITERAL"
><query/></TT
> tag qualified by the
<TT
CLASS="LITERAL"
>jabber:iq:auth</TT
> namespace like this:
<A
NAME="AEN7379"
HREF="#FTN.AEN7379"
>[2]</A
> </P
><P
><PRE
CLASS="SCREEN"
><iq type='set'>
<query xmlns='jabber:iq:auth'>
<username>myserver</username>
<password>secret</password>
<resource>alive</resource>
</query>
</iq></PRE
></P
><P
>Constructing Jabber elements with Jabberbeans uses so-called
<I
CLASS="EMPHASIS"
>builders</I
> that allow individual element
components to be created separately and then fused together
into a final structure. In our code, we use two builders:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -