001: /*
002: * SSHTools - Java SSH2 API
003: *
004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
005: *
006: * Contributions made by:
007: *
008: * Brett Smith
009: * Richard Pernavas
010: * Erwin Bolwidt
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
025: */
026: package com.sshtools.j2ssh.connection;
027:
028: import com.sshtools.j2ssh.io.ByteArrayWriter;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032:
033: import java.io.IOException;
034: import java.io.InterruptedIOException;
035:
036: import java.net.Socket;
037: import java.net.SocketException;
038:
039: /**
040: *
041: *
042: * @author $author$
043: * @version $Revision: 1.14 $
044: */
045: public abstract class SocketChannel extends Channel {
046: private static Log log = LogFactory.getLog(SocketChannel.class);
047:
048: /** */
049: protected Socket socket = null;
050: Thread thread;
051:
052: /**
053: *
054: *
055: * @param socket
056: *
057: * @throws IOException
058: */
059: public void bindSocket(Socket socket) throws IOException {
060: if (state.getValue() == ChannelState.CHANNEL_UNINITIALIZED) {
061: this .socket = socket;
062: } else {
063: throw new IOException(
064: "The socket can only be bound to an unitialized channel");
065: }
066: }
067:
068: /**
069: *
070: *
071: * @param msg
072: *
073: * @throws IOException
074: */
075: protected void onChannelData(SshMsgChannelData msg)
076: throws IOException {
077: try {
078: socket.getOutputStream().write(msg.getChannelData());
079: } catch (IOException ex) {
080: }
081: }
082:
083: /**
084: *
085: *
086: * @throws IOException
087: */
088: protected void onChannelEOF() throws IOException {
089: try {
090: //synchronized(state) {
091: //if (isOpen())
092: // close();
093: socket.shutdownOutput();
094:
095: // }
096: } catch (IOException ex) {
097: log
098: .info("Failed to shutdown Socket OutputStream in response to EOF event: "
099: + ex.getMessage());
100: }
101: }
102:
103: /**
104: *
105: *
106: * @throws IOException
107: */
108: protected void onChannelClose() throws IOException {
109: try {
110: socket.close();
111: } catch (IOException ex) {
112: log.info("Failed to close socket on channel close event: "
113: + ex.getMessage());
114: }
115: }
116:
117: /**
118: *
119: *
120: * @throws IOException
121: */
122: protected void onChannelOpen() throws IOException {
123: if (socket == null) {
124: throw new IOException(
125: "The socket must be bound to the channel before opening");
126: }
127:
128: thread = new Thread(new SocketReader());
129: thread.start();
130: }
131:
132: /**
133: *
134: *
135: * @param msg
136: *
137: * @throws IOException
138: */
139: protected void onChannelExtData(SshMsgChannelExtendedData msg)
140: throws IOException {
141: // We do not have an extended data channel for the socket so ignore
142: }
143:
144: class SocketReader implements Runnable {
145: public void run() {
146: byte[] buffer = new byte[getMaximumPacketSize()];
147: ByteArrayWriter baw = new ByteArrayWriter();
148:
149: try {
150: socket.setSoTimeout(2000);
151: } catch (SocketException ex2) {
152: }
153:
154: try {
155: int read = 0;
156:
157: while ((read >= 0) && !isClosed()) {
158: try {
159: read = socket.getInputStream().read(buffer);
160: } catch (InterruptedIOException ex1) {
161: read = ex1.bytesTransferred;
162: }
163:
164: synchronized (state) {
165: if (isClosed() || isLocalEOF()) {
166: break;
167: }
168:
169: if (read > 0) {
170: baw.write(buffer, 0, read);
171: sendChannelData(baw.toByteArray());
172: baw.reset();
173: }
174: }
175: }
176: } catch (IOException ex) {
177: // Break out of the while loop
178: }
179:
180: try {
181: synchronized (state) {
182: if (!isLocalEOF()) {
183: setLocalEOF();
184: }
185:
186: if (isOpen()) {
187: close();
188: }
189: }
190: } catch (Exception ex) {
191: log.info("Failed to send channel EOF message: "
192: + ex.getMessage());
193: }
194:
195: thread = null;
196: }
197: }
198: }
|