1 /*
2 * SSHTools - Java SSH2 API
3 *
4 * Copyright (C) 2002-2003 Lee David Painter and Contributors.
5 *
6 * Contributions made by:
7 *
8 * Brett Smith
9 * Richard Pernavas
10 * Erwin Bolwidt
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 */
26 package com.sshtools.j2ssh.transport;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import java.io.IOException;
32
33
34 /**
35 * <p>
36 * This class implements the transport protocol service.
37 * </p>
38 *
39 * <p>
40 * After the transport protocol negotiates the protocol version and performs
41 * server authentication via key exchange, the client requests a service. The
42 * service is identified by a name and currently there are 2 services defined.<br>
43 * <br>
44 * ssh-userauth<br>
45 * ssh-connection<br>
46 * <br>
47 * These 2 services are implemented by the SSH authentication protocol and SSH
48 * connection protocol respectivley. Further services can be defined and a
49 * similar local naming policy is applied to the service names, as is applied
50 * to the algorithm names; a local service should use the
51 * "servicename(at)domain" syntax.
52 * </p>
53 *
54 * @author Lee David Painter
55 * @version $Revision: 1.42 $
56 *
57 * @since 0.2.0
58 */
59 public abstract class Service {
60 private static Log log = LogFactory.getLog(Service.class);
61
62 /**
63 * Service start mode passed into <code>init</code> method when the service
64 * is operating in client mode. i.e its requesting a service to be started
65 * on the remote server and requires a SSH_MSG_SERVICE_ACCEPT message.
66 */
67 public final static int REQUESTING_SERVICE = 1;
68
69 /**
70 * Serivce start mode passed into <code>init</code> method when the service
71 * is operating in server mode. i.e a client is requesting a service to be
72 * started on the local computer and requires the SSH_MSG_SERVICE_ACCEPT
73 * message to be sent.
74 */
75 public final static int ACCEPTING_SERVICE = 2;
76
77 /**
78 * The message store registered with the transport protocol to receive the
79 * service's message.
80 */
81 protected SshMessageStore messageStore = new SshMessageStore();
82
83 /** The underlying transport protocol */
84 protected TransportProtocol transport;
85
86 /** This instances start mode */
87 protected Integer startMode = null;
88
89 /** The current state of the service */
90 protected ServiceState state = new ServiceState();
91
92 /** The name of the service */
93 private String serviceName;
94
95 /**
96 * <p>
97 * Constructs the service.
98 * </p>
99 *
100 * @param serviceName the name of the service
101 *
102 * @since 0.2.0
103 */
104 public Service(String serviceName) {
105 this.serviceName = serviceName;
106 }
107
108 /**
109 * <p>
110 * Returns the service name.
111 * </p>
112 *
113 * @return the serivce name
114 *
115 * @since 0.2.0
116 */
117 public final String getServiceName() {
118 return serviceName;
119 }
120
121 /**
122 * <p>
123 * Starts the service.
124 * </p>
125 *
126 * @throws IOException if an IO error occurs
127 *
128 * @since 0.2.0
129 */
130 public final void start() throws IOException {
131 if (startMode == null) {
132 throw new IOException("Service must be initialized first!");
133 }
134
135 // If were accepted (i.e. client) we will call onServiceAccept()
136 if (startMode.intValue() == REQUESTING_SERVICE) {
137 log.info(serviceName + " has been accepted");
138 onServiceAccept();
139 } else {
140 // We've recevied a request instead
141 log.info(serviceName + " has been requested");
142 onServiceRequest();
143 }
144
145 onStart();
146 state.setValue(ServiceState.SERVICE_STARTED);
147 }
148
149 /**
150 * <p>
151 * Called when the service is started.
152 * </p>
153 *
154 * @throws IOException if an IO error occurs
155 *
156 * @since 0.2.0
157 */
158 protected abstract void onStart() throws IOException;
159
160 /**
161 * <p>
162 * Returns the state of the service.
163 * </p>
164 *
165 * @return the state of the service
166 *
167 * @see ServiceState
168 * @since 0.2.0
169 */
170 public ServiceState getState() {
171 return state;
172 }
173
174 /**
175 * <p>
176 * Initialize the service.
177 * </p>
178 *
179 * @param startMode the mode of the service
180 * @param transport the underlying transport protocol
181 *
182 * @throws IOException if an IO error occurs
183 *
184 * @since 0.2.0
185 */
186 public void init(int startMode, TransportProtocol transport)
187 throws IOException {
188 if ((startMode != REQUESTING_SERVICE) &&
189 (startMode != ACCEPTING_SERVICE)) {
190 throw new IOException("Invalid start mode!");
191 }
192
193 this.transport = transport;
194 this.startMode = new Integer(startMode);
195
196 //this.nativeSettings = nativeSettings;
197 onServiceInit(startMode);
198 transport.addMessageStore(messageStore);
199 }
200
201 /**
202 * <p>
203 * Stops the service.
204 * </p>
205 *
206 * @since 0.2.0
207 */
208 public final void stop() {
209 messageStore.close();
210 state.setValue(ServiceState.SERVICE_STOPPED);
211 }
212
213 /**
214 * <p>
215 * Called when the service is accepted by the remote server.
216 * </p>
217 *
218 * @throws IOException
219 *
220 * @since 0.2.0
221 */
222 protected abstract void onServiceAccept() throws IOException;
223
224 /**
225 * <p>
226 * Called when the service is intialized.
227 * </p>
228 *
229 * @param startMode the mode of the service
230 *
231 * @throws IOException if an IO error occurs
232 *
233 * @since 0.2.0
234 */
235 protected abstract void onServiceInit(int startMode)
236 throws IOException;
237
238 /**
239 *
240 *
241 * @throws IOException
242 */
243 protected abstract void onServiceRequest() throws IOException;
244
245 /**
246 * <p>
247 * Sends the SSH_MSG_SERVICE_ACCEPT message to the client to indicate that
248 * the local computer is accepting the remote computers service request.
249 * </p>
250 *
251 * @throws IOException if an IO error occurs
252 *
253 * @since 0.2.0
254 */
255 protected void sendServiceAccept() throws IOException {
256 SshMsgServiceAccept msg = new SshMsgServiceAccept(serviceName);
257 transport.sendMessage(msg, this);
258 }
259 }