aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiao Pan <xyz@flylightning.xyz>2025-04-06 17:27:44 -0700
committerXiao Pan <xyz@flylightning.xyz>2025-04-06 17:27:44 -0700
commita4ec4b272b2eae527f68cbd40488a7805dc5367b (patch)
tree8c11a53a80b559c5d7941d1ed3d32d2179442dcb
parent9e28e186b4877efa70d2a78b6d7ff7134debdc53 (diff)
Integrate with gtk
-rw-r--r--README.md2
-rw-r--r--remote_plot.c385
-rw-r--r--remote_plot_no_gtk.c329
3 files changed, 574 insertions, 142 deletions
diff --git a/README.md b/README.md
index 7413c54..f771f98 100644
--- a/README.md
+++ b/README.md
@@ -2,5 +2,5 @@ work in progress
build
```
-cc -Wall $(pkg-config --cflags --libs libssh --libs plplot) -lm -o remote_plot remote_plot.c
+cc -Wall $(pkg-config --cflags --libs libssh plplot gtk4) -lm -o remote_plot remote_plot.c
```
diff --git a/remote_plot.c b/remote_plot.c
index b1cb2a6..8f89e62 100644
--- a/remote_plot.c
+++ b/remote_plot.c
@@ -2,6 +2,7 @@
// https://api.libssh.org/stable/libssh_tutorial.html
// https://api.libssh.org/stable/libssh_tutor_guided_tour.html
// plplot example 17
+// plplot example ext-cairo-test.c
#include <libssh/libssh.h>
#include <stdlib.h>
@@ -22,6 +23,8 @@
#include <time.h>
#include <unistd.h>
+#include <gtk/gtk.h>
+
// very small also works, just transfter delays, I test accelerometer data is
// like 15782 which is 7 bytes consider newline and \0?
#define MAX_XFER_BUF_SIZE 7
@@ -30,143 +33,78 @@
static PLINT pl_errcode;
static char errmsg[160];
-int sftp_read_sync(ssh_session session, sftp_session sftp)
+typedef struct {
+ ssh_session session;
+ sftp_session sftp;
+ PLINT id1;
+ PLFLT t[10];
+ PLFLT buffer[10];
+ GtkWidget *area;
+}DATA;
+
+static gboolean sftp_read_sync(gpointer user_data)
+ //int sftp_read_sync(ssh_session session, sftp_session sftp)
{
+ //printf("sftp_read_sync begin\n");
+ DATA *data=user_data;
+
int access_type;
sftp_file file;
char buffer[MAX_XFER_BUF_SIZE];
int nbytes, rc;
access_type = O_RDONLY;
- PLINT id1, autoy, acc;
- PLFLT ymin, ymax, xlab, ylab;
- PLFLT t, tmin, tmax, tjump;
- PLINT colbox, collab, colline[4], styline[4];
- PLCHAR_VECTOR legline[4];
-
- // If db is used the plot is much more smooth. However, because of the
- // async X behaviour, one does not have a real-time scripcharter.
- // This is now disabled since it does not significantly improve the
- // performance on new machines and makes it difficult to use this
- // example non-interactively since it requires an extra pleop call after
- // each call to plstripa.
- //
- //plsetopt("db", "");
- //plsetopt("np", "");
-
- // User sets up plot completely except for window and data
- // Eventually settings in place when strip chart is created will be
- // remembered so that multiple strip charts can be used simultaneously.
- //
-
- // Specify some reasonable defaults for ymin and ymax
- // The plot will grow automatically if needed (but not shrink)
-
- ymin = -0.1;
- ymax = 0.1;
-
- // Specify initial tmin and tmax -- this determines length of window.
- // Also specify maximum jump in t
- // This can accomodate adaptive timesteps
-
- tmin = 0.;
- tmax = 10.;
- tjump = 0.3; // percentage of plot to jump
-
- // Axes options same as plbox.
- // Only automatic tick generation and label placement allowed
- // Eventually I'll make this fancier
-
- colbox = 1;
- collab = 3;
- styline[0] = colline[0] = 2; // pens color and line style
- styline[1] = colline[1] = 3;
- styline[2] = colline[2] = 4;
- styline[3] = colline[3] = 5;
-
- legline[0] = "in_accel_z_raw"; // pens legend
- legline[1] = "not_used";
- legline[2] = "not_used";
- legline[3] = "not_used";
-
- xlab = 0.; ylab = 0.25; // legend position
-
- autoy = 1; // autoscale y
- acc = 1; // don't scrip, accumulate
-
- // Initialize plplot
-
- plinit();
-
- pladv( 0 );
- plvsta();
-
- // Register our error variables with PLplot
- // From here on, we're handling all errors here
-
- plsError( &pl_errcode, errmsg );
-
- plstripc( &id1, "bcnst", "bcnstv",
- tmin, tmax, tjump, ymin, ymax,
- xlab, ylab,
- autoy, acc,
- colbox, collab,
- colline, styline, legline,
- "t", "", "Strip chart demo" );
-
- if ( pl_errcode )
- {
- fprintf( stderr, "%s\n", errmsg );
- exit( 1 );
- }
-
- // Let plplot handle errors from here on
-
- plsError( NULL, NULL );
-
- autoy = 0; // autoscale y
- acc = 1; // accumulate
-
// This is to represent a loop over time
// Let's try a random walk process
- for (t=0;;t++) {
- file = sftp_open(sftp, "/sys/bus/iio/devices/iio:device2/in_accel_z_raw",
- access_type, 0);
- if (file == NULL) {
- fprintf(stderr, "Can't open file for reading: %s\n",
- ssh_get_error(session));
+ file = sftp_open(data->sftp, "/sys/bus/iio/devices/iio:device2/in_accel_z_raw",
+ access_type, 0);
+ if (file == NULL) {
+ fprintf(stderr, "Can't open file for reading: %s\n",
+ ssh_get_error(data->session));
+ return SSH_ERROR;
+ }
+
+ for(int i=0;i<9;i++)
+ data->buffer[i]=data->buffer[i+1];
+
+ for (;;) {
+ nbytes = sftp_read(file, buffer, sizeof(buffer));
+ if (nbytes == 0) {
+ break; // EOF
+ } else if (nbytes < 0) {
+ fprintf(stderr, "Error while reading file: %s\n",
+ ssh_get_error(data->session));
+ sftp_close(file);
return SSH_ERROR;
}
- for (;;) {
- nbytes = sftp_read(file, buffer, sizeof(buffer));
- if (nbytes == 0) {
- break; // EOF
- } else if (nbytes < 0) {
- fprintf(stderr, "Error while reading file: %s\n",
- ssh_get_error(session));
- sftp_close(file);
- return SSH_ERROR;
- }
-
- //printf("%s",buffer);
- //printf("%d\n",atoi(buffer));
- plstripa( id1, 0, t, atof(buffer));
- }
+ //printf("buffer %s",buffer);
+ //printf("buffer int %d\n",atoi(buffer));
+ //printf("id1 %d\n",data->id1);
+ //printf("t %f\n",data->t[9]);
+ //printf("before sftp_read_sync plstripa\n");
+ data->buffer[9]=atof(buffer);
+ //printf("after sftp_read_sync plstripa\n");
}
rc = sftp_close(file);
if (rc != SSH_OK) {
fprintf(stderr, "Can't close the read file: %s\n",
- ssh_get_error(session));
+ ssh_get_error(data->session));
return rc;
}
- plstripd( id1 );
- plend();
+ for(int i=0;i<10;i++)
+ data->t[i]++;
+ //printf("sftp_read_sync end\n");
- return SSH_OK;
+ gtk_widget_queue_draw(data->area);
+
+ //return SSH_OK;
+ // must return G_SOURCE_CONTINUE to keep polling
+ // return G_SOURCE_REMOVE to stop
+ return G_SOURCE_CONTINUE;
}
// https://api.libssh.org/stable/libssh_tutor_guided_tour.html
@@ -257,73 +195,238 @@ int verify_knownhost(ssh_session session)
return 0;
}
-int main(void)
+static void draw_function (GtkDrawingArea *area,
+ cairo_t *cr,
+ int width,
+ int height,
+ gpointer user_data)
{
- ssh_session my_ssh_session;
- sftp_session sftp;
+ //printf("draw begin\n");
+ DATA *data=user_data;
+
+ PLINT autoy, acc;
+ PLFLT ymin, ymax, xlab, ylab;
+ PLFLT tmin, tmax, tjump;
+ PLINT colbox, collab, colline[4], styline[4];
+ PLCHAR_VECTOR legline[4];
+
+ // If db is used the plot is much more smooth. However, because of the
+ // async X behaviour, one does not have a real-time scripcharter.
+ // This is now disabled since it does not significantly improve the
+ // performance on new machines and makes it difficult to use this
+ // example non-interactively since it requires an extra pleop call after
+ // each call to plstripa.
+ //
+ //plsetopt("db", "");
+ //plsetopt("np", "");
+
+ // User sets up plot completely except for window and data
+ // Eventually settings in place when strip chart is created will be
+ // remembered so that multiple strip charts can be used simultaneously.
+ //
+
+ // Specify some reasonable defaults for ymin and ymax
+ // The plot will grow automatically if needed (but not shrink)
+
+ ymin = -0.1;
+ ymax = 0.1;
+
+ // Specify initial tmin and tmax -- this determines length of window.
+ // Also specify maximum jump in t
+ // This can accomodate adaptive timesteps
+
+ tmin = 0.;
+ tmax = 10.;
+ tjump = 0.3; // percentage of plot to jump
+
+ // Axes options same as plbox.
+ // Only automatic tick generation and label placement allowed
+ // Eventually I'll make this fancier
+
+ colbox = 1;
+ collab = 3;
+ styline[0] = colline[0] = 2; // pens color and line style
+ styline[1] = colline[1] = 3;
+ styline[2] = colline[2] = 4;
+ styline[3] = colline[3] = 5;
+
+ legline[0] = "in_accel_z_raw"; // pens legend
+ legline[1] = "not_used";
+ legline[2] = "not_used";
+ legline[3] = "not_used";
+
+ xlab = 0.; ylab = 0.25; // legend position
+
+ autoy = 1; // autoscale y
+ acc = 1; // don't scrip, accumulate
+
+ // Initialize plplot
+
+ plsdev( "extcairo" );
+ plinit();
+ pl_cmd( PLESC_DEVINIT, cr );
+
+ pladv( 0 );
+ plvsta();
+
+ // Register our error variables with PLplot
+ // From here on, we're handling all errors here
+
+ plsError( &pl_errcode, errmsg );
+
+ //plstripc( &(data->id1), "bcnst", "bcnstv",
+ plstripc( &(data->id1), "bcnst", "bcnstv",
+ tmin, tmax, tjump, ymin, ymax,
+ xlab, ylab,
+ autoy, acc,
+ colbox, collab,
+ colline, styline, legline,
+ "t", "", "Strip chart demo" );
+
+ if ( pl_errcode )
+ {
+ fprintf( stderr, "%s\n", errmsg );
+ exit( 1 );
+ }
+
+ // Let plplot handle errors from here on
+
+ plsError( NULL, NULL );
+
+ autoy = 0; // autoscale y
+ acc = 1; // accumulate
+
+ for(int i=0;i<10;i++)
+ {
+ //printf("t%d %f\n",i,data->t[i]);
+ //printf("buffer%d %f\n",i,data->buffer[i]);
+ plstripa( data->id1, 0, data->t[i], data->buffer[i]);
+ }
+
+ //printf("before pl free\n");
+ plstripd( data->id1 );
+ plend();
+ //printf("draw done\n");
+}
+
+static void print_hello (GtkWidget *widget, gpointer user_data)
+{
+ g_print ("Hello World\n");
+}
+
+static void activate (GtkApplication *app, gpointer user_data)
+{
+ DATA *data=user_data;
+ GtkWidget *window;
+ data->area = gtk_drawing_area_new ();
+ GtkWidget *button;
+ GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL,1);
+
+ window = gtk_application_window_new (app);
+ gtk_window_set_title (GTK_WINDOW (window), "remote_plot");
+ gtk_window_set_default_size (GTK_WINDOW (window), 1000, 1000);
+
+ gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (data->area), 600);
+ gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (data->area), 600);
+ gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (data->area),
+ draw_function,
+ user_data, NULL);
+
+ button = gtk_button_new_with_label ("Hello World");
+ g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
+
+ gtk_box_append(GTK_BOX(box), button);
+ gtk_box_append(GTK_BOX(box), data->area);
+ gtk_window_set_child (GTK_WINDOW (window), box);
+
+ gtk_window_present (GTK_WINDOW (window));
+
+ g_timeout_add(50,sftp_read_sync,user_data);
+ //printf("after g_timeout_add\n");
+}
+
+int main (int argc, char **argv)
+{
+ DATA data;
+ //ssh_session session;
+ //sftp_session sftp;
int rc;
+ GtkApplication *app;
+ int status;
+
+ for(int i=0;i<10;i++)
+ {
+ data.t[i]=i;
+ data.buffer[i]=0;
+ }
+
// Open session and set options
- my_ssh_session = ssh_new();
- if (my_ssh_session == NULL)
+ data.session = ssh_new();
+ if (data.session == NULL)
exit(-1);
- ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "10.0.0.7");
+ ssh_options_set(data.session, SSH_OPTIONS_HOST, "10.0.0.7");
// Connect to server
- rc = ssh_connect(my_ssh_session);
+ rc = ssh_connect(data.session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error connecting to 10.0.0.7: %s\n",
- ssh_get_error(my_ssh_session));
- ssh_free(my_ssh_session);
+ ssh_get_error(data.session));
+ ssh_free(data.session);
exit(-1);
}
// Verify the server's identity
// For the source code of verify_knownhost(), check previous example
- if (verify_knownhost(my_ssh_session) < 0)
+ if (verify_knownhost(data.session) < 0)
{
- ssh_disconnect(my_ssh_session);
- ssh_free(my_ssh_session);
+ ssh_disconnect(data.session);
+ ssh_free(data.session);
exit(-1);
}
// Authenticate ourselves
// https://api.libssh.org/stable/libssh_tutor_authentication.html
- rc = ssh_userauth_publickey_auto(my_ssh_session, NULL, NULL);
+ rc = ssh_userauth_publickey_auto(data.session, NULL, NULL);
if (rc != SSH_AUTH_SUCCESS)
{
fprintf(stderr, "Error authenticating with key: %s\n",
- ssh_get_error(my_ssh_session));
- ssh_disconnect(my_ssh_session);
- ssh_free(my_ssh_session);
+ ssh_get_error(data.session));
+ ssh_disconnect(data.session);
+ ssh_free(data.session);
exit(-1);
}
- sftp = sftp_new(my_ssh_session);
- if (sftp == NULL)
+ data.sftp = sftp_new(data.session);
+ if (data.sftp == NULL)
{
fprintf(stderr, "Error allocating SFTP session: %s\n",
- ssh_get_error(my_ssh_session));
+ ssh_get_error(data.session));
return SSH_ERROR;
}
- rc = sftp_init(sftp);
+ rc = sftp_init(data.sftp);
if (rc != SSH_OK)
{
fprintf(stderr, "Error initializing SFTP session: code %d.\n",
- sftp_get_error(sftp));
- sftp_free(sftp);
+ sftp_get_error(data.sftp));
+ sftp_free(data.sftp);
return rc;
}
- sftp_read_sync(my_ssh_session,sftp);
+ app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
+ g_signal_connect (app, "activate", G_CALLBACK (activate), &data);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
+
+ //printf("before ssh free\n");
- ssh_disconnect(my_ssh_session);
- ssh_free(my_ssh_session);
+ ssh_disconnect(data.session);
+ ssh_free(data.session);
// Segmentation fault (core dumped) error, why? maybe double free? so no free is ok?
//sftp_free(sftp);
- return 0;
+ return status;
}
diff --git a/remote_plot_no_gtk.c b/remote_plot_no_gtk.c
new file mode 100644
index 0000000..b1cb2a6
--- /dev/null
+++ b/remote_plot_no_gtk.c
@@ -0,0 +1,329 @@
+// references:
+// https://api.libssh.org/stable/libssh_tutorial.html
+// https://api.libssh.org/stable/libssh_tutor_guided_tour.html
+// plplot example 17
+
+#include <libssh/libssh.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <libssh/sftp.h>
+
+// verify_knownhost()
+#include <errno.h>
+#include <string.h>
+
+#include <fcntl.h> // open()
+
+// plplot
+#include <plplot/plConfig.h>
+#include <plplot/plplot.h>
+#include <math.h>
+//#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+// very small also works, just transfter delays, I test accelerometer data is
+// like 15782 which is 7 bytes consider newline and \0?
+#define MAX_XFER_BUF_SIZE 7
+
+// Variables for holding error return info from PLplot
+static PLINT pl_errcode;
+static char errmsg[160];
+
+int sftp_read_sync(ssh_session session, sftp_session sftp)
+{
+ int access_type;
+ sftp_file file;
+ char buffer[MAX_XFER_BUF_SIZE];
+ int nbytes, rc;
+ access_type = O_RDONLY;
+
+ PLINT id1, autoy, acc;
+ PLFLT ymin, ymax, xlab, ylab;
+ PLFLT t, tmin, tmax, tjump;
+ PLINT colbox, collab, colline[4], styline[4];
+ PLCHAR_VECTOR legline[4];
+
+ // If db is used the plot is much more smooth. However, because of the
+ // async X behaviour, one does not have a real-time scripcharter.
+ // This is now disabled since it does not significantly improve the
+ // performance on new machines and makes it difficult to use this
+ // example non-interactively since it requires an extra pleop call after
+ // each call to plstripa.
+ //
+ //plsetopt("db", "");
+ //plsetopt("np", "");
+
+ // User sets up plot completely except for window and data
+ // Eventually settings in place when strip chart is created will be
+ // remembered so that multiple strip charts can be used simultaneously.
+ //
+
+ // Specify some reasonable defaults for ymin and ymax
+ // The plot will grow automatically if needed (but not shrink)
+
+ ymin = -0.1;
+ ymax = 0.1;
+
+ // Specify initial tmin and tmax -- this determines length of window.
+ // Also specify maximum jump in t
+ // This can accomodate adaptive timesteps
+
+ tmin = 0.;
+ tmax = 10.;
+ tjump = 0.3; // percentage of plot to jump
+
+ // Axes options same as plbox.
+ // Only automatic tick generation and label placement allowed
+ // Eventually I'll make this fancier
+
+ colbox = 1;
+ collab = 3;
+ styline[0] = colline[0] = 2; // pens color and line style
+ styline[1] = colline[1] = 3;
+ styline[2] = colline[2] = 4;
+ styline[3] = colline[3] = 5;
+
+ legline[0] = "in_accel_z_raw"; // pens legend
+ legline[1] = "not_used";
+ legline[2] = "not_used";
+ legline[3] = "not_used";
+
+ xlab = 0.; ylab = 0.25; // legend position
+
+ autoy = 1; // autoscale y
+ acc = 1; // don't scrip, accumulate
+
+ // Initialize plplot
+
+ plinit();
+
+ pladv( 0 );
+ plvsta();
+
+ // Register our error variables with PLplot
+ // From here on, we're handling all errors here
+
+ plsError( &pl_errcode, errmsg );
+
+ plstripc( &id1, "bcnst", "bcnstv",
+ tmin, tmax, tjump, ymin, ymax,
+ xlab, ylab,
+ autoy, acc,
+ colbox, collab,
+ colline, styline, legline,
+ "t", "", "Strip chart demo" );
+
+ if ( pl_errcode )
+ {
+ fprintf( stderr, "%s\n", errmsg );
+ exit( 1 );
+ }
+
+ // Let plplot handle errors from here on
+
+ plsError( NULL, NULL );
+
+ autoy = 0; // autoscale y
+ acc = 1; // accumulate
+
+ // This is to represent a loop over time
+ // Let's try a random walk process
+
+ for (t=0;;t++) {
+ file = sftp_open(sftp, "/sys/bus/iio/devices/iio:device2/in_accel_z_raw",
+ access_type, 0);
+ if (file == NULL) {
+ fprintf(stderr, "Can't open file for reading: %s\n",
+ ssh_get_error(session));
+ return SSH_ERROR;
+ }
+
+ for (;;) {
+ nbytes = sftp_read(file, buffer, sizeof(buffer));
+ if (nbytes == 0) {
+ break; // EOF
+ } else if (nbytes < 0) {
+ fprintf(stderr, "Error while reading file: %s\n",
+ ssh_get_error(session));
+ sftp_close(file);
+ return SSH_ERROR;
+ }
+
+ //printf("%s",buffer);
+ //printf("%d\n",atoi(buffer));
+ plstripa( id1, 0, t, atof(buffer));
+ }
+ }
+
+ rc = sftp_close(file);
+ if (rc != SSH_OK) {
+ fprintf(stderr, "Can't close the read file: %s\n",
+ ssh_get_error(session));
+ return rc;
+ }
+
+ plstripd( id1 );
+ plend();
+
+ return SSH_OK;
+}
+
+// https://api.libssh.org/stable/libssh_tutor_guided_tour.html
+int verify_knownhost(ssh_session session)
+{
+ enum ssh_known_hosts_e state;
+ unsigned char *hash = NULL;
+ ssh_key srv_pubkey = NULL;
+ size_t hlen;
+ char buf[10];
+ char *hexa;
+ char *p;
+ int cmp;
+ int rc;
+
+ rc = ssh_get_server_publickey(session, &srv_pubkey);
+ if (rc < 0) {
+ return -1;
+ }
+
+ rc = ssh_get_publickey_hash(srv_pubkey,
+ SSH_PUBLICKEY_HASH_SHA1,
+ &hash,
+ &hlen);
+ ssh_key_free(srv_pubkey);
+ if (rc < 0) {
+ return -1;
+ }
+
+ state = ssh_session_is_known_server(session);
+ switch (state) {
+ case SSH_KNOWN_HOSTS_OK:
+ /* OK */
+
+ break;
+ case SSH_KNOWN_HOSTS_CHANGED:
+ fprintf(stderr, "Host key for server changed: it is now:\n");
+ ssh_print_hexa("Public key hash", hash, hlen);
+ fprintf(stderr, "For security reasons, connection will be stopped\n");
+ ssh_clean_pubkey_hash(&hash);
+
+ return -1;
+ case SSH_KNOWN_HOSTS_OTHER:
+ fprintf(stderr, "The host key for this server was not found but an other"
+ "type of key exists.\n");
+ fprintf(stderr, "An attacker might change the default server key to"
+ "confuse your client into thinking the key does not exist\n");
+ ssh_clean_pubkey_hash(&hash);
+
+ return -1;
+ case SSH_KNOWN_HOSTS_NOT_FOUND:
+ fprintf(stderr, "Could not find known host file.\n");
+ fprintf(stderr, "If you accept the host key here, the file will be"
+ "automatically created.\n");
+
+ /* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */
+
+ case SSH_KNOWN_HOSTS_UNKNOWN:
+ hexa = ssh_get_hexa(hash, hlen);
+ fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
+ fprintf(stderr, "Public key hash: %s\n", hexa);
+ ssh_string_free_char(hexa);
+ ssh_clean_pubkey_hash(&hash);
+ p = fgets(buf, sizeof(buf), stdin);
+ if (p == NULL) {
+ return -1;
+ }
+
+ cmp = strncasecmp(buf, "yes", 3);
+ if (cmp != 0) {
+ return -1;
+ }
+
+ rc = ssh_session_update_known_hosts(session);
+ if (rc < 0) {
+ fprintf(stderr, "Error %s\n", strerror(errno));
+ return -1;
+ }
+
+ break;
+ case SSH_KNOWN_HOSTS_ERROR:
+ fprintf(stderr, "Error %s", ssh_get_error(session));
+ ssh_clean_pubkey_hash(&hash);
+ return -1;
+ }
+
+ ssh_clean_pubkey_hash(&hash);
+ return 0;
+}
+
+int main(void)
+{
+ ssh_session my_ssh_session;
+ sftp_session sftp;
+ int rc;
+
+ // Open session and set options
+ my_ssh_session = ssh_new();
+ if (my_ssh_session == NULL)
+ exit(-1);
+ ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "10.0.0.7");
+
+ // Connect to server
+ rc = ssh_connect(my_ssh_session);
+ if (rc != SSH_OK)
+ {
+ fprintf(stderr, "Error connecting to 10.0.0.7: %s\n",
+ ssh_get_error(my_ssh_session));
+ ssh_free(my_ssh_session);
+ exit(-1);
+ }
+
+ // Verify the server's identity
+ // For the source code of verify_knownhost(), check previous example
+ if (verify_knownhost(my_ssh_session) < 0)
+ {
+ ssh_disconnect(my_ssh_session);
+ ssh_free(my_ssh_session);
+ exit(-1);
+ }
+
+ // Authenticate ourselves
+ // https://api.libssh.org/stable/libssh_tutor_authentication.html
+ rc = ssh_userauth_publickey_auto(my_ssh_session, NULL, NULL);
+ if (rc != SSH_AUTH_SUCCESS)
+ {
+ fprintf(stderr, "Error authenticating with key: %s\n",
+ ssh_get_error(my_ssh_session));
+ ssh_disconnect(my_ssh_session);
+ ssh_free(my_ssh_session);
+ exit(-1);
+ }
+
+
+ sftp = sftp_new(my_ssh_session);
+ if (sftp == NULL)
+ {
+ fprintf(stderr, "Error allocating SFTP session: %s\n",
+ ssh_get_error(my_ssh_session));
+ return SSH_ERROR;
+ }
+
+ rc = sftp_init(sftp);
+ if (rc != SSH_OK)
+ {
+ fprintf(stderr, "Error initializing SFTP session: code %d.\n",
+ sftp_get_error(sftp));
+ sftp_free(sftp);
+ return rc;
+ }
+
+ sftp_read_sync(my_ssh_session,sftp);
+
+ ssh_disconnect(my_ssh_session);
+ ssh_free(my_ssh_session);
+ // Segmentation fault (core dumped) error, why? maybe double free? so no free is ok?
+ //sftp_free(sftp);
+
+ return 0;
+}