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