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;
61 import org.onap.appc.i18n.Msg;
63 public class SshJcraftWrapper {
65 private static final EELFLogger log = EELFManager.getInstance().getLogger(SshJcraftWrapper.class);
66 static final int DEFAULT_PORT = 22;
67 static final String EOL = "\n";
68 static final String CHANNEL_SHELL_TYPE = "shell";
69 static final String CHANNEL_SUBSYSTEM_TYPE = "subsystem";
70 private static final String TERMINAL_BASIC_MODE = "vt102";
71 static final String STRICT_HOST_CHECK_KEY = "StrictHostKeyChecking";
72 static final String STRICT_HOST_CHECK_VALUE = "no";
73 static final String DELIMITERS_SEPARATOR = "|";
75 private TelnetListener listener = null;
76 private String routerLogFileName = null;
77 private BufferedReader reader = null;
78 private BufferedWriter out = null;
79 private File tmpFile = null;
80 private JSch jsch = null;
81 private Session session = null;
82 private Channel channel = null;
83 private String aggregatedReceivedString = "";
84 private String routerCmdType = "XML";
85 private String routerFileName = null;
86 private File jcraftReadSwConfigFileFromDisk = new File("/tmp/jcraftReadSwConfigFileFromDisk");
87 private String equipNameCode = null;
88 private String routerName = null;
89 private String hostName = null;
90 private String userName = null;
91 private String passWord = null;
92 private int readIntervalMs = 500;
93 private int readBufferSizeBytes = 512_000;
94 private char[] charBuffer;
95 private Runtime runtime = Runtime.getRuntime();
97 public SshJcraftWrapper() {
98 this.jsch = new JSch();
99 this.charBuffer = new char[readBufferSizeBytes];
102 SshJcraftWrapper(JSch jsch, int readIntervalMs, int readBufferSizeBytes) {
103 this.readIntervalMs = readIntervalMs;
105 this.readBufferSizeBytes = readBufferSizeBytes;
106 this.charBuffer = new char[readBufferSizeBytes];
109 public void connect(String hostname, String username, String password, String prompt, int timeOut)
111 log.debug("Attempting to connect to {0} username={1} prompt='{2}' timeOut={3}",
112 hostname, username, prompt, timeOut);
113 routerName = hostname;
118 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, DEFAULT_PORT, timeOut);
119 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
120 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())),
121 readBufferSizeBytes);
123 log.info("Successfully connected. Flushing input buffer.");
125 receiveUntil(prompt, 3000, "No cmd was sent, just waiting");
126 } catch (IOException e) {
127 log.warn("Caught an Exception: Nothing to flush out.", e);
129 } catch (JSchException e) {
130 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostname, String.valueOf(DEFAULT_PORT), username);
131 throw new IOException(e.toString());
135 // User specifies the port number.
136 public void connect(String hostname, String username, String password, String prompt, int timeOut, int portNum)
138 log.debug("Attempting to connect to {0} username={1} prompt='{2}' timeOut={3} portNum={4}",
139 hostname, username, prompt, timeOut, portNum);
140 routerName = hostname;
145 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, portNum, timeOut);
146 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
147 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())),
148 readBufferSizeBytes);
150 log.info("Successfully connected. Flushing input buffer.");
152 if ("]]>]]>".equals(prompt)) {
153 receiveUntil("]]>]]>", 10000, "No cmd was sent, just waiting");
155 receiveUntil(":~#", 5000, "No cmd was sent, just waiting");
157 } catch (IOException e) {
158 log.warn("Caught an Exception: Nothing to flush out.", e);
160 } catch (JSchException e) {
161 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostname, String.valueOf(portNum), username);
162 throw new IOException(e.toString());
167 public String receiveUntil(String delimeters, int timeout, String cmdThatWasSent) throws IOException {
169 boolean match = false;
170 boolean cliPromptCmd = false;
171 StringBuilder sb = new StringBuilder();
172 StringBuilder sbReceive = new StringBuilder();
173 log.debug("delimeters='{0}' timeout={1} cmdThatWasSent='{2}'", delimeters, timeout, cmdThatWasSent);
175 aggregatedReceivedString = "";
176 FileWriter fileWriter = null;
178 long deadline = new Date().getTime() + timeout;
180 session.setTimeout(timeout); // This is the socket timeout value.
182 if (new Date().getTime() > deadline) {
183 String formattedCmd = removeWhiteSpaceAndNewLineCharactersAroundString(cmdThatWasSent);
184 log.error(Msg.SSH_CONNECTION_TIMEOUT, routerName, formattedCmd);
185 throw new TimedOutException("Routine has timed out");
187 sleep(readIntervalMs);
188 int len = reader.read(charBuffer, 0, readBufferSizeBytes);
189 log.trace("After reader. Read command len={0}", len);
191 log.error(Msg.SSH_CONNECTION_TIMEOUT, routerName, cmdThatWasSent);
192 throw new TimedOutException("Received a SocketTimeoutException router=" + routerName);
195 if (cmdThatWasSent.indexOf("IOS_XR_uploadedSwConfigCmd") != -1) {
197 // This is a IOS XR sw config file. We will write it to the disk.
198 timeout = timeout * 2;
199 deadline = new Date().getTime() + timeout;
200 log.debug("IOS XR upload for software config: timeout={0}", timeout);
201 StringTokenizer st = new StringTokenizer(cmdThatWasSent);
203 routerFileName = st.nextToken();
204 fileWriter = new FileWriter(routerFileName);
205 out = new BufferedWriter(fileWriter);
206 routerLogFileName = "/tmp/" + routerName;
207 tmpFile = new File(routerLogFileName);
208 log.debug("Prepared for writing swConfigFile to disk, routerFileName=" + routerFileName);
210 out.write(charBuffer, 0, len);
212 log.debug("{0} bytes has been written to the disk", len);
213 if (tmpFile.exists()) {
214 appendToRouterFile(routerLogFileName, len);
216 match = checkIfReceivedStringMatchesDelimeter(len, "\nXML>");
225 log.debug("Reader read {0} of data within {1} read iteration", len, readCounts);
228 for (int i = 0; i < len; i++) {
230 if ((c != 7) && (c != 13) && (c != 0) && (c != 27)) {
231 sbReceive.append(charBuffer[i]);
232 sb.append(charBuffer[i]);
235 appendToRouterFile("/tmp/" + routerName, len);
236 if (listener != null) {
237 listener.receivedString(sb.toString());
239 match = checkIfReceivedStringMatchesDelimeter(delimeters, sb.toString(), cmdThatWasSent);
241 log.trace("Match was true, breaking the loop.");
246 log.trace("cliPromptCmd");
248 for (int i = 0; i < len; i++) {
249 sbReceive.append(charBuffer[i]);
250 sb.append(charBuffer[i]);
252 appendToRouterFile("/tmp/" + routerName, sb);
253 if (listener != null) {
254 listener.receivedString(sb.toString());
256 log.debug("sb2={0} delimiters={1}", sb.toString(), delimeters);
257 if (sb.toString().contains("\nariPrompt>")) {
258 log.debug("Found ari prompt");
263 } catch (JSchException | IOException e) {
264 log.error(Msg.SSH_DATA_EXCEPTION, e.getMessage());
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(Msg.SSH_DATA_EXCEPTION, e.getMessage());
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(Msg.SSH_DATA_EXCEPTION, e.getMessage());
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(Msg.SSH_DATA_EXCEPTION, e.getMessage());
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.warn("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.warn("Could not write data 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 command) throws IOException {
598 log.debug("ncharsSent={0}, timeout={1}, message={2}", ncharsSent, timeout, command);
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(Msg.SSH_CONNECTION_TIMEOUT, routerName, command);
609 throw new TimedOutException("Routine has timed out");
611 ncharsRead = reader.read(charBuffer, 0, readBufferSizeBytes);
612 if (listener != null) {
613 listener.receivedString(String.copyValueOf(charBuffer, 0, ncharsRead));
615 appendToRouterFile("/tmp/" + routerName, ncharsRead);
616 ncharsTotalReceived = ncharsTotalReceived + ncharsRead;
617 if (ncharsTotalReceived >= ncharsSent) {
618 log.debug("Received the correct number of characters, ncharsSent={0}, ncharsTotalReceived={1}",
619 ncharsSent, ncharsTotalReceived);
624 } catch (JSchException e) {
625 log.error(Msg.SSH_SESSION_CONFIG_ERROR, e.getMessage());
626 log.debug("ncharsSent={0}, ncharsTotalReceived={1}, ncharsRead={2} until error occurred",
627 ncharsSent, ncharsTotalReceived, ncharsRead);
628 throw new TimedOutException(e.getMessage());
632 public String getHostName() {
636 public String getUserName() {
640 public String getPassWord() {
644 public void sftpPutFile(String sourcePath, String destDirectory) throws IOException {
646 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
647 UserInfo ui = new MyUserInfo();
648 sftpSession.setPassword(passWord);
649 sftpSession.setUserInfo(ui);
650 sftpSession.connect(30 * 1000);
651 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
653 log.debug("Sending via sftp from source: {0} to destination: {1}", sourcePath, destDirectory);
654 sftp.put(sourcePath, destDirectory, ChannelSftp.OVERWRITE);
655 sftpSession.disconnect();
656 } catch (JSchException ex) {
657 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostName, String.valueOf(DEFAULT_PORT), userName);
658 throw new IOException(ex.getMessage());
659 } catch (SftpException ex) {
660 log.error(Msg.SFTP_TRANSFER_FAILED, hostName, userName, "PUT", ex.getMessage());
661 throw new IOException(ex.getMessage());
665 public void sftpPutStringData(String stringOfData, String fullPathDest) throws IOException {
667 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
668 UserInfo ui = new MyUserInfo();
669 sftpSession.setPassword(passWord);
670 sftpSession.setUserInfo(ui);
671 sftpSession.connect(30 * 1000);
672 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
674 InputStream is = new ByteArrayInputStream(stringOfData.getBytes());
675 log.debug("Sending via sftp stringOfData to destination: {0}", fullPathDest);
676 sftp.put(is, fullPathDest, ChannelSftp.OVERWRITE);
677 sftpSession.disconnect();
678 } catch (JSchException ex) {
679 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostName, String.valueOf(DEFAULT_PORT), userName);
680 throw new IOException(ex.getMessage());
681 } catch (SftpException ex) {
682 log.error(Msg.SFTP_TRANSFER_FAILED, hostName, userName, "PUT", ex.getMessage());
683 throw new IOException(ex.getMessage());
687 public String sftpGet(String fullFilePathName) throws IOException {
689 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
690 UserInfo ui = new MyUserInfo();
691 sftpSession.setPassword(passWord);
692 sftpSession.setUserInfo(ui);
693 sftpSession.connect(30 * 1000);
694 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
696 InputStream in = sftp.get(fullFilePathName);
697 String sftpFileString = readInputStreamAsString(in);
698 log.debug("Received data via sftp connection sftpFileString={0} from fullFilePathName={1}",
699 sftpFileString, fullFilePathName);
700 sftpSession.disconnect();
701 return sftpFileString;
702 } catch (JSchException ex) {
703 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostName, String.valueOf(DEFAULT_PORT), userName);
704 throw new IOException(ex.getMessage());
705 } catch (SftpException ex) {
706 log.error(Msg.SFTP_TRANSFER_FAILED, hostName, userName, "GET", ex.getMessage());
707 throw new IOException(ex.getMessage());
711 public static String readInputStreamAsString(InputStream in) throws IOException {
712 BufferedInputStream bis = new BufferedInputStream(in);
713 ByteArrayOutputStream buf = new ByteArrayOutputStream();
714 int result = bis.read();
715 while (result != -1) {
716 byte b = (byte) result;
720 return buf.toString();
724 public void logMemoryUsage() {
725 int mb = 1024 * 1024;
727 long maxMemoryAvailable;
728 long memoryLeftOnHeap;
729 maxMemoryAvailable = runtime.maxMemory() / mb;
730 usedMemory = (runtime.totalMemory() / mb) - (runtime.freeMemory() / mb);
731 memoryLeftOnHeap = maxMemoryAvailable - usedMemory;
732 log.info("Memory usage: maxMemoryAvailable={0}, usedMemory={1}, memoryLeftOnHeap={2}",
733 maxMemoryAvailable, usedMemory, memoryLeftOnHeap);
736 public void connect(String hostname, String username, String password, int timeOut, int portNum,
737 String subsystem) throws IOException {
739 if (log.isDebugEnabled()) {
741 "Attempting to connect to {0} username={1} timeOut={2} portNum={3} subsystem={4}",
742 hostname, username, timeOut, portNum, subsystem);
744 this.routerName = hostname;
745 this.hostName = hostname;
746 this.userName = username;
747 this.passWord = password;
749 channel = provideSessionChannel(CHANNEL_SUBSYSTEM_TYPE, portNum, timeOut);
750 ((ChannelSubsystem) channel).setSubsystem(subsystem);
751 ((ChannelSubsystem) channel).setPty(true); //expected ptyType vt102
752 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())),
753 readBufferSizeBytes);
754 channel.connect(5000);
755 } catch (JSchException e) {
756 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostname, String.valueOf(portNum), username);
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())),
771 readBufferSizeBytes);
774 receiveUntil(":~#", 9000, "No cmd was sent, just waiting, but we can stop on a '~#'");
775 } catch (Exception e) {
776 log.warn("Caught an Exception: Nothing to flush out.", e);
779 } catch (JSchException e) {
780 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostName, String.valueOf(DEFAULT_PORT), username);
781 throw new IOException(e.getMessage());
786 public void put(String sourcePath, String destDirectory) throws IOException {
788 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
789 UserInfo ui = new MyUserInfo();
790 sftpSession.setPassword(passWord);
791 sftpSession.setUserInfo(ui);
792 sftpSession.connect(30 * 1000);
793 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
795 log.debug("Sending via sftp from source: {0} to destination: {1}", sourcePath, destDirectory);
796 sftp.put(sourcePath, destDirectory, ChannelSftp.OVERWRITE);
797 sftpSession.disconnect();
798 } catch (JSchException ex) {
799 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostName, String.valueOf(DEFAULT_PORT), userName);
800 throw new IOException(ex.getMessage());
801 } catch (SftpException ex) {
802 log.error(Msg.SFTP_TRANSFER_FAILED, hostName, userName, "PUT", ex.getMessage());
803 throw new IOException(ex.getMessage());
807 public void put(InputStream is, String fullPathDest, String hostName, String userName, String passWord)
809 Session sftpSession = null;
811 log.debug("Sftp put invoked, connection details: username={1} hostname={2}",
814 java.util.Properties config = new java.util.Properties();
815 config.put("StrictHostKeyChecking", "no");
816 sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
817 UserInfo ui = new MyUserInfo();
818 sftpSession.setPassword(passWord);
819 sftpSession.setUserInfo(ui);
820 sftpSession.setConfig(config);
821 sftpSession.connect(30 * 1000);
822 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
824 String oldFiles = fullPathDest + "*";
825 log.debug("Deleting old files: {0}", oldFiles);
828 } catch (SftpException ex) {
829 String exp = "No such file";
830 if (ex.getMessage() != null && ex.getMessage().contains(exp)) {
831 log.warn("No files found, continue");
833 log.error(Msg.SFTP_TRANSFER_FAILED, hostName, userName, "RM", ex.getMessage());
837 log.debug("Sending stringOfData to destination {0}", fullPathDest);
838 sftp.put(is, fullPathDest, ChannelSftp.OVERWRITE);
839 } catch (JSchException ex) {
840 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostName, String.valueOf(DEFAULT_PORT), userName);
841 throw new IOException(ex.getMessage());
842 } catch (SftpException ex) {
843 log.error(Msg.SFTP_TRANSFER_FAILED, hostName, userName, "PUT", ex.getMessage());
844 throw new IOException(ex.getMessage());
846 if (sftpSession != null) {
847 sftpSession.disconnect();
852 public String get(String fullFilePathName, String hostName, String userName, String passWord) throws IOException {
853 Session sftpSession = null;
855 log.debug("Sftp get invoked, connection details: username={1} hostname={2}",
858 sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
859 java.util.Properties config = new java.util.Properties();
860 config.put("StrictHostKeyChecking", "no");
861 UserInfo ui = new MyUserInfo();
862 sftpSession.setPassword(passWord);
863 sftpSession.setUserInfo(ui);
864 sftpSession.setConfig(config);
865 sftpSession.connect(30 * 1000);
866 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
868 InputStream in = sftp.get(fullFilePathName);
869 return readInputStreamAsString(in);
870 } catch (JSchException ex) {
871 log.error(Msg.CANNOT_ESTABLISH_CONNECTION, hostName, String.valueOf(DEFAULT_PORT), userName);
872 throw new IOException(ex.getMessage());
873 } catch (SftpException ex) {
874 log.error(Msg.SFTP_TRANSFER_FAILED, hostName, userName, "GET", ex.getMessage());
875 throw new IOException(ex.getMessage());
877 if (sftpSession != null) {
878 sftpSession.disconnect();
883 public String send(String cmd, String delimiter) throws IOException {
884 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
885 sendSshCommand(cmd, dos);
886 return receiveUntil(delimiter, 300000, cmd);
890 private void sendSshCommand(@Nonnull String originalCommand, @Nonnull DataOutputStream channelOutputStream)
892 String command = enhanceCommandWithEOL(originalCommand);
893 int length = command.length(); // 2,937,706
894 int charsChunkSize = 300000;
895 int charsTotalSent = 0;
897 log.debug("Sending ssh command: length={0}, payload: {1}", length, command);
898 if (isCmdLengthEnoughToSendInChunks(length, charsChunkSize)) {
900 for (int i = 0; i < length; i += charsChunkSize) {
901 String commandChunk = command.substring(i, Math.min(length, i + charsChunkSize));
902 int numCharsSentInChunk = commandChunk.length();
903 charsTotalSent = charsTotalSent + commandChunk.length();
904 log.debug("Iteration nr:{0}, sending command chunk: {1}", i, numCharsSentInChunk);
905 channelOutputStream.writeBytes(commandChunk);
906 channelOutputStream.flush();
908 if (numCharsSentInChunk < length) {
909 receiveUntilBufferFlush(numCharsSentInChunk, timeout, originalCommand);
911 log.trace("i={0}, flush immediately", i);
912 channelOutputStream.flush();
914 } catch (IOException ex) {
915 log.warn("IOException occurred: nothing to flush out", ex);
919 channelOutputStream.writeBytes(command);
921 channelOutputStream.flush();
924 private boolean isCmdLengthEnoughToSendInChunks(int length, int chunkSize) {
925 return length > 2 * chunkSize;
928 private String enhanceCommandWithEOL(@Nonnull String originalCommand) {
929 char commandEnding = originalCommand.charAt(originalCommand.length() - 1);
930 if (commandEnding != '\n' && commandEnding != '\r') {
931 return originalCommand + EOL;
933 return originalCommand;
936 private Channel provideSessionChannel(String channelType, int port, int timeout) throws JSchException {
937 session = jsch.getSession(this.userName, this.hostName, port);
938 session.setPassword(this.passWord);
939 session.setUserInfo(new MyUserInfo()); //needed?
940 session.setConfig(STRICT_HOST_CHECK_KEY, STRICT_HOST_CHECK_VALUE);
941 session.connect(timeout);
942 session.setServerAliveCountMax(
943 0); // If this is not set to '0', then socket timeout on all reads will not work!!!!
944 return session.openChannel(channelType);