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 javax.annotation.Nonnull;
59 import org.apache.commons.lang.StringUtils;
61 public class SshJcraftWrapper {
63 private static final EELFLogger log = EELFManager.getInstance().getLogger(SshJcraftWrapper.class);
65 private static final int BUFFER_SIZE = 512000;
66 static final int DEFAULT_PORT = 22;
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 private TelnetListener listener = null;
73 private String routerLogFileName = null;
74 private String routerName = null;
75 private char[] charBuffer = new char[BUFFER_SIZE];
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 hostName = null;
88 private String userName = null;
89 private String passWord = null;
90 private Runtime runtime = Runtime.getRuntime();
93 public SshJcraftWrapper() {
94 this.jsch = new JSch();
97 SshJcraftWrapper(JSch jsch) {
101 public void connect(String hostname, String username, String password, String prompt, int timeOut)
103 log.debug("Attempting to connect to {0} username={1} prompt='{2}' timeOut={3}",
104 hostname, username, prompt, timeOut);
105 routerName = hostname;
110 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, DEFAULT_PORT, timeOut);
111 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
112 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE);
114 log.info("Successfully connected. Flushing input buffer.");
116 receiveUntil(prompt, 3000, "No cmd was sent, just waiting");
117 } catch (IOException e) {
118 log.warn("Caught an Exception: Nothing to flush out.", e);
120 } catch (JSchException e) {
121 log.error("Could not connect to host=" + hostname, e);
122 throw new IOException(e.toString());
126 // User specifies the port number.
127 public void connect(String hostname, String username, String password, String prompt, int timeOut, int portNum)
129 log.debug("Attempting to connect to {0} username={1} prompt='{2}' timeOut={3} portNum={4}",
130 hostname, username, prompt, timeOut, portNum);
131 routerName = hostname;
136 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, portNum, timeOut);
137 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
138 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE);
140 log.info("Successfully connected. Flushing input buffer.");
142 if ("]]>]]>".equals(prompt)) {
143 receiveUntil("]]>]]>", 10000, "No cmd was sent, just waiting");
145 receiveUntil(":~#", 5000, "No cmd was sent, just waiting");
147 } catch (IOException e) {
148 log.warn("Caught an Exception: Nothing to flush out.", e);
150 } catch (JSchException e) {
151 log.error("Could not connect to host=" + hostname, e);
152 throw new IOException(e.toString());
157 public String receiveUntil(String delimeters, int timeout, String cmdThatWasSent) throws IOException {
158 boolean match = false;
159 boolean cliPromptCmd = false;
160 StringBuilder sb = new StringBuilder();
161 StringBuilder sbReceive = new StringBuilder();
162 log.debug("delimeters='{0}' timeout={1} cmdThatWasSent='{2}'", delimeters, timeout, cmdThatWasSent);
164 aggregatedReceivedString = "";
165 FileWriter fileWriter = null;
167 long deadline = new Date().getTime() + timeout;
169 session.setTimeout(timeout); // This is the socket timeout value.
171 if (new Date().getTime() > deadline) {
172 String formattedCmd = removeWhiteSpaceAndNewLineCharactersAroundString(cmdThatWasSent);
173 log.error("Routine has timed out: routerName={0} CmdThatWasSent={1}", routerName, formattedCmd);
174 throw new TimedOutException("Routine has timed out");
178 } catch (java.lang.InterruptedException ee) {
179 Thread.currentThread().interrupt();
181 int len = reader.read(charBuffer, 0, BUFFER_SIZE);
182 log.trace("After reader. Read command len={0}", len);
184 log.error("Reader failed to read any bytes. Suspected socket timeout, router={0}", routerName);
185 throw new TimedOutException("Received a SocketTimeoutException router=" + routerName);
188 if (cmdThatWasSent.indexOf("IOS_XR_uploadedSwConfigCmd") != -1) {
190 // This is a IOS XR sw config file. We will write it to the disk.
191 timeout = timeout * 2;
192 deadline = new Date().getTime() + timeout;
193 log.debug("IOS XR upload for software config: timeout={0}", timeout);
194 StringTokenizer st = new StringTokenizer(cmdThatWasSent);
196 routerFileName = st.nextToken();
197 fileWriter = new FileWriter(routerFileName);
198 out = new BufferedWriter(fileWriter);
199 routerLogFileName = "/tmp/" + routerName;
200 tmpFile = new File(routerLogFileName);
201 log.debug("Prepared for writing swConfigFile to disk, routerFileName=" + routerFileName);
203 out.write(charBuffer, 0, len);
205 log.debug("{0} bytes has been written to the disk", len);
206 if (tmpFile.exists()) {
207 appendToRouterFile(routerLogFileName, len);
209 match = checkIfReceivedStringMatchesDelimeter(len, "\nXML>");
218 log.debug("Reader read {0} of data within {1} read iteration", len, readCounts);
221 for (int i = 0; i < len; i++) {
223 if ((c != 7) && (c != 13) && (c != 0) && (c != 27)) {
224 sbReceive.append(charBuffer[i]);
225 sb.append(charBuffer[i]);
228 appendToRouterFile("/tmp/" + routerName, len);
229 if (listener != null) {
230 listener.receivedString(sb.toString());
232 match = checkIfReceivedStringMatchesDelimeter(delimeters, sb.toString(), cmdThatWasSent);
234 log.trace("Match was true, breaking the loop.");
239 log.trace("cliPromptCmd");
241 for (int i = 0; i < len; i++) {
242 sbReceive.append(charBuffer[i]);
243 sb.append(charBuffer[i]);
245 appendToRouterFile("/tmp/" + routerName, sb);
246 if (listener != null) {
247 listener.receivedString(sb.toString());
249 log.debug("sb2={0} delimiters={1}", sb.toString(), delimeters);
250 if (sb.toString().contains("\nariPrompt>")) {
251 log.debug("Found ari prompt");
256 } catch (JSchException e) {
257 log.error("JSchException occurred", e);
258 throw new TimedOutException(e.getMessage());
259 } catch (IOException e) {
260 log.error("IOException occurred", e);
261 throw new TimedOutException(e.getMessage());
264 if (fileWriter != null) {
267 } catch (IOException ex) {
268 log.warn("Failed to close fileWriter output stream", ex);
271 return stripOffCmdFromRouterResponse(sbReceive.toString());
274 public boolean checkIfReceivedStringMatchesDelimeter(String delimeters, String receivedString,
275 String cmdThatWasSent) {
276 // The delimeters are in a '|' seperated string. Return true on the first match.
277 log.debug("Entered checkIfReceivedStringMatchesDelimeter: delimeters={0} cmdThatWasSent={1} receivedString={2}",
278 delimeters, cmdThatWasSent, receivedString);
279 StringTokenizer st = new StringTokenizer(delimeters, "|");
281 if ((delimeters.contains("#$")) || ("CLI".equals(routerCmdType))) // This would be an IOS XR, CLI command.
283 int x = receivedString.lastIndexOf('#');
284 int y = receivedString.length() - 1;
285 log.debug("IOS XR, CLI command");
286 if (log.isTraceEnabled()) {
287 log.trace("cmdThatWasSent={0}, lastIndexOf hash delimiter={1}, maxIndexNum={2}", cmdThatWasSent, x, y);
289 return (x != -1) && (y == x);
291 if (cmdThatWasSent.contains("show config")) {
292 log.trace("In the block for 'show config'");
293 while (st.hasMoreTokens()) {
294 String delimeter = st.nextToken();
295 // Make sure we don't get faked out by a response of " #".
297 // # signaling-local-address ipv6 FD00:F4D5:EA06:1::110:136:254
299 int x = receivedString.lastIndexOf(delimeter);
300 if ((receivedString.lastIndexOf(delimeter) != -1) && (receivedString.lastIndexOf(" #") != x - 1)) {
301 log.debug("receivedString={0}", receivedString);
302 log.trace("Found ending for 'show config' command, exiting.");
307 aggregatedReceivedString = aggregatedReceivedString + receivedString;
308 appendToFile("/tmp/aggregatedReceivedString.debug", aggregatedReceivedString);
310 log.debug("receivedString={0}", receivedString);
311 while (st.hasMoreTokens()) {
312 String delimeter = st.nextToken();
313 log.debug("Looking for an delimiter of:{0}", delimeter);
314 if (aggregatedReceivedString.indexOf(delimeter) != -1) {
315 log.debug("Found delimiter={0}, exiting", delimeter);
316 aggregatedReceivedString = "";
324 public boolean checkIfReceivedStringMatchesDelimeter(int len, String delimeter) {
327 String str = StringUtils.EMPTY;
329 if (jcraftReadSwConfigFileFromDisk()) {
330 log.trace("jcraftReadSwConfigFileFromDisk block");
331 File fileName = new File(routerFileName);
332 log.debug("jcraftReadSwConfigFileFromDisk::: Will read the tail end of the file from the disk");
334 str = getLastFewLinesOfFile(fileName, 3);
335 } catch (IOException e) {
336 log.warn("IOException occurred, while reading file=" + fileName, e);
339 // When looking at the end of the charBuffer, don't include any linefeeds or spaces. We only want to make the smallest string possible.
340 for (x = len - 1; x >= 0; x--) {
342 if ((c != 10) && (c != 32)) // Not a line feed nor a space.
347 if ((x + 1 - 13) >= 0) {
348 str = new String(charBuffer, x + 1 - 13, 13);
349 log.debug("str:{0}", str);
351 File fileName = new File(routerFileName);
352 log.debug("Will read the tail end of the file from the disk, x={0} len={1} str={2} routerFileName={3}",
353 x, len, str, routerFileName);
355 str = getLastFewLinesOfFile(fileName, 3);
356 } catch (IOException e) {
357 log.warn("IOException occurred, while reading file=" + fileName, e);
362 log.debug("Parsed string was str='{0}', searched delimiter was {1}");
363 return str.contains(delimeter);
366 public void closeConnection() {
367 log.info("Closing connection");
369 if (reader != null) {
372 } catch(IOException ex) {
373 log.warn("Could not close reader instance", ex);
376 channel.disconnect();
377 session.disconnect();
385 boolean isConnected() {
386 return (channel != null && session != null);
389 public void send(String cmd) throws IOException {
390 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
391 sendSshCommand(cmd, dos);
392 } catch (IOException e) {
393 log.error("IOException occurred while sending command=" + cmd, e);
398 public void sendChar(int v) throws IOException {
399 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
400 if (log.isTraceEnabled()) {
401 log.trace("Sending charCode: {0}", v);
405 } catch (IOException e) {
406 log.error("IOException occurred while writing char to channel output stream", e);
411 public void send(byte[] b, int off, int len) throws IOException {
412 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
413 dos.write(b, off, len);
415 } catch (IOException e) {
416 log.error("IOException occurred while writing bytes to channel output stream", e);
421 public static class MyUserInfo implements UserInfo, UIKeyboardInteractive {
424 public String getPassword() {
429 public boolean promptYesNo(String str) {
434 public String getPassphrase() {
439 public boolean promptPassphrase(String message) {
444 public boolean promptPassword(String message) {
449 public void showMessage(String message) {
454 public String[] promptKeyboardInteractive(String destination,
459 return new String[0];
463 public void addListener(TelnetListener listener) {
464 this.listener = listener;
467 private void appendToFile(String fileName, String dataToWrite) {
468 File outputFile = new File(fileName);
469 if (outputFile.exists()) {
470 try (FileWriter fw = new FileWriter(fileName, true); BufferedWriter ow = new BufferedWriter(fw)) {
471 ow.write(dataToWrite);
473 } catch (IOException e) {
474 log.error("IOException occurred while writing to file=" + fileName, e);
479 public String getTheDate() {
480 DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy H:mm:ss ");
481 return dateFormat.format(Calendar.getInstance().getTime());
485 public void appendToRouterFile(String fileName, StringBuilder dataToWrite) {
486 appendToFile(fileName, dataToWrite.toString());
489 public void appendToRouterFile(String fileName, int len) {
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(charBuffer, 0, len);
495 } catch (IOException e) {
496 log.error("IOException occurred while writing to router file=" + fileName, e);
501 public String removeWhiteSpaceAndNewLineCharactersAroundString(String str) {
502 if (str != null && !StringUtils.EMPTY.equals(str)) {
503 StringTokenizer strTok = new StringTokenizer(str, "\n");
504 StringBuilder sb = new StringBuilder();
506 while (strTok.hasMoreTokens()) {
507 String line = strTok.nextToken();
510 return sb.toString().trim();
512 return StringUtils.EMPTY;
515 public String stripOffCmdFromRouterResponse(String routerResponse) {
516 // The session of SSH will echo the command sent to the router, in the router's response.
517 // Since all our commands are terminated by a '\n', strip off the first line
518 // of the response from the router. This first line contains the orginal command.
519 StringTokenizer rr = new StringTokenizer(routerResponse, "\n");
520 StringBuilder sb = new StringBuilder();
522 int numTokens = rr.countTokens();
524 rr.nextToken(); //Skip the first line.
525 while (rr.hasMoreTokens()) {
526 sb.append(rr.nextToken()).append("\n");
529 return sb.toString();
532 public void setRouterCommandType(String type) {
533 this.routerCmdType = type;
534 log.debug("Router command type is set to: {0}", type);
537 public String getLastFewLinesOfFile(File file, int linesToRead) throws IOException {
538 RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
540 StringBuilder builder = new StringBuilder();
542 long length = file.length();
544 randomAccessFile.seek(length);
545 for (long seek = length; seek >= 0; --seek) {
546 randomAccessFile.seek(seek);
547 char c = (char) randomAccessFile.read();
550 builder = builder.reverse();
551 tail = builder.toString() + tail;
553 builder.setLength(0);
554 if (lines == linesToRead) {
559 randomAccessFile.close();
560 if (log.isDebugEnabled()) {
561 log.debug("Content read from file={0} was tail={1}", file.getName(), tail);
566 public boolean jcraftReadSwConfigFileFromDisk() {
567 return jcraftReadSwConfigFileFromDisk.exists();
570 public String getEquipNameCode() {
571 return equipNameCode;
574 public void setEquipNameCode(String equipNameCode) {
575 this.equipNameCode = equipNameCode;
578 public String getRouterName() {
582 // Routine does reads until it has read 'nchars' or times out.
583 public void receiveUntilBufferFlush(int ncharsSent, int timeout, String message) throws IOException {
584 log.debug("ncharsSent={0}, timeout={1}, message={2}", ncharsSent, timeout, message);
585 int ncharsTotalReceived = 0;
588 long deadline = new Date().getTime() + timeout;
591 session.setTimeout(timeout); // This is the socket timeout value.
593 if (new Date().getTime() > deadline) {
594 log.error("Routine has timed out: ncharsSent={0}, ncharsTotalReceived={1}", ncharsSent,
595 ncharsTotalReceived);
596 throw new TimedOutException("Routine has timed out");
598 ncharsRead = reader.read(charBuffer, 0, BUFFER_SIZE);
599 if (listener != null) {
600 listener.receivedString(String.copyValueOf(charBuffer, 0, ncharsRead));
602 appendToRouterFile("/tmp/" + routerName, ncharsRead);
603 ncharsTotalReceived = ncharsTotalReceived + ncharsRead;
604 if (ncharsTotalReceived >= ncharsSent) {
605 log.debug("Received the correct number of characters, ncharsSent={0}, ncharsTotalReceived={1}",
606 ncharsSent, ncharsTotalReceived);
611 } catch (JSchException e) {
612 log.error("JSchException occurred while command sending", e);
613 log.debug("ncharsSent={0}, ncharsTotalReceived={1}, ncharsRead={2} until error occurred",
614 ncharsSent, ncharsTotalReceived, ncharsRead);
615 throw new TimedOutException(e.getMessage());
619 public String getHostName() {
623 public String getUserName() {
627 public String getPassWord() {
631 public void sftpPutFile(String sourcePath, String destDirectory) throws IOException {
633 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
634 UserInfo ui = new MyUserInfo();
635 sftpSession.setPassword(passWord);
636 sftpSession.setUserInfo(ui);
637 sftpSession.connect(30 * 1000);
638 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
640 log.debug("Sending via sftp from source: {0} to destination: {1}", sourcePath, destDirectory);
641 sftp.put(sourcePath, destDirectory, ChannelSftp.OVERWRITE);
642 sftpSession.disconnect();
643 } catch (JSchException ex) {
644 log.error("JSchException occurred while handling sftp session", ex);
645 throw new IOException(ex.getMessage());
646 } catch (SftpException ex) {
647 log.error("SftpException occurred during file transfer", ex);
648 throw new IOException(ex.getMessage());
652 public void sftpPutStringData(String stringOfData, String fullPathDest) throws IOException {
654 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
655 UserInfo ui = new MyUserInfo();
656 sftpSession.setPassword(passWord);
657 sftpSession.setUserInfo(ui);
658 sftpSession.connect(30 * 1000);
659 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
661 InputStream is = new ByteArrayInputStream(stringOfData.getBytes());
662 log.debug("Sending via sftp stringOfData to destination: {0}", fullPathDest);
663 sftp.put(is, fullPathDest, ChannelSftp.OVERWRITE);
664 sftpSession.disconnect();
665 } catch (JSchException ex) {
666 log.error("JSchException occurred while handling sftp session", ex);
667 throw new IOException(ex.getMessage());
668 } catch (SftpException ex) {
669 log.error("SftpException occurred during data transfer", ex);
670 throw new IOException(ex.getMessage());
674 public String sftpGet(String fullFilePathName) throws IOException {
676 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
677 UserInfo ui = new MyUserInfo();
678 sftpSession.setPassword(passWord);
679 sftpSession.setUserInfo(ui);
680 sftpSession.connect(30 * 1000);
681 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
683 InputStream in = sftp.get(fullFilePathName);
684 String sftpFileString = readInputStreamAsString(in);
685 log.debug("Received data via sftp connection sftpFileString={0} from fullFilePathName={1}",
686 sftpFileString, fullFilePathName);
687 sftpSession.disconnect();
688 return sftpFileString;
689 } catch (JSchException ex) {
690 log.error("JSchException occurred while handling sftp session", ex);
691 throw new IOException(ex.getMessage());
692 } catch (SftpException ex) {
693 log.error("SftpException occurred during data transfer", ex);
694 throw new IOException(ex.getMessage());
698 public static String readInputStreamAsString(InputStream in) throws IOException {
699 BufferedInputStream bis = new BufferedInputStream(in);
700 ByteArrayOutputStream buf = new ByteArrayOutputStream();
701 int result = bis.read();
702 while (result != -1) {
703 byte b = (byte) result;
707 return buf.toString();
711 public void logMemoryUsage() {
712 int mb = 1024 * 1024;
714 long maxMemoryAvailable;
715 long memoryLeftOnHeap;
716 maxMemoryAvailable =runtime.maxMemory() / mb;
717 usedMemory = (runtime.totalMemory() / mb) - (runtime.freeMemory() / mb);
718 memoryLeftOnHeap = maxMemoryAvailable - usedMemory;
719 log.info("Memory usage: maxMemoryAvailable={0}, usedMemory={1}, memoryLeftOnHeap={2}",
720 maxMemoryAvailable, usedMemory, memoryLeftOnHeap);
723 public void connect(String hostname, String username, String password, int timeOut, int portNum,
724 String subsystem) throws IOException {
726 if (log.isDebugEnabled()) {
728 "Attempting to connect to {0} username={1} timeOut={2} portNum={3} subsystem={4}",
729 hostname, username, timeOut, portNum, subsystem);
731 this.routerName = hostname;
732 this.hostName = hostname;
733 this.userName = username;
734 this.passWord = password;
736 channel = provideSessionChannel(CHANNEL_SUBSYSTEM_TYPE, portNum, timeOut);
737 ((ChannelSubsystem) channel).setSubsystem(subsystem);
738 ((ChannelSubsystem) channel).setPty(true); //expected ptyType vt102
739 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE);
740 channel.connect(5000);
741 } catch (JSchException e) {
742 log.error("JschException occurred ", e);
743 throw new IOException(e.getMessage());
747 public void connect(String hostName, String username, String password) throws IOException {
748 log.debug("Attempting to connect to {0} username={1} portNumber={2}", hostName, username, DEFAULT_PORT);
749 this.routerName = hostName;
750 this.hostName = hostName;
751 this.userName = username;
752 this.passWord = password;
754 channel = provideSessionChannel(CHANNEL_SHELL_TYPE, DEFAULT_PORT, 30000);
755 ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE);
756 reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE);
759 receiveUntil(":~#", 9000, "No cmd was sent, just waiting, but we can stop on a '~#'");
760 } catch (Exception e) {
761 log.warn("Caught an Exception: Nothing to flush out.", e);
764 } catch (JSchException e) {
765 log.error("JschException occurred ", e);
766 throw new IOException(e.getMessage());
771 public void put(String sourcePath, String destDirectory) throws IOException {
773 Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
774 UserInfo ui = new MyUserInfo();
775 sftpSession.setPassword(passWord);
776 sftpSession.setUserInfo(ui);
777 sftpSession.connect(30 * 1000);
778 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
780 log.debug("Sending via sftp from source: {0} to destination: {1}", sourcePath, destDirectory);
781 sftp.put(sourcePath, destDirectory, ChannelSftp.OVERWRITE);
782 sftpSession.disconnect();
783 } catch (JSchException ex) {
784 log.error("JSchException occurred while handling sftp session", ex);
785 throw new IOException(ex.getMessage());
786 } catch (SftpException ex) {
787 log.error("SftpException occurred during file transfer", ex);
788 throw new IOException(ex.getMessage());
792 public void put(InputStream is, String fullPathDest, String hostName, String userName, String passWord)
794 Session sftpSession = null;
796 log.debug("Sftp put invoked, connection details: username={1} hostname={2}",
799 java.util.Properties config = new java.util.Properties();
800 config.put("StrictHostKeyChecking", "no");
801 sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
802 UserInfo ui = new MyUserInfo();
803 sftpSession.setPassword(passWord);
804 sftpSession.setUserInfo(ui);
805 sftpSession.setConfig(config);
806 sftpSession.connect(30 * 1000);
807 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
809 String oldFiles = fullPathDest + "*";
810 log.debug("Deleting old files: {0}", oldFiles);
813 } catch (SftpException ex) {
814 String exp = "No such file";
815 if (ex.getMessage() != null && ex.getMessage().contains(exp)) {
816 log.warn("No files found, continue");
818 log.error("SftpException while invoking rm command over sftp", ex);
822 log.debug("Sending stringOfData to destination {0}", fullPathDest);
823 sftp.put(is, fullPathDest, ChannelSftp.OVERWRITE);
824 } catch (JSchException ex) {
825 log.error("JSchException occurred while handling sftp session", ex);
826 throw new IOException(ex.getMessage());
827 } catch (SftpException ex) {
828 log.error("SftpException occurred during file transfer", ex);
829 throw new IOException(ex.getMessage());
831 if (sftpSession != null) {
832 sftpSession.disconnect();
837 public String get(String fullFilePathName, String hostName, String userName, String passWord) throws IOException {
838 Session sftpSession = null;
840 log.debug("Sftp get invoked, connection details: username={1} hostname={2}",
843 sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT);
844 java.util.Properties config = new java.util.Properties();
845 config.put("StrictHostKeyChecking", "no");
846 UserInfo ui = new MyUserInfo();
847 sftpSession.setPassword(passWord);
848 sftpSession.setUserInfo(ui);
849 sftpSession.setConfig(config);
850 sftpSession.connect(30 * 1000);
851 ChannelSftp sftp = (ChannelSftp) sftpSession.openChannel("sftp");
853 InputStream in = sftp.get(fullFilePathName);
854 return readInputStreamAsString(in);
855 } catch (JSchException ex) {
856 log.error("JSchException occurred while handling sftp session", ex);
857 throw new IOException(ex.getMessage());
858 } catch (SftpException ex) {
859 log.error("SftpException occurred during file transfer", ex);
860 throw new IOException(ex.getMessage());
862 if (sftpSession != null) {
863 sftpSession.disconnect();
868 public String send(String cmd, String delimiter) throws IOException {
869 try (OutputStream os = channel.getOutputStream(); DataOutputStream dos = new DataOutputStream(os)) {
870 sendSshCommand(cmd, dos);
871 return receiveUntil(delimiter, 300000, cmd);
872 } catch (IOException ex) {
873 log.error("IOException occurred", ex);
874 throw new IOException(ex.getMessage());
878 private void sendSshCommand(@Nonnull String originalCommand, @Nonnull DataOutputStream channelOutputStream)
880 String command = enhanceCommandWithEOL(originalCommand);
881 int length = command.length(); // 2,937,706
882 int charsChunkSize = 300000;
883 int charsTotalSent = 0;
885 log.debug("Sending ssh command: length={0}, payload: {1}", length, command);
886 if (isCmdLengthEnoughToSendInChunks(length, charsChunkSize)) {
888 for (int i = 0; i < length; i += charsChunkSize) {
889 String commandChunk = command.substring(i, Math.min(length, i + charsChunkSize));
890 int numCharsSentInChunk = commandChunk.length();
891 charsTotalSent = charsTotalSent + commandChunk.length();
892 log.debug("Iteration nr:{0}, sending command chunk: {1}", i, numCharsSentInChunk);
893 channelOutputStream.writeBytes(commandChunk);
894 channelOutputStream.flush();
896 if (numCharsSentInChunk < length) {
897 receiveUntilBufferFlush(numCharsSentInChunk, timeout, "buffer flush i=" + i);
899 log.trace("i={0}, flush immediately", i);
900 channelOutputStream.flush();
902 } catch (IOException ex) {
903 log.warn("IOException occurred: nothing to flush out", ex);
907 channelOutputStream.writeBytes(command);
909 channelOutputStream.flush();
912 private boolean isCmdLengthEnoughToSendInChunks(int length, int chunkSize) {
913 return length > 2 * chunkSize;
916 private String enhanceCommandWithEOL(@Nonnull String originalCommand) {
917 char commandEnding = originalCommand.charAt(originalCommand.length() - 1);
918 if (commandEnding != '\n' && commandEnding != '\r') {
919 return originalCommand + "\n";
921 return originalCommand;
924 private Channel provideSessionChannel(String channelType, int port, int timeout) throws JSchException {
925 session = jsch.getSession(this.userName, this.hostName, port);
926 session.setPassword(this.passWord);
927 session.setUserInfo(new MyUserInfo()); //needed?
928 session.setConfig(STRICT_HOST_CHECK_KEY, STRICT_HOST_CHECK_VALUE);
929 session.connect(timeout);
930 session.setServerAliveCountMax(
931 0); // If this is not set to '0', then socket timeout on all reads will not work!!!!
932 return session.openChannel(channelType);