shell_client.c
Go to the documentation of this file.
1 /**
2  * @file shell_client.c
3  * @brief SSH secure shell client
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSH Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SHELL_TRACE_LEVEL
33 
34 //Dependencies
35 #include <stdarg.h>
36 #include "ssh/ssh.h"
37 #include "ssh/ssh_connection.h"
38 #include "ssh/ssh_transport.h"
39 #include "ssh/ssh_request.h"
40 #include "shell/shell_client.h"
42 #include "debug.h"
43 
44 //Check SSH stack configuration
45 #if (SHELL_CLIENT_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Initialize shell client context
50  * @param[in] context Pointer to the shell client context
51  * @return Error code
52  **/
53 
55 {
56  //Make sure the shell client context is valid
57  if(context == NULL)
59 
60  //Clear shell client context
61  osMemset(context, 0, sizeof(ShellClientContext));
62 
63  //Initialize shell client state
64  context->state = SHELL_CLIENT_STATE_DISCONNECTED;
65  //Default timeout
66  context->timeout = SHELL_CLIENT_DEFAULT_TIMEOUT;
67 
68  //Successful processing
69  return NO_ERROR;
70 }
71 
72 
73 /**
74  * @brief Register SSH initialization callback function
75  * @param[in] context Pointer to the shell client context
76  * @param[in] callback SSH initialization callback function
77  * @return Error code
78  **/
79 
82 {
83  //Check parameters
84  if(context == NULL || callback == NULL)
86 
87  //Save callback function
88  context->sshInitCallback = callback;
89 
90  //Successful processing
91  return NO_ERROR;
92 }
93 
94 
95 /**
96  * @brief Set communication timeout
97  * @param[in] context Pointer to the shell client context
98  * @param[in] timeout Timeout value, in milliseconds
99  * @return Error code
100  **/
101 
103 {
104  //Make sure the shell client context is valid
105  if(context == NULL)
107 
108  //Save timeout value
109  context->timeout = timeout;
110 
111  //Successful processing
112  return NO_ERROR;
113 }
114 
115 
116 /**
117  * @brief Bind the shell client to a particular network interface
118  * @param[in] context Pointer to the shell client context
119  * @param[in] interface Network interface to be used
120  * @return Error code
121  **/
122 
124  NetInterface *interface)
125 {
126  //Make sure the shell client context is valid
127  if(context == NULL)
129 
130  //Explicitly associate the shell client with the specified interface
131  context->interface = interface;
132 
133  //Successful processing
134  return NO_ERROR;
135 }
136 
137 
138 /**
139  * @brief Establish a connection with the specified SSH server
140  * @param[in] context Pointer to the shell client context
141  * @param[in] serverIpAddr IP address of the SSH server to connect to
142  * @param[in] serverPort Port number
143  * @return Error code
144  **/
145 
147  const IpAddr *serverIpAddr, uint16_t serverPort)
148 {
149  error_t error;
150 
151  //Make sure the shell client context is valid
152  if(context == NULL)
154 
155  //Initialize status code
156  error = NO_ERROR;
157 
158  //Establish connection with the SSH server
159  while(!error)
160  {
161  //Check current state
162  if(context->state == SHELL_CLIENT_STATE_DISCONNECTED)
163  {
164  //Open network connection
165  error = shellClientOpenConnection(context);
166 
167  //Check status code
168  if(!error)
169  {
170  //Update shell client state
172  }
173  }
174  else if(context->state == SHELL_CLIENT_STATE_CONNECTING_1)
175  {
176  //Establish network connection
177  error = socketConnect(context->sshConnection.socket, serverIpAddr,
178  serverPort);
179 
180  //Check status code
181  if(error == NO_ERROR)
182  {
183  //Force the socket to operate in non-blocking mode
184  socketSetTimeout(context->sshConnection.socket, 0);
185 
186  //Update shell client state
188  }
189  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
190  {
191  //Check whether the timeout has elapsed
192  error = shellClientCheckTimeout(context);
193  }
194  else
195  {
196  //Communication error
197  }
198  }
199  else if(context->state == SHELL_CLIENT_STATE_CONNECTING_2)
200  {
201  //Establish SSH connection
202  error = shellClientEstablishConnection(context);
203  }
204  else if(context->state == SHELL_CLIENT_STATE_CONNECTED)
205  {
206  //The shell client is connected
207  break;
208  }
209  else
210  {
211  //Invalid state
212  error = ERROR_WRONG_STATE;
213  }
214  }
215 
216  //Failed to establish connection with the SSH server?
217  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
218  {
219  //Clean up side effects
221  //Update shell client state
223  }
224 
225  //Return status code
226  return error;
227 }
228 
229 
230 /**
231  * @brief Format a command line
232  * @param[in] context Pointer to the shell client context
233  * @param[in] command NULL-terminating string containing the command line
234  * @param[in] ... Optional arguments
235  * @return Error code
236  **/
237 
239  const char_t *command, ...)
240 {
241  error_t error;
242 
243  //Check parameters
244  if(context == NULL || command == NULL)
246 
247  //Initialize status code
248  error = NO_ERROR;
249 
250  //Execute the command line
251  while(!error)
252  {
253  //Check the state of the shell client
254  if(context->state == SHELL_CLIENT_STATE_CONNECTED)
255  {
256  size_t n;
257  va_list args;
258 
259  //Initialize processing of a varying-length argument list
260  va_start(args, command);
261 
262  //Format command line
263  n = osVsnprintf(context->buffer, SHELL_CLIENT_BUFFER_SIZE, command,
264  args);
265 
266  //End varying-length argument list processing
267  va_end(args);
268 
269  //Check the length of the resulting string
271  {
272  //Update shell client state
274  }
275  else
276  {
277  //A return value larger than or equal to buffer size means that the
278  //output was truncated
279  error = ERROR_BUFFER_OVERFLOW;
280  }
281  }
282  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_INIT ||
283  context->state == SHELL_CLIENT_STATE_CHANNEL_OPEN ||
284  context->state == SHELL_CLIENT_STATE_CHANNEL_REQUEST ||
285  context->state == SHELL_CLIENT_STATE_CHANNEL_REPLY ||
286  context->state == SHELL_CLIENT_STATE_CHANNEL_CLOSE)
287  {
288  //Send the "exec" request
289  error = shellClientExecuteCommand(context, context->buffer);
290  }
291  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_DATA)
292  {
293  //An SSH_MSG_CHANNEL_SUCCESS message has been received
295  //We are done
296  break;
297  }
298  else
299  {
300  //Invalid state
301  error = ERROR_WRONG_STATE;
302  }
303  }
304 
305  //Return status code
306  return error;
307 }
308 
309 
310 /**
311  * @brief Execute a command line
312  * @param[in] context Pointer to the shell client context
313  * @param[in] command NULL-terminating string containing the command line
314  * @return Error code
315  **/
316 
318  const char_t *command)
319 {
320  error_t error;
321  SshConnection *connection;
322  SshChannel *channel;
323 
324  //Check parameters
325  if(context == NULL || command == NULL)
327 
328  //Point to the SSH connection
329  connection = &context->sshConnection;
330  //Point to the SSH channel
331  channel = &context->sshChannel;
332 
333  //Initialize status code
334  error = NO_ERROR;
335 
336  //Execute the command line
337  while(!error)
338  {
339  //Check the state of the shell client
340  if(context->state == SHELL_CLIENT_STATE_CONNECTED)
341  {
342  //Update shell client state
344  }
345  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_INIT)
346  {
347  //Allocate a new SSH channel
348  channel = sshCreateChannel(connection);
349 
350  //Valid channel handle?
351  if(channel != NULL)
352  {
353  //Force the channel to operate in non-blocking mode
354  error = sshSetChannelTimeout(channel, 0);
355 
356  //Check status code
357  if(!error)
358  {
359  //The client sends an SSH_MSG_CHANNEL_OPEN message to the server
360  //in order to open a new channel
361  error = sshSendChannelOpen(channel, "session", NULL);
362  }
363 
364  //Check status code
365  if(!error)
366  {
367  //Update shell client state
369  }
370  }
371  else
372  {
373  //Update shell client state
375  //Report an error
376  error = ERROR_OPEN_FAILED;
377  }
378  }
379  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_OPEN)
380  {
381  //Wait for server's response
382  error = shellClientProcessEvents(context);
383 
384  //Check status code
385  if(!error)
386  {
387  //Check the state of the channel
388  if(channel->state == SSH_CHANNEL_STATE_RESERVED)
389  {
390  //Continue processing
391  }
392  else if(channel->state == SSH_CHANNEL_STATE_OPEN)
393  {
394  //An SSH_MSG_CHANNEL_OPEN_CONFIRMATION message has been received
396  }
397  else if(channel->state == SSH_CHANNEL_STATE_CLOSED)
398  {
399  //Release SSH channel
400  sshDeleteChannel(&context->sshChannel);
401  //Update shell client state
403  //An SSH_MSG_CHANNEL_OPEN_FAILURE message has been received
404  error = ERROR_OPEN_FAILED;
405  }
406  else
407  {
408  //Invalid state
409  error = ERROR_WRONG_STATE;
410  }
411  }
412  }
413  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_REQUEST)
414  {
415  SshExecParams requestParams;
416 
417  //Set "exec" request parameters
418  requestParams.command.value = command;
419  requestParams.command.length = osStrlen(command);
420 
421  //Send an SSH_MSG_CHANNEL_REQUEST message to the server
422  error = sshSendChannelRequest(channel, "exec", &requestParams, TRUE);
423 
424  //Check status code
425  if(!error)
426  {
427  //Update shell client state
429  }
430  }
431  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_REPLY)
432  {
433  //Wait for server's response
434  error = shellClientProcessEvents(context);
435 
436  //Check status code
437  if(!error)
438  {
439  //Check the state of the channel request
440  if(channel->requestState == SSH_REQUEST_STATE_PENDING)
441  {
442  //Continue processing
443  }
444  else if(channel->requestState == SSH_REQUEST_STATE_SUCCESS)
445  {
446  //An SSH_MSG_CHANNEL_SUCCESS message has been received
448  //We are done
449  break;
450  }
451  else if(channel->requestState == SSH_REQUEST_STATE_FAILURE)
452  {
453  //An SSH_MSG_CHANNEL_FAILURE message has been received
455  }
456  else
457  {
458  //Invalid state
459  error = ERROR_WRONG_STATE;
460  }
461  }
462  }
463  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_CLOSE)
464  {
465  //When either party wishes to terminate the channel, it sends an
466  //SSH_MSG_CHANNEL_CLOSE message
467  error = sshCloseChannel(&context->sshChannel);
468 
469  //Check status code
470  if(error == NO_ERROR)
471  {
472  //Wait for the SSH_MSG_CHANNEL_CLOSE message to be transmitted
473  if(context->sshConnection.txBufferLen > 0)
474  {
475  //Flush pending data
476  error = shellClientProcessEvents(context);
477  }
478  else
479  {
480  //Release SSH channel
481  sshDeleteChannel(&context->sshChannel);
482  //Update shell client state
484  //Report an error
486  }
487  }
488  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
489  {
490  //Process SSH connection events
491  error = shellClientProcessEvents(context);
492  }
493  else
494  {
495  //Just for sanity
496  }
497  }
498  else
499  {
500  //Invalid state
501  error = ERROR_WRONG_STATE;
502  }
503  }
504 
505  //Return status code
506  return error;
507 }
508 
509 
510 /**
511  * @brief Write to stdin stream
512  * @param[in] context Pointer to the shell client context
513  * @param[in] data Pointer to a buffer containing the data to be written
514  * @param[in] length Number of data bytes to write
515  * @param[in] written Number of bytes that have been written (optional parameter)
516  * @param[in] flags Set of flags that influences the behavior of this function
517  * @return Error code
518  **/
519 
521  size_t length, size_t *written, uint_t flags)
522 {
523  error_t error;
524  size_t n;
525  size_t totalLength;
526 
527  //Make sure the shell client context is valid
528  if(context == NULL)
530 
531  //Check parameters
532  if(data == NULL && length != 0)
534 
535  //Initialize status code
536  error = NO_ERROR;
537  //Actual number of bytes written
538  totalLength = 0;
539 
540  //Write as much data as possible
541  while(totalLength < length && !error)
542  {
543  //Check the state of the shell client
544  if(context->state == SHELL_CLIENT_STATE_CHANNEL_DATA)
545  {
546  //Write data to stdin stream
547  error = sshWriteChannel(&context->sshChannel, data, length, &n, flags);
548 
549  //Check status code
550  if(error == NO_ERROR || error == ERROR_TIMEOUT)
551  {
552  //Any data transmitted?
553  if(n > 0)
554  {
555  //Advance data pointer
556  data = (uint8_t *) data + n;
557  totalLength += n;
558 
559  //Save current time
560  context->timestamp = osGetSystemTime();
561  }
562  }
563 
564  //Check status code
565  if(error == NO_ERROR)
566  {
567  //Successful write operation
568  break;
569  }
570  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
571  {
572  //Process SSH connection events
573  error = shellClientProcessEvents(context);
574  }
575  else
576  {
577  //Communication error
578  }
579  }
580  else
581  {
582  //Invalid state
583  error = ERROR_WRONG_STATE;
584  }
585  }
586 
587  //Check status code
588  if(!error)
589  {
590  //Flush pending data
591  error = shellClientFlushStream(context);
592  }
593 
594  //The parameter is optional
595  if(written != NULL)
596  {
597  //Total number of data that have been written
598  *written = totalLength;
599  }
600 
601  //Return status code
602  return error;
603 }
604 
605 
606 /**
607  * @brief Flush stdin stream
608  * @param[in] context Pointer to the shell client context
609  * @return Error code
610  **/
611 
613 {
614  error_t error;
615 
616  //Initialize status code
617  error = NO_ERROR;
618 
619  //Check the state of the shell client
620  if(context->state == SHELL_CLIENT_STATE_CHANNEL_DATA)
621  {
622  //Any data pending for transmission?
623  while(context->sshChannel.txBuffer.length > 0 && !error)
624  {
625  //Flush pending data
626  error = shellClientProcessEvents(context);
627  }
628  }
629  else
630  {
631  //Invalid state
632  error = ERROR_WRONG_STATE;
633  }
634 
635  //Return error code
636  return error;
637 }
638 
639 
640 /**
641  * @brief Read from stdout stream
642  * @param[in] context Pointer to the shell client context
643  * @param[out] data Buffer where to store the incoming data
644  * @param[in] size Maximum number of bytes that can be read
645  * @param[out] received Actual number of bytes that have been read
646  * @param[in] flags Set of flags that influences the behavior of this function
647  * @return Error code
648  **/
649 
651  size_t size, size_t *received, uint_t flags)
652 {
653  error_t error;
654  size_t n;
655 
656  //Check parameters
657  if(context == NULL || data == NULL || received == NULL)
659 
660  //Initialize status code
661  error = NO_ERROR;
662  //No data has been read yet
663  *received = 0;
664 
665  //Read as much data as possible
666  while(*received < size && !error)
667  {
668  //Check the state of the shell client
669  if(context->state == SHELL_CLIENT_STATE_CHANNEL_DATA)
670  {
671  //Read more data
672  error = sshReadChannel(&context->sshChannel, data, size, &n, flags);
673 
674  //Check status code
675  if(error == NO_ERROR || error == ERROR_TIMEOUT)
676  {
677  //Any data received?
678  if(n > 0)
679  {
680  //Advance data pointer
681  data = (uint8_t *) data + n;
682  *received += n;
683 
684  //Save current time
685  context->timestamp = osGetSystemTime();
686  }
687  }
688 
689  //Check status code
690  if(error == NO_ERROR)
691  {
692  //Successful read operation
693  break;
694  }
695  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
696  {
697  //Process SSH connection events
698  error = shellClientProcessEvents(context);
699  }
700  else
701  {
702  //Communication error
703  }
704  }
705  else
706  {
707  //Invalid state
708  error = ERROR_WRONG_STATE;
709  }
710  }
711 
712  //Check status code
713  if(error == ERROR_END_OF_STREAM)
714  {
715  //Check flags
716  if((flags & SSH_FLAG_BREAK_CHAR) != 0 || (flags & SSH_FLAG_WAIT_ALL) == 0)
717  {
718  //The user must be satisfied with data already on hand
719  if(*received > 0)
720  {
721  error = NO_ERROR;
722  }
723  }
724  }
725 
726  //Return status code
727  return error;
728 }
729 
730 
731 /**
732  * @brief Close stream
733  * @param[in] context Pointer to the shell client context
734  * @return Error code
735  **/
736 
738 {
739  error_t error;
740  size_t n;
741 
742  //Make sure the shell client context is valid
743  if(context == NULL)
745 
746  //Initialize status code
747  error = NO_ERROR;
748 
749  //Close the file
750  while(!error)
751  {
752  //Check the state of the shell client
753  if(context->state == SHELL_CLIENT_STATE_CHANNEL_DATA)
754  {
755  //Discard data from stdout stream
756  error = sshReadChannel(&context->sshChannel, context->buffer,
758 
759  //Check status code
760  if(error == NO_ERROR)
761  {
762  //Save current time
763  context->timestamp = osGetSystemTime();
764  }
765  else if(error == ERROR_END_OF_STREAM)
766  {
767  //An SSH_MSG_CHANNEL_EOF message has been received
768  error = NO_ERROR;
769  //Update shell client state
771  }
772  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
773  {
774  //Process SSH connection events
775  error = shellClientProcessEvents(context);
776  }
777  else
778  {
779  //Communication error
780  }
781  }
782  else if(context->state == SHELL_CLIENT_STATE_CHANNEL_CLOSE)
783  {
784  //When either party wishes to terminate the channel, it sends an
785  //SSH_MSG_CHANNEL_CLOSE message
786  error = sshCloseChannel(&context->sshChannel);
787 
788  //Check status code
789  if(error == NO_ERROR)
790  {
791  //Wait for the SSH_MSG_CHANNEL_CLOSE message to be transmitted
792  if(context->sshConnection.txBufferLen > 0)
793  {
794  //Flush pending data
795  error = shellClientProcessEvents(context);
796  }
797  else
798  {
799  //Release SSH channel
800  sshDeleteChannel(&context->sshChannel);
801  //Update shell client state
803  }
804  }
805  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
806  {
807  //Process SSH connection events
808  error = shellClientProcessEvents(context);
809  }
810  else
811  {
812  //Just for sanity
813  }
814  }
815  else if(context->state == SHELL_CLIENT_STATE_CONNECTED)
816  {
817  //We are done
818  break;
819  }
820  else
821  {
822  //Invalid state
823  error = ERROR_WRONG_STATE;
824  }
825  }
826 
827  //Return status code
828  return error;
829 }
830 
831 
832 /**
833  * @brief Retrieve exit status
834  * @param[in] context Pointer to the shell client context
835  * @return Exit status
836  **/
837 
839 {
840  uint32_t exitStatus;
841 
842  //Make sure the shell client context is valid
843  if(context != NULL)
844  {
845  //Get exit status
846  exitStatus = context->exitStatus;
847  }
848  else
849  {
850  //The shell client context is not valid
851  exitStatus = 0;
852  }
853 
854  //Return exit status
855  return exitStatus;
856 }
857 
858 
859 /**
860  * @brief Gracefully disconnect from the SSH server
861  * @param[in] context Pointer to the shell client context
862  * @return Error code
863  **/
864 
866 {
867  error_t error;
868 
869  //Make sure the shell client context is valid
870  if(context == NULL)
872 
873  //Initialize status code
874  error = NO_ERROR;
875 
876  //Gracefully disconnect from the SSH server
877  while(!error)
878  {
879  //Check current state
880  if(context->state == SHELL_CLIENT_STATE_CONNECTED)
881  {
882  //Send an SSH_MSG_DISCONNECT message
883  error = sshSendDisconnect(&context->sshConnection,
884  SSH_DISCONNECT_BY_APPLICATION, "Connection closed by user");
885 
886  //Check status code
887  if(!error)
888  {
889  //Update shell client state
891  }
892  }
893  else if(context->state == SHELL_CLIENT_STATE_DISCONNECTING_1)
894  {
895  //Wait for the SSH_MSG_DISCONNECT message to be transmitted
896  error = shellClientProcessEvents(context);
897 
898  //Check status code
899  if(error == ERROR_CONNECTION_CLOSING)
900  {
901  //Catch exception
902  error = NO_ERROR;
903  //Set timeout
904  socketSetTimeout(context->sshConnection.socket, context->timeout);
905  //Update shell client state
907  }
908  }
909  else if(context->state == SHELL_CLIENT_STATE_DISCONNECTING_2)
910  {
911  //Shutdown TCP connection
912  error = socketShutdown(context->sshConnection.socket, SOCKET_SD_BOTH);
913 
914  //Check status code
915  if(error == NO_ERROR)
916  {
917  //Close network connection
919  //Update shell client state
921  }
922  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
923  {
924  //Check whether the timeout has elapsed
925  error = shellClientCheckTimeout(context);
926  }
927  else
928  {
929  //A communication error has occurred
930  }
931  }
932  else if(context->state == SHELL_CLIENT_STATE_DISCONNECTED)
933  {
934  //We are done
935  break;
936  }
937  else
938  {
939  //Invalid state
940  error = ERROR_WRONG_STATE;
941  }
942  }
943 
944  //Failed to gracefully disconnect from the SSH server?
945  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
946  {
947  //Close network connection
949  //Update shell client state
951  }
952 
953  //Return status code
954  return error;
955 }
956 
957 
958 /**
959  * @brief Close the connection with the SSH server
960  * @param[in] context Pointer to the shell client context
961  * @return Error code
962  **/
963 
965 {
966  //Make sure the shell client context is valid
967  if(context == NULL)
969 
970  //Close network connection
972  //Update shell client state
974 
975  //Successful processing
976  return NO_ERROR;
977 }
978 
979 
980 /**
981  * @brief Release shell client context
982  * @param[in] context Pointer to the shell client context
983  **/
984 
986 {
987  //Make sure the shell client context is valid
988  if(context != NULL)
989  {
990  //Close network connection
992 
993  //Clear shell client context
994  osMemset(context, 0, sizeof(ShellClientContext));
995  }
996 }
997 
998 #endif
void shellClientDeinit(ShellClientContext *context)
Release shell client context.
Definition: shell_client.c:985
@ SHELL_CLIENT_STATE_CHANNEL_CLOSE
Definition: shell_client.h:83
@ SSH_FLAG_WAIT_ALL
Definition: ssh.h:916
@ SHELL_CLIENT_STATE_CHANNEL_REQUEST
Definition: shell_client.h:80
@ ERROR_WOULD_BLOCK
Definition: error.h:96
Helper functions for SSH secure shell client.
@ SHELL_CLIENT_STATE_CONNECTING_1
Definition: shell_client.h:75
IP network address.
Definition: ip.h:90
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
@ SHELL_CLIENT_STATE_DISCONNECTED
Definition: shell_client.h:74
@ SHELL_CLIENT_STATE_CHANNEL_INIT
Definition: shell_client.h:78
SSH connection protocol.
@ SHELL_CLIENT_STATE_DISCONNECTING_1
Definition: shell_client.h:84
#define TRUE
Definition: os_port.h:50
@ SSH_FLAG_BREAK_CHAR
Definition: ssh.h:917
uint8_t data[]
Definition: ethernet.h:222
error_t(* ShellClientSshInitCallback)(ShellClientContext *context, SshContext *sshContext)
SSH initialization callback function.
Definition: shell_client.h:93
error_t sshCloseChannel(SshChannel *channel)
Close channel.
Definition: ssh.c:2465
SSH transport layer protocol.
"exec" channel request parameters
Definition: ssh_request.h:119
error_t shellClientFlushStream(ShellClientContext *context)
Flush stdin stream.
Definition: shell_client.c:612
size_t length
Definition: ssh_types.h:58
uint16_t totalLength
Definition: ipv4.h:322
void sshDeleteChannel(SshChannel *channel)
Release channel.
Definition: ssh.c:2536
#define osStrlen(s)
Definition: os_port.h:165
@ ERROR_END_OF_STREAM
Definition: error.h:210
#define ShellClientContext
Definition: shell_client.h:60
@ ERROR_WRONG_STATE
Definition: error.h:209
error_t sshReadChannel(SshChannel *channel, void *data, size_t size, size_t *received, uint_t flags)
Receive data from the specified channel.
Definition: ssh.c:2180
@ SSH_REQUEST_STATE_PENDING
Definition: ssh.h:1087
@ SHELL_CLIENT_STATE_CHANNEL_REPLY
Definition: shell_client.h:81
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ SSH_DISCONNECT_BY_APPLICATION
Definition: ssh.h:1006
SSH secure shell client.
#define SHELL_CLIENT_BUFFER_SIZE
Definition: shell_client.h:53
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
const char_t * value
Definition: ssh_types.h:57
error_t shellClientProcessEvents(ShellClientContext *context)
Process shell client events.
error_t
Error codes.
Definition: error.h:43
error_t shellClientExecuteCommand(ShellClientContext *context, const char_t *command)
Execute a command line.
Definition: shell_client.c:317
#define osVsnprintf(dest, size, format, ap)
Definition: os_port.h:243
#define NetInterface
Definition: net.h:36
SshChannel * sshCreateChannel(SshConnection *connection)
Create a new SSH channel.
Definition: ssh.c:1964
@ SHELL_CLIENT_STATE_CHANNEL_DATA
Definition: shell_client.h:82
@ SSH_CHANNEL_STATE_OPEN
Definition: ssh.h:1075
error_t sshWriteChannel(SshChannel *channel, const void *data, size_t length, size_t *written, uint_t flags)
Write data to the specified channel.
Definition: ssh.c:2051
error_t shellClientSetTimeout(ShellClientContext *context, systime_t timeout)
Set communication timeout.
Definition: shell_client.c:102
error_t sshSendDisconnect(SshConnection *connection, uint32_t reasonCode, const char_t *description)
Send SSH_MSG_DISCONNECT message.
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1349
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:2020
@ SHELL_CLIENT_STATE_CONNECTED
Definition: shell_client.h:77
@ ERROR_UNEXPECTED_RESPONSE
Definition: error.h:70
uint8_t length
Definition: tcp.h:368
error_t shellClientReadStream(ShellClientContext *context, void *data, size_t size, size_t *received, uint_t flags)
Read from stdout stream.
Definition: shell_client.c:650
error_t shellClientOpenConnection(ShellClientContext *context)
Open SSH connection.
error_t shellClientClose(ShellClientContext *context)
Close the connection with the SSH server.
Definition: shell_client.c:964
@ ERROR_CONNECTION_CLOSING
Definition: error.h:78
@ SSH_REQUEST_STATE_FAILURE
Definition: ssh.h:1089
void shellClientChangeState(ShellClientContext *context, ShellClientState newState)
Update Shell client state.
uint32_t systime_t
System time.
uint8_t flags
Definition: tcp.h:351
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:48
@ SHELL_CLIENT_STATE_CHANNEL_OPEN
Definition: shell_client.h:79
error_t shellClientDisconnect(ShellClientContext *context)
Gracefully disconnect from the SSH server.
Definition: shell_client.c:865
error_t shellClientWriteStream(ShellClientContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Write to stdin stream.
Definition: shell_client.c:520
@ SSH_REQUEST_STATE_SUCCESS
Definition: ssh.h:1088
#define SHELL_CLIENT_DEFAULT_TIMEOUT
Definition: shell_client.h:46
void shellClientCloseConnection(ShellClientContext *context)
Close SSH connection.
uint8_t n
#define SshConnection
Definition: ssh.h:874
@ SSH_CHANNEL_STATE_RESERVED
Definition: ssh.h:1074
error_t shellClientCheckTimeout(ShellClientContext *context)
Determine whether a timeout error has occurred.
SshString command
Definition: ssh_request.h:120
uint32_t shellClientGetExitStatus(ShellClientContext *context)
Retrieve exit status.
Definition: shell_client.c:838
error_t shellClientRegisterSshInitCallback(ShellClientContext *context, ShellClientSshInitCallback callback)
Register SSH initialization callback function.
Definition: shell_client.c:80
error_t shellClientCloseStream(ShellClientContext *context)
Close stream.
Definition: shell_client.c:737
error_t sshSendChannelRequest(SshChannel *channel, const char_t *requestType, const void *requestParams, bool_t wantReply)
Send SSH_MSG_CHANNEL_REQUEST message.
Definition: ssh_request.c:179
error_t sshSendChannelOpen(SshChannel *channel, const char_t *channelType, const void *channelParams)
Send SSH_MSG_CHANNEL_OPEN message.
unsigned int uint_t
Definition: compiler_port.h:50
@ SSH_CHANNEL_STATE_CLOSED
Definition: ssh.h:1076
#define osMemset(p, value, length)
Definition: os_port.h:135
error_t sshSetChannelTimeout(SshChannel *channel, systime_t timeout)
Set timeout for read/write operations.
Definition: ssh.c:2027
Secure Shell (SSH)
error_t shellClientInit(ShellClientContext *context)
Initialize shell client context.
Definition: shell_client.c:54
@ SHELL_CLIENT_STATE_DISCONNECTING_2
Definition: shell_client.h:85
@ SOCKET_SD_BOTH
Definition: socket.h:161
error_t shellClientConnect(ShellClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish a connection with the specified SSH server.
Definition: shell_client.c:146
error_t shellClientEstablishConnection(ShellClientContext *context)
Establish SSH connection.
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:148
error_t shellClientFormatCommand(ShellClientContext *context, const char_t *command,...)
Format a command line.
Definition: shell_client.c:238
error_t shellClientBindToInterface(ShellClientContext *context, NetInterface *interface)
Bind the shell client to a particular network interface.
Definition: shell_client.c:123
Global request and channel request handling.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define SshChannel
Definition: ssh.h:878
systime_t osGetSystemTime(void)
Retrieve system time.
@ SHELL_CLIENT_STATE_CONNECTING_2
Definition: shell_client.h:76