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