2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.onap.appc.ccadaptor;
27 import com.att.eelf.configuration.EELFLogger;
28 import com.att.eelf.configuration.EELFManager;
29 import com.jcraft.jsch.Channel;
30 import com.jcraft.jsch.ChannelSftp;
31 import com.jcraft.jsch.ChannelShell;
32 import com.jcraft.jsch.ChannelSubsystem;
33 import com.jcraft.jsch.JSch;
34 import com.jcraft.jsch.JSchException;
35 import com.jcraft.jsch.Session;
36 import com.jcraft.jsch.SftpException;
37 import com.jcraft.jsch.UIKeyboardInteractive;
38 import com.jcraft.jsch.UserInfo;
39 import java.io.BufferedInputStream;
40 import java.io.BufferedReader;
41 import java.io.BufferedWriter;
42 import java.io.ByteArrayInputStream;
43 import java.io.ByteArrayOutputStream;
44 import java.io.DataInputStream;
45 import java.io.DataOutputStream;
47 import java.io.FileWriter;
48 import java.io.IOException;
49 import java.io.InputStream;
50 import java.io.InputStreamReader;
51 import java.io.OutputStream;
52 import java.io.RandomAccessFile;
53 import java.text.DateFormat;
54 import java.text.SimpleDateFormat;
55 import java.util.Calendar;
56 import java.util.Date;
57 import java.util.StringTokenizer;
58 import java.util.concurrent.TimeUnit;
59 import javax.annotation.Nonnull;
60 import org.apache.commons.lang.StringUtils;
62 public class SshJcraftWrapper {
64 private static final EELFLogger log = EELFManager.getInstance().getLogger(SshJcraftWrapper.class);
65 static final int DEFAULT_PORT = 22;
66 static final String EOL = "\n";
67 static final String CHANNEL_SHELL_TYPE = "shell";
68 static final String CHANNEL_SUBSYSTEM_TYPE = "subsystem";
69 private static final String TERMINAL_BASIC_MODE = "vt102";
70 static final String STRICT_HOST_CHECK_KEY = "StrictHostKeyChecking";
71 static final String STRICT_HOST_CHECK_VALUE = "no";
72 static final String DELIMITERS_SEPARATOR = "|";
74 private TelnetListener listener = null;
75 private String routerLogFileName = null;
76 private BufferedReader reader = null;
77 private BufferedWriter out = null;
78 private File tmpFile = null;
79 private JSch jsch = null;
80 private Session session = null;
81 private Channel channel = null;
82 private String aggregatedReceivedString = "";
83 private String routerCmdType = "XML";
84 private String routerFileName = null;
85 private File jcraftReadSwConfigFileFromDisk = new File("/tmp/jcraftReadSwConfigFileFromDisk");
86 private String equipNameCode = null;
87 private String routerName = null;
88 private String hostName = null;
89 private String userName = null;
90 private String passWord = null;
91 private int readIntervalMs = 500;
92 private int readBufferSizeBytes = 512_000;
93 private char[] charBuffer;
94 private Runtime runtime = Runtime.getRuntime();
96 public SshJcraftWrapper() {
97 this.jsch = new JSch();
98 this.charBuffer = new char[readBufferSizeBytes];
101 SshJcraftWrapper(JSch jsch, int readIntervalMs, int readBufferSizeBytes) {
102 this.readIntervalMs = readIntervalMs;
104 this.readBufferSizeBytes = readBufferSizeBytes;
105 this.charBuffer = new char[readBufferSizeBytes];
108 public void connect(String hostname, String username, String password, String prompt, int timeOut)
110 log.debug("Attempting to connect to {0} username={1} prompt='{2}' timeOut={3}",
111 hostname, username, prompt, timeOut);
112 routerName = hostname;
117 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, DEFAULT_PORT, timeOut);
118 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
119 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), readBufferSizeBytes);
121 log.info("Successfully connected. Flushing input buffer.");
123 receiveUntil(prompt, 3000, "No cmd was sent, just waiting");
124 } catch (IOException e) {
125 log.warn("Caught an Exception: Nothing to flush out.", e);
127 } catch (JSchException e) {
128 log.error("Could not connect to host=" + hostname, e);
129 throw new IOException(e.toString());
133 // User specifies the port number.
134 public void connect(String hostname, String username, String password, String prompt, int timeOut, int portNum)
136 log.debug("Attempting to connect to {0} username={1} prompt='{2}' timeOut={3} portNum={4}",
137 hostname, username, prompt, timeOut, portNum);
138 routerName = hostname;
143 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, portNum, timeOut);
144 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
145 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), readBufferSizeBytes);
147 log.info("Successfully connected. Flushing input buffer.");
149 if ("]]>]]>".equals(prompt)) {
150 receiveUntil("]]>]]>", 10000, "No cmd was sent, just waiting");
152 receiveUntil(":~#", 5000, "No cmd was sent, just waiting");
154 } catch (IOException e) {
155 log.warn("Caught an Exception: Nothing to flush out.", e);
157 } catch (JSchException e) {
158 log.error("Could not connect to host=" + hostname, e);
159 throw new IOException(e.toString());
164 public String receiveUntil(String delimeters, int timeout, String cmdThatWasSent) throws IOException {
166 boolean match = false;
167 boolean cliPromptCmd = false;
168 StringBuilder sb = new StringBuilder();
169 StringBuilder sbReceive = new StringBuilder();
170 log.debug("delimeters='{0}' timeout={1} cmdThatWasSent='{2}'", delimeters, timeout, cmdThatWasSent);
172 aggregatedReceivedString = "";
173 FileWriter fileWriter = null;
175 long deadline = new Date().getTime() + timeout;
177 session.setTimeout(timeout); // This is the socket timeout value.
179 if (new Date().getTime() > deadline) {
180 String formattedCmd = removeWhiteSpaceAndNewLineCharactersAroundString(cmdThatWasSent);
181 log.error("Routine has timed out: routerName={0} CmdThatWasSent={1}", routerName, formattedCmd);
182 throw new TimedOutException("Routine has timed out");
184 sleep(readIntervalMs);
185 int len = reader.read(charBuffer, 0, readBufferSizeBytes);
186 log.trace("After reader. Read command len={0}", len);
188 log.error("Reader failed to read any bytes. Suspected socket timeout, router={0}", routerName);
189 throw new TimedOutException("Received a SocketTimeoutException router=" + routerName);
192 if (cmdThatWasSent.indexOf("IOS_XR_uploadedSwConfigCmd") != -1) {
194 // This is a IOS XR sw config file. We will write it to the disk.
195 timeout = timeout * 2;
196 deadline = new Date().getTime() + timeout;
197 log.debug("IOS XR upload for software config: timeout={0}", timeout);
198 StringTokenizer st = new StringTokenizer(cmdThatWasSent);
200 routerFileName = st.nextToken();
201 fileWriter = new FileWriter(routerFileName);
202 out = new BufferedWriter(fileWriter);
203 routerLogFileName = "/tmp/" + routerName;
204 tmpFile = new File(routerLogFileName);
205 log.debug("Prepared for writing swConfigFile to disk, routerFileName=" + routerFileName);
207 out.write(charBuffer, 0, len);
209 log.debug("{0} bytes has been written to the disk", len);
210 if (tmpFile.exists()) {
211 appendToRouterFile(routerLogFileName, len);
213 match = checkIfReceivedStringMatchesDelimeter(len, "\nXML>");
222 log.debug("Reader read {0} of data within {1} read iteration", len, readCounts);
225 for (int i = 0; i < len; i++) {
227 if ((c != 7) && (c != 13) && (c != 0) && (c != 27)) {
228 sbReceive.append(charBuffer[i]);
229 sb.append(charBuffer[i]);
232 appendToRouterFile("/tmp/" + routerName, len);
233 if (listener != null) {
234 listener.receivedString(sb.toString());
236 match = checkIfReceivedStringMatchesDelimeter(delimeters, sb.toString(), cmdThatWasSent);
238 log.trace("Match was true, breaking the loop.");
243 log.trace("cliPromptCmd");
245 for (int i = 0; i < len; i++) {
246 sbReceive.append(charBuffer[i]);
247 sb.append(charBuffer[i]);
249 appendToRouterFile("/tmp/" + routerName, sb);
250 if (listener != null) {
251 listener.receivedString(sb.toString());
253 log.debug("sb2={0} delimiters={1}", sb.toString(), delimeters);
254 if (sb.toString().contains("\nariPrompt>")) {
255 log.debug("Found ari prompt");
260 } catch (JSchException e) {
261 log.error("JSchException occurred", e);
262 throw new TimedOutException(e.getMessage());
263 } catch (IOException e) {
264 log.error("IOException occurred", e);
265 throw new TimedOutException(e.getMessage());
268 if (fileWriter != null) {
271 } catch (IOException ex) {
272 log.warn("Failed to close fileWriter output stream", ex);
275 return stripOffCmdFromRouterResponse(sbReceive.toString());
278 private void sleep(long timeoutMs) {
280 TimeUnit.MILLISECONDS.sleep(timeoutMs);
281 } catch (java.lang.InterruptedException ee) {
282 Thread.currentThread().interrupt();
286 private void checkConnection() {
288 if (!isConnected() || !reader.ready()) {
289 throw new IllegalStateException("Connection not established. Cannot perform action.");
291 } catch (IOException e) {
292 throw new IllegalStateException("Reader stream is closed. Cannot perform action.", e);
296 public boolean checkIfReceivedStringMatchesDelimeter(String delimeters, String receivedString,
297 String cmdThatWasSent) {
298 // The delimeters are in a '|' seperated string. Return true on the first match.
299 log.debug("Entered checkIfReceivedStringMatchesDelimeter: delimeters={0} cmdThatWasSent={1} receivedString={2}",
300 delimeters, cmdThatWasSent, receivedString);
301 StringTokenizer st = new StringTokenizer(delimeters, DELIMITERS_SEPARATOR);
303 if ((delimeters.contains("#$")) || ("CLI".equals(routerCmdType))) // This would be an IOS XR, CLI command.
305 int x = receivedString.lastIndexOf('#');
306 int y = receivedString.length() - 1;
307 log.debug("IOS XR, CLI command");
308 if (log.isTraceEnabled()) {
309 log.trace("cmdThatWasSent={0}, lastIndexOf hash delimiter={1}, maxIndexNum={2}", cmdThatWasSent, x, y);
311 return (x != -1) && (y == x);
313 if (cmdThatWasSent.contains("show config")) {
314 log.trace("In the block for 'show config'");
315 while (st.hasMoreTokens()) {
316 String delimeter = st.nextToken();
317 // Make sure we don't get faked out by a response of " #".
319 // # signaling-local-address ipv6 FD00:F4D5:EA06:1::110:136:254
321 int x = receivedString.lastIndexOf(delimeter);
322 if ((receivedString.lastIndexOf(delimeter) != -1) && (receivedString.lastIndexOf(" #") != x - 1)) {
323 log.debug("receivedString={0}", receivedString);
324 log.trace("Found ending for 'show config' command, exiting.");
329 aggregatedReceivedString = aggregatedReceivedString + receivedString;
330 appendToFile("/tmp/aggregatedReceivedString.debug", aggregatedReceivedString);
332 log.debug("receivedString={0}", receivedString);
333 while (st.hasMoreTokens()) {
334 String delimeter = st.nextToken();
335 log.debug("Looking for an delimiter of:{0}", delimeter);
336 if (aggregatedReceivedString.indexOf(delimeter) != -1) {
337 log.debug("Found delimiter={0}, exiting", delimeter);
338 aggregatedReceivedString = "";
346 public boolean checkIfReceivedStringMatchesDelimeter(int len, String delimeter) {
349 String str = StringUtils.EMPTY;
351 if (jcraftReadSwConfigFileFromDisk()) {
352 log.trace("jcraftReadSwConfigFileFromDisk block");
353 File fileName = new File(routerFileName);
354 log.debug("jcraftReadSwConfigFileFromDisk::: Will read the tail end of the file from the disk");
356 str = getLastFewLinesOfFile(fileName, 3);
357 } catch (IOException e) {
358 log.warn("IOException occurred, while reading file=" + fileName, e);
361 // When looking at the end of the charBuffer, don't include any linefeeds or spaces. We only want to make the smallest string possible.
362 for (x = len - 1; x >= 0; x--) {
364 if ((c != 10) && (c != 32)) // Not a line feed nor a space.
369 if ((x + 1 - 13) >= 0) {
370 str = new String(charBuffer, x + 1 - 13, 13);
371 log.debug("str:{0}", str);
373 File fileName = new File(routerFileName);
374 log.debug("Will read the tail end of the file from the disk, x={0} len={1} str={2} routerFileName={3}",
375 x, len, str, routerFileName);
377 str = getLastFewLinesOfFile(fileName, 3);
378 } catch (IOException e) {
379 log.warn("IOException occurred, while reading file=" + fileName, e);
384 log.debug("Parsed string was str='{0}', searched delimiter was {1}");
385 return str.contains(delimeter);
388 public void closeConnection() {
389 log.info("Closing connection");
391 if (reader != null) {
394 } catch(IOException ex) {
395 log.warn("Could not close reader instance", ex);
398 channel.disconnect();
399 session.disconnect();
407 boolean isConnected() {
408 return (channel != null && session != null);
411 public void send(String cmd) throws IOException {
412 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
413 sendSshCommand(cmd, dos);
414 } catch (IOException e) {
415 log.error("IOException occurred while sending command=" + cmd, e);
420 public void sendChar(int v) throws IOException {
421 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
422 if (log.isTraceEnabled()) {
423 log.trace("Sending charCode: {0}", v);
427 } catch (IOException e) {
428 log.error("IOException occurred while writing char to channel output stream", e);
433 public void send(byte[] b, int off, int len) throws IOException {
434 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
435 dos.write(b, off, len);
437 } catch (IOException e) {
438 log.error("IOException occurred while writing bytes to channel output stream", e);
443 public static class MyUserInfo implements UserInfo, UIKeyboardInteractive {
446 public String getPassword() {
451 public boolean promptYesNo(String str) {
456 public String getPassphrase() {
461 public boolean promptPassphrase(String message) {
466 public boolean promptPassword(String message) {
471 public void showMessage(String message) {
476 public String[] promptKeyboardInteractive(String destination,
481 return new String[0];
485 public void addListener(TelnetListener listener) {
486 this.listener = listener;
489 private void appendToFile(String fileName, String dataToWrite) {
490 File outputFile = new File(fileName);
491 if (outputFile.exists()) {
492 try (FileWriter fw = new FileWriter(fileName, true); BufferedWriter ow = new BufferedWriter(fw)) {
493 ow.write(dataToWrite);
495 } catch (IOException e) {
496 log.error("IOException occurred while writing to file=" + fileName, e);
501 public String getTheDate() {
502 DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy H:mm:ss ");
503 return dateFormat.format(Calendar.getInstance().getTime());
507 public void appendToRouterFile(String fileName, StringBuilder dataToWrite) {
508 appendToFile(fileName, dataToWrite.toString());
511 public void appendToRouterFile(String fileName, int len) {
512 File outputFile = new File(fileName);
513 if (outputFile.exists()) {
514 try (FileWriter fw = new FileWriter(fileName, true); BufferedWriter ow = new BufferedWriter(fw)) {
515 ow.write(charBuffer, 0, len);
517 } catch (IOException e) {
518 log.error("IOException occurred while writing to router file=" + fileName, e);
523 public String removeWhiteSpaceAndNewLineCharactersAroundString(String str) {
524 if (str != null && !StringUtils.EMPTY.equals(str)) {
525 StringTokenizer strTok = new StringTokenizer(str, EOL);
526 StringBuilder sb = new StringBuilder();
528 while (strTok.hasMoreTokens()) {
529 String line = strTok.nextToken();
532 return sb.toString().trim();
534 return StringUtils.EMPTY;
537 public String stripOffCmdFromRouterResponse(String routerResponse) {
538 // The session of SSH will echo the command sent to the router, in the router's response.
539 // Since all our commands are terminated by a '\n', strip off the first line
540 // of the response from the router. This first line contains the orginal command.
542 String[] responseTokens = routerResponse.split(EOL, 2);
543 return responseTokens[responseTokens.length-1];
546 public void setRouterCommandType(String type) {
547 this.routerCmdType = type;
548 log.debug("Router command type is set to: {0}", type);
551 public String getLastFewLinesOfFile(File file, int linesToRead) throws IOException {
552 RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
554 StringBuilder builder = new StringBuilder();
556 long length = file.length();
558 randomAccessFile.seek(length);
559 for (long seek = length; seek >= 0; --seek) {
560 randomAccessFile.seek(seek);
561 char c = (char) randomAccessFile.read();
564 builder = builder.reverse();
565 tail = builder.toString() + tail;
567 builder.setLength(0);
568 if (lines == linesToRead) {
573 randomAccessFile.close();
574 if (log.isDebugEnabled()) {
575 log.debug("Content read from file={0} was tail={1}", file.getName(), tail);
580 public boolean jcraftReadSwConfigFileFromDisk() {
581 return jcraftReadSwConfigFileFromDisk.exists();
584 public String getEquipNameCode() {
585 return equipNameCode;
588 public void setEquipNameCode(String equipNameCode) {
589 this.equipNameCode = equipNameCode;
592 public String getRouterName() {
596 // Routine does reads until it has read 'nchars' or times out.
597 public void receiveUntilBufferFlush(int ncharsSent, int timeout, String message) throws IOException {
598 log.debug("ncharsSent={0}, timeout={1}, message={2}", ncharsSent, timeout, message);
599 int ncharsTotalReceived = 0;
602 long deadline = new Date().getTime() + timeout;
605 session.setTimeout(timeout); // This is the socket timeout value.
607 if (new Date().getTime() > deadline) {
608 log.error("Routine has timed out: ncharsSent={0}, ncharsTotalReceived={1}", ncharsSent,
609 ncharsTotalReceived);
610 throw new TimedOutException("Routine has timed out");
612 ncharsRead = reader.read(charBuffer, 0, readBufferSizeBytes);
613 if (listener != null) {
614 listener.receivedString(String.copyValueOf(charBuffer, 0, ncharsRead));
616 appendToRouterFile("/tmp/" + routerName, ncharsRead);
617 ncharsTotalReceived = ncharsTotalReceived + ncharsRead;
618 if (ncharsTotalReceived >= ncharsSent) {
619 log.debug("Received the correct number of characters, ncharsSent={0}, ncharsTotalReceived={1}",
620 ncharsSent, ncharsTotalReceived);
625 } catch (JSchException e) {
626 log.error("JSchException occurred while command sending", e);
627 log.debug("ncharsSent={0}, ncharsTotalReceived={1}, ncharsRead={2} until error occurred",
628 ncharsSent, ncharsTotalReceived, ncharsRead);
629 throw new TimedOutException(e.getMessage());
633 public String getHostName() {
637 public String getUserName() {
641 public String getPassWord() {
645 public void sftpPutFile(String sourcePath, String destDirectory) throws IOException {
647 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
648 UserInfo ui = new MyUserInfo();
649 sftpSession.setPassword(passWord);
650 sftpSession.setUserInfo(ui);
651 sftpSession.connect(30 * 1000);
652 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
654 log.debug("Sending via sftp from source: {0} to destination: {1}", sourcePath, destDirectory);
655 sftp.put(sourcePath, destDirectory, ChannelSftp.OVERWRITE);
656 sftpSession.disconnect();
657 } catch (JSchException ex) {
658 log.error("JSchException occurred while handling sftp session", ex);
659 throw new IOException(ex.getMessage());
660 } catch (SftpException ex) {
661 log.error("SftpException occurred during file transfer", ex);
662 throw new IOException(ex.getMessage());
666 public void sftpPutStringData(String stringOfData, String fullPathDest) throws IOException {
668 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
669 UserInfo ui = new MyUserInfo();
670 sftpSession.setPassword(passWord);
671 sftpSession.setUserInfo(ui);
672 sftpSession.connect(30 * 1000);
673 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
675 InputStream is = new ByteArrayInputStream(stringOfData.getBytes());
676 log.debug("Sending via sftp stringOfData to destination: {0}", fullPathDest);
677 sftp.put(is, fullPathDest, ChannelSftp.OVERWRITE);
678 sftpSession.disconnect();
679 } catch (JSchException ex) {
680 log.error("JSchException occurred while handling sftp session", ex);
681 throw new IOException(ex.getMessage());
682 } catch (SftpException ex) {
683 log.error("SftpException occurred during data transfer", ex);
684 throw new IOException(ex.getMessage());
688 public String sftpGet(String fullFilePathName) throws IOException {
690 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
691 UserInfo ui = new MyUserInfo();
692 sftpSession.setPassword(passWord);
693 sftpSession.setUserInfo(ui);
694 sftpSession.connect(30 * 1000);
695 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
697 InputStream in = sftp.get(fullFilePathName);
698 String sftpFileString = readInputStreamAsString(in);
699 log.debug("Received data via sftp connection sftpFileString={0} from fullFilePathName={1}",
700 sftpFileString, fullFilePathName);
701 sftpSession.disconnect();
702 return sftpFileString;
703 } catch (JSchException ex) {
704 log.error("JSchException occurred while handling sftp session", ex);
705 throw new IOException(ex.getMessage());
706 } catch (SftpException ex) {
707 log.error("SftpException occurred during data transfer", ex);
708 throw new IOException(ex.getMessage());
712 public static String readInputStreamAsString(InputStream in) throws IOException {
713 BufferedInputStream bis = new BufferedInputStream(in);
714 ByteArrayOutputStream buf = new ByteArrayOutputStream();
715 int result = bis.read();
716 while (result != -1) {
717 byte b = (byte) result;
721 return buf.toString();
725 public void logMemoryUsage() {
726 int mb = 1024 * 1024;
728 long maxMemoryAvailable;
729 long memoryLeftOnHeap;
730 maxMemoryAvailable =runtime.maxMemory() / mb;
731 usedMemory = (runtime.totalMemory() / mb) - (runtime.freeMemory() / mb);
732 memoryLeftOnHeap = maxMemoryAvailable - usedMemory;
733 log.info("Memory usage: maxMemoryAvailable={0}, usedMemory={1}, memoryLeftOnHeap={2}",
734 maxMemoryAvailable, usedMemory, memoryLeftOnHeap);
737 public void connect(String hostname, String username, String password, int timeOut, int portNum,
738 String subsystem) throws IOException {
740 if (log.isDebugEnabled()) {
742 "Attempting to connect to {0} username={1} timeOut={2} portNum={3} subsystem={4}",
743 hostname, username, timeOut, portNum, subsystem);
745 this.routerName = hostname;
746 this.hostName = hostname;
747 this.userName = username;
748 this.passWord = password;
750 channel = provideSessionChannel(CHANNEL_SUBSYSTEM_TYPE, portNum, timeOut);
751 ((ChannelSubsystem) channel).setSubsystem(subsystem);
752 ((ChannelSubsystem) channel).setPty(true); //expected ptyType vt102
753 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), readBufferSizeBytes);
754 channel.connect(5000);
755 } catch (JSchException e) {
756 log.error("JschException occurred ", e);
757 throw new IOException(e.getMessage());
761 public void connect(String hostName, String username, String password) throws IOException {
762 log.debug("Attempting to connect to {0} username={1} portNumber={2}", hostName, username, DEFAULT_PORT);
763 this.routerName = hostName;
764 this.hostName = hostName;
765 this.userName = username;
766 this.passWord = password;
768 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, DEFAULT_PORT, 30000);
769 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
770 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), readBufferSizeBytes);
773 receiveUntil(":~#", 9000, "No cmd was sent, just waiting, but we can stop on a '~#'");
774 } catch (Exception e) {
775 log.warn("Caught an Exception: Nothing to flush out.", e);
778 } catch (JSchException e) {
779 log.error("JschException occurred ", e);
780 throw new IOException(e.getMessage());
785 public void put(String sourcePath, String destDirectory) throws IOException {
787 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
788 UserInfo ui = new MyUserInfo();
789 sftpSession.setPassword(passWord);
790 sftpSession.setUserInfo(ui);
791 sftpSession.connect(30 * 1000);
792 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
794 log.debug("Sending via sftp from source: {0} to destination: {1}", sourcePath, destDirectory);
795 sftp.put(sourcePath, destDirectory, ChannelSftp.OVERWRITE);
796 sftpSession.disconnect();
797 } catch (JSchException ex) {
798 log.error("JSchException occurred while handling sftp session", ex);
799 throw new IOException(ex.getMessage());
800 } catch (SftpException ex) {
801 log.error("SftpException occurred during file transfer", ex);
802 throw new IOException(ex.getMessage());
806 public void put(InputStream is, String fullPathDest, String hostName, String userName, String passWord)
808 Session sftpSession = null;
810 log.debug("Sftp put invoked, connection details: username={1} hostname={2}",
813 java.util.Properties config = new java.util.Properties();
814 config.put("StrictHostKeyChecking", "no");
815 sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
816 UserInfo ui = new MyUserInfo();
817 sftpSession.setPassword(passWord);
818 sftpSession.setUserInfo(ui);
819 sftpSession.setConfig(config);
820 sftpSession.connect(30 * 1000);
821 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
823 String oldFiles = fullPathDest + "*";
824 log.debug("Deleting old files: {0}", oldFiles);
827 } catch (SftpException ex) {
828 String exp = "No such file";
829 if (ex.getMessage() != null && ex.getMessage().contains(exp)) {
830 log.warn("No files found, continue");
832 log.error("SftpException while invoking rm command over sftp", ex);
836 log.debug("Sending stringOfData to destination {0}", fullPathDest);
837 sftp.put(is, fullPathDest, ChannelSftp.OVERWRITE);
838 } catch (JSchException ex) {
839 log.error("JSchException occurred while handling sftp session", ex);
840 throw new IOException(ex.getMessage());
841 } catch (SftpException ex) {
842 log.error("SftpException occurred during file transfer", ex);
843 throw new IOException(ex.getMessage());
845 if (sftpSession != null) {
846 sftpSession.disconnect();
851 public String get(String fullFilePathName, String hostName, String userName, String passWord) throws IOException {
852 Session sftpSession = null;
854 log.debug("Sftp get invoked, connection details: username={1} hostname={2}",
857 sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
858 java.util.Properties config = new java.util.Properties();
859 config.put("StrictHostKeyChecking", "no");
860 UserInfo ui = new MyUserInfo();
861 sftpSession.setPassword(passWord);
862 sftpSession.setUserInfo(ui);
863 sftpSession.setConfig(config);
864 sftpSession.connect(30 * 1000);
865 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
867 InputStream in = sftp.get(fullFilePathName);
868 return readInputStreamAsString(in);
869 } catch (JSchException ex) {
870 log.error("JSchException occurred while handling sftp session", ex);
871 throw new IOException(ex.getMessage());
872 } catch (SftpException ex) {
873 log.error("SftpException occurred during file transfer", ex);
874 throw new IOException(ex.getMessage());
876 if (sftpSession != null) {
877 sftpSession.disconnect();
882 public String send(String cmd, String delimiter) throws IOException {
883 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
884 sendSshCommand(cmd, dos);
885 return receiveUntil(delimiter, 300000, cmd);
886 } catch (IOException ex) {
887 log.error("IOException occurred", ex);
888 throw new IOException(ex.getMessage());
892 private void sendSshCommand(@Nonnull String originalCommand, @Nonnull DataOutputStream channelOutputStream)
894 String command = enhanceCommandWithEOL(originalCommand);
895 int length = command.length(); // 2,937,706
896 int charsChunkSize = 300000;
897 int charsTotalSent = 0;
899 log.debug("Sending ssh command: length={0}, payload: {1}", length, command);
900 if (isCmdLengthEnoughToSendInChunks(length, charsChunkSize)) {
902 for (int i = 0; i < length; i += charsChunkSize) {
903 String commandChunk = command.substring(i, Math.min(length, i + charsChunkSize));
904 int numCharsSentInChunk = commandChunk.length();
905 charsTotalSent = charsTotalSent + commandChunk.length();
906 log.debug("Iteration nr:{0}, sending command chunk: {1}", i, numCharsSentInChunk);
907 channelOutputStream.writeBytes(commandChunk);
908 channelOutputStream.flush();
910 if (numCharsSentInChunk < length) {
911 receiveUntilBufferFlush(numCharsSentInChunk, timeout, "buffer flush i=" + i);
913 log.trace("i={0}, flush immediately", i);
914 channelOutputStream.flush();
916 } catch (IOException ex) {
917 log.warn("IOException occurred: nothing to flush out", ex);
921 channelOutputStream.writeBytes(command);
923 channelOutputStream.flush();
926 private boolean isCmdLengthEnoughToSendInChunks(int length, int chunkSize) {
927 return length > 2 * chunkSize;
930 private String enhanceCommandWithEOL(@Nonnull String originalCommand) {
931 char commandEnding = originalCommand.charAt(originalCommand.length() - 1);
932 if (commandEnding != '\n' && commandEnding != '\r') {
933 return originalCommand + EOL;
935 return originalCommand;
938 private Channel provideSessionChannel(String channelType, int port, int timeout) throws JSchException {
939 session = jsch.getSession(this.userName, this.hostName, port);
940 session.setPassword(this.passWord);
941 session.setUserInfo(new MyUserInfo()); //needed?
942 session.setConfig(STRICT_HOST_CHECK_KEY, STRICT_HOST_CHECK_VALUE);
943 session.connect(timeout);
944 session.setServerAliveCountMax(
945 0); // If this is not set to '0', then socket timeout on all reads will not work!!!!
946 return session.openChannel(channelType);