diff --git a/tests/client/torture_sftp_aio.c b/tests/client/torture_sftp_aio.c index 4f62fa38..4cbb5793 100644 --- a/tests/client/torture_sftp_aio.c +++ b/tests/client/torture_sftp_aio.c @@ -60,13 +60,13 @@ static int session_teardown(void **state) return 0; } -static void torture_sftp_aio_read(void **state) +static void torture_sftp_aio_read_file(void **state) { struct torture_state *s = *state; struct torture_sftp *t = s->ssh.tsftp; struct { - char buf[MAX_XFER_BUF_SIZE]; + char *buf; ssize_t bytes_read; } a = {0}, b = {0}; @@ -74,17 +74,31 @@ static void torture_sftp_aio_read(void **state) sftp_attributes file_attr = NULL; int fd; - size_t chunk_size = MAX_XFER_BUF_SIZE; + size_t chunk_size; int in_flight_requests = 20; sftp_aio aio = NULL; struct ssh_list *aio_queue = NULL; + sftp_limits_t li = NULL; size_t file_size; - size_t bytes_requested; + size_t total_bytes_requested; size_t to_read, total_bytes_read; + ssize_t bytes_requested; + int i, rc; + /* Get the max limit for reading, use it as the chunk size */ + li = sftp_limits(t->sftp); + assert_non_null(li); + chunk_size = li->max_read_length; + + a.buf = calloc(chunk_size, 1); + assert_non_null(a.buf); + + b.buf = calloc(chunk_size, 1); + assert_non_null(b.buf); + aio_queue = ssh_list_new(); assert_non_null(aio_queue); @@ -99,18 +113,18 @@ static void torture_sftp_aio_read(void **state) assert_non_null(file_attr); file_size = file_attr->size; - bytes_requested = 0; + total_bytes_requested = 0; for (i = 0; - i < in_flight_requests && bytes_requested < file_size; + i < in_flight_requests && total_bytes_requested < file_size; ++i) { - to_read = file_size - bytes_requested; + to_read = file_size - total_bytes_requested; if (to_read > chunk_size) { to_read = chunk_size; } - rc = sftp_aio_begin_read(file, to_read, &aio); - assert_int_equal(rc, SSH_OK); - bytes_requested += to_read; + bytes_requested = sftp_aio_begin_read(file, to_read, &aio); + assert_int_equal(bytes_requested, to_read); + total_bytes_requested += bytes_requested; /* enqueue */ rc = ssh_list_append(aio_queue, aio); @@ -119,7 +133,7 @@ static void torture_sftp_aio_read(void **state) total_bytes_read = 0; while ((aio = ssh_list_pop_head(sftp_aio, aio_queue)) != NULL) { - a.bytes_read = sftp_aio_wait_read(&aio, a.buf, sizeof(a.buf)); + a.bytes_read = sftp_aio_wait_read(&aio, a.buf, chunk_size); assert_int_not_equal(a.bytes_read, SSH_ERROR); total_bytes_read += (size_t)a.bytes_read; @@ -129,9 +143,8 @@ static void torture_sftp_aio_read(void **state) * Failure of this assertion means that a short * read is encountered but we have not reached * the end of file yet. A short read before reaching - * the end of file should not occur for disk files - * according to the SFTP protocol. (In our code the - * file SSH_EXECUTABLE being read is a disk file) + * the end of file should not occur for our test where + * the chunk size respects the max limit for reading. */ } @@ -147,19 +160,19 @@ static void torture_sftp_aio_read(void **state) assert_int_equal(rc, 0); /* Issue more read requests if needed */ - if (bytes_requested == file_size) { + if (total_bytes_requested == file_size) { continue; } /* else issue more requests */ - to_read = file_size - bytes_requested; + to_read = file_size - total_bytes_requested; if (to_read > chunk_size) { to_read = chunk_size; } - rc = sftp_aio_begin_read(file, to_read, &aio); - assert_int_equal(rc, SSH_OK); - bytes_requested += to_read; + bytes_requested = sftp_aio_begin_read(file, to_read, &aio); + assert_int_equal(bytes_requested, to_read); + total_bytes_requested += bytes_requested; /* enqueue */ rc = ssh_list_append(aio_queue, aio); @@ -170,20 +183,59 @@ static void torture_sftp_aio_read(void **state) * Check whether sftp server responds with an * eof for more requests. */ - rc = sftp_aio_begin_read(file, chunk_size, &aio); - assert_int_equal(rc, SSH_OK); + bytes_requested = sftp_aio_begin_read(file, chunk_size, &aio); + assert_int_equal(bytes_requested, chunk_size); - a.bytes_read = sftp_aio_wait_read(&aio, a.buf, sizeof(a.buf)); + a.bytes_read = sftp_aio_wait_read(&aio, a.buf, chunk_size); assert_int_equal(a.bytes_read, 0); - /* Cleanup */ + /* Clean up */ sftp_attributes_free(file_attr); close(fd); sftp_close(file); ssh_list_free(aio_queue); + free(b.buf); + free(a.buf); + sftp_limits_free(li); } -static void torture_sftp_aio_write(void **state) +static void torture_sftp_aio_read_more_than_cap(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + + sftp_limits_t li = NULL; + sftp_file file = NULL; + sftp_aio aio = NULL; + + char *buf = NULL; + ssize_t bytes; + + /* Get the max limit for reading */ + li = sftp_limits(t->sftp); + assert_non_null(li); + + file = sftp_open(t->sftp, SSH_EXECUTABLE, O_RDONLY, 0); + assert_non_null(file); + + /* Try reading more than the max limit */ + bytes = sftp_aio_begin_read(file, + li->max_read_length * 2, + &aio); + assert_int_equal(bytes, li->max_read_length); + + buf = calloc(li->max_read_length, 1); + assert_non_null(buf); + + bytes = sftp_aio_wait_read(&aio, buf, li->max_read_length); + assert_int_not_equal(bytes, SSH_ERROR); + + free(buf); + sftp_close(file); + sftp_limits_free(li); +} + +static void torture_sftp_aio_write_file(void **state) { struct torture_state *s = *state; struct torture_sftp *t = s->ssh.tsftp; @@ -193,15 +245,29 @@ static void torture_sftp_aio_write(void **state) int fd; struct { - char buf[MAX_XFER_BUF_SIZE]; + char *buf; ssize_t bytes; } wr = {0}, rd = {0}; - int in_flight_requests; + size_t chunk_size; + ssize_t bytes_requested; + int in_flight_requests = 2; + + sftp_limits_t li = NULL; sftp_aio *aio_queue = NULL; int rc, i; - in_flight_requests = 2; + /* Get the max limit for writing, use it as the chunk size */ + li = sftp_limits(t->sftp); + assert_non_null(li); + chunk_size = li->max_write_length; + + rd.buf = calloc(chunk_size, 1); + assert_non_null(rd.buf); + + wr.buf = calloc(chunk_size, 1); + assert_non_null(wr.buf); + aio_queue = malloc(sizeof(sftp_aio) * in_flight_requests); assert_non_null(aio_queue); @@ -214,13 +280,16 @@ static void torture_sftp_aio_write(void **state) assert_int_not_equal(fd, -1); for (i = 0; i < in_flight_requests; ++i) { - rc = sftp_aio_begin_write(file, wr.buf, sizeof(wr.buf), &aio_queue[i]); - assert_int_equal(rc, SSH_OK); + bytes_requested = sftp_aio_begin_write(file, + wr.buf, + chunk_size, + &aio_queue[i]); + assert_int_equal(bytes_requested, chunk_size); } for (i = 0; i < in_flight_requests; ++i) { wr.bytes = sftp_aio_wait_write(&aio_queue[i]); - assert_int_equal(wr.bytes, sizeof(wr.buf)); + assert_int_equal(wr.bytes, chunk_size); /* * Check whether the bytes written to the file @@ -235,64 +304,121 @@ static void torture_sftp_aio_write(void **state) assert_int_equal(rc, 0); } - /* Cleanup */ + /* Clean up */ close(fd); sftp_close(file); free(aio_queue); rc = unlink(file_path); assert_int_equal(rc, 0); + + free(wr.buf); + free(rd.buf); + sftp_limits_free(li); } -static void torture_sftp_aio_negative(void **state) +static void torture_sftp_aio_write_more_than_cap(void **state) { struct torture_state *s = *state; struct torture_sftp *t = s->ssh.tsftp; - char buf[MAX_XFER_BUF_SIZE] = {0}; - sftp_file file = NULL; - char file_path[128] = {0}; - sftp_aio aio = NULL; + sftp_limits_t li = NULL; + char *buf = NULL; + size_t buf_size; - size_t chunk_size = MAX_XFER_BUF_SIZE; - ssize_t bytes_read, bytes_written; + char file_path[128] = {0}; + sftp_file file = NULL; + + sftp_aio aio = NULL; + ssize_t bytes; int rc; + li = sftp_limits(t->sftp); + assert_non_null(li); + + buf_size = li->max_write_length * 2; + buf = calloc(buf_size, 1); + assert_non_null(buf); + + snprintf(file_path, sizeof(file_path), + "%s/libssh_sftp_aio_write_test_cap", t->testdir); + file = sftp_open(t->sftp, file_path, O_CREAT | O_WRONLY, 0777); + assert_non_null(file); + + /* Try writing more than the max limit for writing */ + bytes = sftp_aio_begin_write(file, buf, buf_size, &aio); + assert_int_equal(bytes, li->max_write_length); + + bytes = sftp_aio_wait_write(&aio); + assert_int_equal(bytes, li->max_write_length); + + /* Clean up */ + sftp_close(file); + + rc = unlink(file_path); + assert_int_equal(rc, 0); + + free(buf); + sftp_limits_free(li); +} + +static void torture_sftp_aio_read_negative(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + + char *buf = NULL; + sftp_file file = NULL; + sftp_aio aio = NULL; + sftp_limits_t li = NULL; + + size_t chunk_size; + ssize_t bytes; + int rc; + + li = sftp_limits(t->sftp); + assert_non_null(li); + chunk_size = li->max_read_length; + + buf = calloc(chunk_size, 1); + assert_non_null(buf); + /* Open a file for reading */ file = sftp_open(t->sftp, SSH_EXECUTABLE, O_RDONLY, 0); assert_non_null(file); - /* Negative tests for reading start */ - /* Passing NULL as the sftp file handle */ - rc = sftp_aio_begin_read(NULL, chunk_size, &aio); - assert_int_equal(rc, SSH_ERROR); + bytes = sftp_aio_begin_read(NULL, chunk_size, &aio); + assert_int_equal(bytes, SSH_ERROR); /* Passing 0 as the number of bytes to read */ - rc = sftp_aio_begin_read(file, 0, &aio); - assert_int_equal(rc, SSH_ERROR); + bytes = sftp_aio_begin_read(file, 0, &aio); + assert_int_equal(bytes, SSH_ERROR); - /* Passing NULL instead of a pointer to a location to store an aio handle */ - rc = sftp_aio_begin_read(file, chunk_size, NULL); - assert_int_equal(rc, SSH_ERROR); + /* + * Passing NULL instead of a pointer to a location to + * store an aio handle. + */ + bytes = sftp_aio_begin_read(file, chunk_size, NULL); + assert_int_equal(bytes, SSH_ERROR); /* Passing NULL instead of a pointer to an aio handle */ - bytes_read = sftp_aio_wait_read(NULL, buf, sizeof(buf)); - assert_int_equal(bytes_read, SSH_ERROR); + bytes = sftp_aio_wait_read(NULL, buf, sizeof(buf)); + assert_int_equal(bytes, SSH_ERROR); /* Passing NULL as the buffer's address */ - rc = sftp_aio_begin_read(file, chunk_size, &aio); - assert_int_equal(rc, SSH_OK); + bytes = sftp_aio_begin_read(file, chunk_size, &aio); + assert_int_equal(bytes, chunk_size); - bytes_read = sftp_aio_wait_read(&aio, NULL, sizeof(buf)); - assert_int_equal(bytes_read, SSH_ERROR); + bytes = sftp_aio_wait_read(&aio, NULL, sizeof(buf)); + assert_int_equal(bytes, SSH_ERROR); /* Passing 0 as the buffer size */ - rc = sftp_aio_begin_read(file, chunk_size, &aio); - assert_int_equal(rc, SSH_OK); + bytes = sftp_aio_begin_read(file, chunk_size, &aio); + assert_int_equal(bytes, chunk_size); - bytes_read = sftp_aio_wait_read(&aio, buf, 0); - assert_int_equal(bytes_read, SSH_ERROR); + bytes = sftp_aio_wait_read(&aio, buf, 0); + assert_int_equal(bytes, SSH_ERROR); /* * Test for the scenario when the number @@ -301,62 +427,101 @@ static void torture_sftp_aio_negative(void **state) rc = sftp_seek(file, 0); /* Seek to the start of file */ assert_int_equal(rc, 0); - rc = sftp_aio_begin_read(file, 2, &aio); - assert_int_equal(rc, SSH_OK); + bytes = sftp_aio_begin_read(file, 2, &aio); + assert_int_equal(bytes, 2); - bytes_read = sftp_aio_wait_read(&aio, buf, 1); - assert_int_equal(bytes_read, SSH_ERROR); + bytes = sftp_aio_wait_read(&aio, buf, 1); + assert_int_equal(bytes, SSH_ERROR); sftp_close(file); + free(buf); + sftp_limits_free(li); +} + +static void torture_sftp_aio_write_negative(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + + char *buf = NULL; + + char file_path[128] = {0}; + sftp_file file = NULL; + sftp_aio aio = NULL; + sftp_limits_t li = NULL; + + size_t chunk_size; + ssize_t bytes; + int rc; + + li = sftp_limits(t->sftp); + assert_non_null(li); + chunk_size = li->max_write_length; + + buf = calloc(chunk_size, 1); + assert_non_null(buf); /* Open a file for writing */ snprintf(file_path, sizeof(file_path), - "%s/libssh_sftp_aio_write_test", t->testdir); + "%s/libssh_sftp_aio_write_test_negative", t->testdir); file = sftp_open(t->sftp, file_path, O_CREAT | O_WRONLY, 0777); assert_non_null(file); - /* Negative tests for writing start */ - /* Passing NULL as the sftp file handle */ - rc = sftp_aio_begin_write(NULL, buf, MAX_XFER_BUF_SIZE, &aio); - assert_int_equal(rc, SSH_ERROR); + bytes = sftp_aio_begin_write(NULL, buf, chunk_size, &aio); + assert_int_equal(bytes, SSH_ERROR); /* Passing NULL as the buffer's address */ - rc = sftp_aio_begin_write(file, NULL, MAX_XFER_BUF_SIZE, &aio); - assert_int_equal(rc, SSH_ERROR); + bytes = sftp_aio_begin_write(file, NULL, chunk_size, &aio); + assert_int_equal(bytes, SSH_ERROR); /* Passing 0 as the size of buffer */ - rc = sftp_aio_begin_write(file, buf, 0, &aio); - assert_int_equal(rc, SSH_ERROR); + bytes = sftp_aio_begin_write(file, buf, 0, &aio); + assert_int_equal(bytes, SSH_ERROR); /* Passing NULL instead of a pointer to a location to store an aio handle */ - rc = sftp_aio_begin_write(file, buf, MAX_XFER_BUF_SIZE, NULL); - assert_int_equal(rc, SSH_ERROR); + bytes = sftp_aio_begin_write(file, buf, chunk_size, NULL); + assert_int_equal(bytes, SSH_ERROR); /* Passing NULL instead of a pointer to an aio handle */ - bytes_written = sftp_aio_wait_write(NULL); - assert_int_equal(bytes_written, SSH_ERROR); + bytes = sftp_aio_wait_write(NULL); + assert_int_equal(bytes, SSH_ERROR); sftp_close(file); rc = unlink(file_path); assert_int_equal(rc, 0); + + free(buf); + sftp_limits_free(li); } int torture_run_tests(void) { int rc; struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(torture_sftp_aio_read, + cmocka_unit_test_setup_teardown(torture_sftp_aio_read_file, session_setup, session_teardown), - cmocka_unit_test_setup_teardown(torture_sftp_aio_write, + cmocka_unit_test_setup_teardown(torture_sftp_aio_read_more_than_cap, session_setup, session_teardown), - cmocka_unit_test_setup_teardown(torture_sftp_aio_negative, + cmocka_unit_test_setup_teardown(torture_sftp_aio_write_file, session_setup, - session_teardown) + session_teardown), + + cmocka_unit_test_setup_teardown(torture_sftp_aio_write_more_than_cap, + session_setup, + session_teardown), + + cmocka_unit_test_setup_teardown(torture_sftp_aio_read_negative, + session_setup, + session_teardown), + + cmocka_unit_test_setup_teardown(torture_sftp_aio_write_negative, + session_setup, + session_teardown), }; ssh_init();