Advertisement
Guest User

sftp_readahead.c

a guest
Jun 8th, 2015
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.61 KB | None | 0 0
  1. /*
  2.  * Example that demonstrates SFTP read-ahead with libssh
  3.  *
  4.  * Usage:
  5.  * sftp_readahead <user> <password> <host> <filepath> [<read_ahead_size>]
  6.  */
  7.  
  8. #include <ctype.h>
  9. #include <errno.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <libssh/libssh.h>
  14. #include <libssh/sftp.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17.  
  18. // Declarations
  19.  
  20. typedef struct {
  21.    int* buffer;
  22.    int* buffer_end;
  23.    int* data_start;
  24.    int* data_end;
  25.    uint64_t  count;
  26.    uint64_t  size;
  27. } ring_buffer;
  28.  
  29. static int sftp_fread(char* buffer, size_t bytesRequested, sftp_file handle, ring_buffer* readAheadBuf, size_t* bytesReturned);
  30.  
  31. static int  ringbuffer_init(ring_buffer* rb, uint64_t size);
  32. static void ringbuffer_free(ring_buffer* rb);
  33. static void ringbuffer_push(ring_buffer* rb, int data);
  34. static int  ringbuffer_pop(ring_buffer* rb);
  35. static int  ringbuffer_full(ring_buffer* rb);
  36. static int  ringbuffer_empty(ring_buffer* rb);
  37.  
  38. // Implementation
  39.  
  40. static int sftp_fread(char* buffer, size_t bytesRequested, sftp_file handle, ring_buffer* readAheadBuf, size_t* bytesReturned) {
  41.    size_t bytesToRead = bytesRequested;
  42.    int bytesRead = 1, async_request, result = 0;
  43.  
  44.    // ensure fread() semantics (always return full buffers unless eof/error)
  45.    while (bytesToRead > 0) {
  46.       if (bytesRead > 0) {
  47.          // send a request and put its handle into the ring buffer until full
  48.          while (!ringbuffer_full(readAheadBuf)) {
  49.             async_request = sftp_async_read_begin(handle, bytesToRead);
  50.             //fprintf(stderr, "Sent request %d\n", async_request);
  51.             if (async_request >= 0) {
  52.                ringbuffer_push(readAheadBuf, async_request);
  53.             }
  54.          }
  55.       }
  56.       // read data from one response
  57.       if (!ringbuffer_empty(readAheadBuf)) {
  58.          async_request = ringbuffer_pop(readAheadBuf);
  59.          //fprintf(stderr, "Waiting for reply %d\n", async_request);
  60.          bytesRead = sftp_async_read(handle, buffer, bytesToRead, async_request);
  61.          if (bytesRead>0) {
  62.             bytesToRead -= bytesRead;
  63.             buffer+=bytesRead;
  64.          } else if (bytesRead == 0) { // EOF
  65.             result = 1;
  66.             break;
  67.          } else {  // Error
  68.             result = 2;
  69.             break;
  70.          }
  71.       } else {
  72.          fprintf(stderr, "Error: ringbuffer empty\n");
  73.          result = 2;
  74.          break;
  75.       }
  76.    }
  77.  
  78.    *bytesReturned = bytesRequested - bytesToRead;
  79.    return result;
  80. }
  81.  
  82. int main(int argc, char *argv[]) {
  83.    char *username=NULL, *password=NULL, *hostname=NULL, *filepath=NULL;
  84.    ssh_session sshSession;
  85.    sftp_session sftpSession;
  86.    sftp_file sftpFile;
  87.    ring_buffer readAheadBuf;
  88.    long timeout = 30;
  89.    int rc;
  90.    char buffer[4096];
  91.    int readAheadMax = 128;
  92.    size_t read, readTotal = 0;
  93.  
  94.    if (argc != 5 && argc != 6) {
  95.       fprintf(stderr, "Usage: %s <user> <password> <host> <filepath> [<read_ahead_size>]\n", argv[0]);
  96.       fprintf(stderr, "<read_ahead_size> defaults to %d blocks of 4 KiB\n", readAheadMax);
  97.       return 1;
  98.    }
  99.    username = argv[1];
  100.    password = argv[2];
  101.    hostname = argv[3];
  102.    filepath = argv[4];
  103.    if (argc == 6) {
  104.       readAheadMax = atoi(argv[5]);
  105.    }
  106.  
  107.    if (readAheadMax <= 0) {
  108.       fprintf(stderr, "<read_ahead_size> parameter must be a positive number of 4 KiB blocks\n");
  109.    }
  110.  
  111.    // create SSH session handle
  112.    sshSession = ssh_new();
  113.    if (sshSession == NULL) {
  114.       fprintf(stderr, "libssh failed to initialize the session!\n");
  115.       return 1;
  116.    }
  117.  
  118.    // configure session
  119.    ssh_options_set(sshSession, SSH_OPTIONS_HOST, hostname);
  120.    ssh_options_set(sshSession, SSH_OPTIONS_USER, username);
  121.    ssh_options_set(sshSession, SSH_OPTIONS_TIMEOUT, &timeout);
  122.    ssh_options_set(sshSession, SSH_OPTIONS_LOG_VERBOSITY, "SSH_LOG_PACKET");
  123.  
  124.    // Connect to server
  125.    rc = ssh_connect(sshSession);
  126.    if (rc != SSH_OK) {
  127.       fprintf(stderr, "Error connecting to %s: %s\n", hostname, ssh_get_error(sshSession));
  128.       return 1;
  129.    }
  130.  
  131.    fprintf(stderr, "Connected.\n");
  132.  
  133.    // set blocking mode
  134.    ssh_set_blocking(sshSession, 1);
  135.  
  136.    // authenticate with password
  137.    rc = ssh_userauth_password(sshSession, NULL, password);
  138.    if (rc != SSH_AUTH_SUCCESS) {
  139.       fprintf(stderr, "Error authenticating with password: %s\n", ssh_get_error(sshSession));
  140.       return 1;
  141.    }
  142.  
  143.    fprintf(stderr, "Authenticated.\n");
  144.  
  145.    // start SFTP session
  146.    sftpSession = sftp_new(sshSession);
  147.    if (sftpSession == NULL) {
  148.        fprintf(stderr, "Unable to init SFTP session\n");
  149.        return 1;
  150.    }
  151.  
  152.    rc = sftp_init(sftpSession);
  153.    if (rc != SSH_OK) {
  154.       fprintf(stderr, "Error initializing SFTP session: %s.\n", ssh_get_error(sshSession));
  155.       return 1;
  156.    }
  157.  
  158.    // open file via SFTP
  159.    sftpFile =  sftp_open(sftpSession, filepath, O_RDONLY, 0);
  160.    if (sftpFile == NULL) {
  161.       fprintf(stderr, "Cannot open file %s for reading: %s\n", filepath, ssh_get_error(sshSession));
  162.       return 1;
  163.    }
  164.  
  165.    // initialize ring buffer
  166.    if (!ringbuffer_init(&readAheadBuf, readAheadMax)) {
  167.       fprintf(stderr, "Could not allocate read ahead buffer\n");
  168.       return 1;
  169.    }
  170.  
  171.    fprintf(stderr, "Reading file %s ...\n", filepath);
  172.  
  173.    // read the whole file
  174.    do {
  175.       rc = sftp_fread(buffer, sizeof(buffer), sftpFile, &readAheadBuf, &read);
  176.       readTotal += read;
  177.    } while (rc == 0);
  178.  
  179.    if (rc == 1) {
  180.       fprintf(stderr, "EOF reached\n");
  181.    } else if (rc == 2) {
  182.       fprintf(stderr, "Error while reading: %s\n", ssh_get_error(sshSession));
  183.    }
  184.  
  185.    fprintf(stderr, "Read %lu bytes.\n", (unsigned long)readTotal);
  186.  
  187.    /* Need to read any requested blocks prior to sftp_close()?
  188.    while (!ringbuffer_empty(&readAheadBuf)) {
  189.       // skip over any requested but unfetched data
  190.       rc = ringbuffer_pop(&readAheadBuf);
  191.       fprintf(stderr, "skipping %d\n", rc);
  192.       sftp_async_read(sftpFile, buffer, bufsize, rc);
  193.    }
  194.    */
  195.  
  196.    // clean up
  197.    fprintf(stderr, "sftp_close()");
  198.    rc = sftp_close(sftpFile);
  199.    fprintf(stderr, " done\n");
  200.    if(rc==SSH_ERROR) {
  201.       fprintf(stderr, "Failed to close the file\n");
  202.    }
  203.    sftp_free(sftpSession);
  204.    ssh_disconnect(sshSession);
  205.    ssh_free(sshSession);
  206.    ringbuffer_free(&readAheadBuf);
  207.  
  208.    fprintf(stderr, "Done\n");
  209.  
  210.    return 0;
  211. }
  212.  
  213. // *********************Ring Buffer implementation**********************
  214. static int ringbuffer_init(ring_buffer* rb, uint64_t size) {
  215.    rb->buffer = malloc(sizeof(int) * size);
  216.    rb->buffer_end = rb->buffer + size;
  217.    rb->size = size;
  218.    rb->data_start = rb->buffer;
  219.    rb->data_end = rb->buffer;
  220.    rb->count = 0;
  221.    return rb->buffer != NULL;
  222. }
  223.  
  224. static void ringbuffer_free(ring_buffer* rb) {
  225.    if (rb->buffer != NULL) {
  226.       free(rb->buffer);
  227.       rb->buffer = NULL;
  228.    }
  229. }
  230.  
  231. static void ringbuffer_push(ring_buffer* rb, int data) {
  232.    *rb->data_end = data;
  233.    rb->data_end++;
  234.    if (rb->data_end == rb->buffer_end)
  235.       rb->data_end = rb->buffer;
  236.  
  237.    if (ringbuffer_full(rb)) {
  238.       if ((rb->data_start + 1) == rb->buffer_end)
  239.          rb->data_start = rb->buffer;
  240.       else
  241.          rb->data_start++;
  242.    } else {
  243.       rb->count++;
  244.    }
  245. }
  246.  
  247. static int ringbuffer_pop(ring_buffer* rb) {
  248.    int data = *rb->data_start;
  249.    rb->data_start++;
  250.    if (rb->data_start == rb->buffer_end)
  251.       rb->data_start = rb->buffer;
  252.    rb->count--;
  253.  
  254.    return data;
  255. }
  256.  
  257. static int ringbuffer_full(ring_buffer* rb) {
  258.    return rb->count == rb->size;
  259. }
  260.  
  261. static int ringbuffer_empty(ring_buffer* rb) {
  262.    return rb->count == 0;
  263. }
  264.  
  265. /**********************************************************************/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement