Source code: com/jabberwookie/Component2Server.java
1 /*
2 * Component2Server.java
3 *
4 * Created on May 16, 2003, 4:18 PM
5 * Copyright (c) 2003, Sean M. Meiners, sean@jabberwookie.com
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * * Neither the name of JabberWookie nor the names of its contributors may be used
17 * to endorse or promote products derived from this software without specific
18 * prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 package com.jabberwookie;
33
34 import java.util.Hashtable;
35
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
39
40 import com.jabberwookie.ns.jabber.Chunk;
41
42 import com.jabberwookie.UnrecognizedChunkListener;
43
44 import com.ssttr.crypto.SHA1;
45
46 import com.ssttr.util.processor.Processor;
47
48 /**
49 * Implements the required methods to establish a connection to a
50 * Jabber server as a component. This allows you to create new
51 * services for the server.
52 * @author smeiners
53 */
54 public class Component2Server
55 extends Stream
56 implements UnrecognizedChunkListener
57 {
58
59 private static final String STREAM_OPENER =
60 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' " +
61 "xmlns='jabber:component:accept' to='";
62
63 private static final String STREAM_CLOSER =
64 "</stream:stream>";
65
66 private String secret = "";
67
68 private boolean authenticated = false;
69
70 /** Creates a new instance of Component2Server. Since this class
71 * doesn't understand what a Socket is you'll have to open
72 * one youself and then pass in the input and output stream.
73 * @param secret The secret used to authenticate yourself to
74 * the Jabber server. */
75 public Component2Server (InputStream in, OutputStream out, String secret) {
76 super(in,out);
77 _init(secret);
78 }
79
80 /** Creates a new instance of Component2Server. Since this class
81 * doesn't understand what a Socket is you'll have to open
82 * one youself and then pass in the input and output stream.
83 * Please see the documentation for
84 * {@link Stream#Stream(InputStream,OutputStream,Processor)}
85 * and {@link Stream#setProcessor} for more information about
86 * the Processor.
87 * @param secret The secret used to authenticate yourself to
88 * the Jabber server.
89 */
90 public Component2Server (InputStream in, OutputStream out,
91 String secret, Processor processor) {
92 super(in,out,processor);
93 _init(secret);
94 }
95
96 private void _init(String secret)
97 {
98 unListener = this;
99 this.secret = secret;
100 }
101
102 /**
103 * Since Jabber components are set to receive data from specific
104 * namespaces only this overrides the default
105 * {@link Stream#setUnrecogizedChunkListener} to do nothing.
106 */
107 public void setUnrecogizedChunkListener(UnrecognizedChunkListener listener)
108 {
109 }
110
111 /**
112 * Opens the stream and attempts to authenticate itself.
113 */
114 public boolean open(String serverName, int timeoutSecs)
115 throws IOException
116 {
117 if( DEBUG )
118 System.out.println("SEND: " + (STREAM_OPENER + serverName + "'>"));
119
120 if( ns == null )
121 ns = new Namespaces();
122
123 out.write( (STREAM_OPENER + serverName + "'>").getBytes() );
124 out.flush();
125
126 long stopTime = System.currentTimeMillis() + timeoutSecs * 1000;
127 while( ! connected && ! authenticated && System.currentTimeMillis() < stopTime )
128 {
129 try
130 { Thread.sleep(5); }
131 catch( InterruptedException x )
132 { }
133 }
134
135 return connected && authenticated;
136 }
137
138 /**
139 * Closes the stream.
140 */
141 public synchronized void close()
142 {
143 try
144 {
145 if( DEBUG )
146 System.out.println("SEND: " + (STREAM_CLOSER));
147
148 if( out != null )
149 {
150 out.write ( STREAM_CLOSER.getBytes () );
151 out.flush();
152 }
153 }
154 catch( IOException x )
155 { }
156
157 if( in != null )
158 try
159 { in.close(); }
160 catch( IOException x )
161 { }
162
163 if( out != null )
164 try
165 { out.close(); }
166 catch( IOException x )
167 { }
168
169 connected = false;
170 authenticated = false;
171 in = null;
172 out = null;
173 }
174
175 public void docStart (String tag, Hashtable attrs)
176 {
177 super.docStart(tag,attrs);
178
179 // authenticate ourselves
180 SHA1 md = new SHA1();
181 String resp = getConnectionId() + secret;
182 if( DEBUG )
183 System.out.println("Making hash from: '"+resp+"'");
184 md.computeDigest( resp.getBytes() );
185 String hash = md.getDigestHex();
186
187 Chunk hs = new Chunk("handshake");
188 hs.setValue(hash);
189
190 try
191 { send(hs); }
192 catch( IOException x )
193 { x.printStackTrace(); }
194 }
195
196 /** From UnrecognizedChunkListener, needed for authentication. */
197 public void incomingChunk(Chunk chunk)
198 {
199 if( chunk.getName().equals("handshake") )
200 authenticated = true;
201 }
202
203 }