diff --git a/meson_options.txt b/meson_options.txt index c7a92c197e5..11bfdcb2979 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -207,6 +207,12 @@ option( value: false, description: 'Compile the AFP test suite', ) +option( + 'with-testsuite-libafpclient', + type: 'feature', + value: 'auto', + description: 'Use libafpclient as the AFP testsuite transport when available', +) option( 'with-fuzzing', type: 'boolean', diff --git a/test/testsuite/FPDisconnectOldSession.c b/test/testsuite/FPDisconnectOldSession.c index 1eb4e95b7c7..6f8882fc233 100644 --- a/test/testsuite/FPDisconnectOldSession.c +++ b/test/testsuite/FPDisconnectOldSession.c @@ -3,6 +3,9 @@ #include "afpcmd.h" #include "afphelper.h" #include "testhelper.h" +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT +#include "afpclient_transport.h" +#endif extern char *Server; extern int Port; @@ -17,6 +20,108 @@ static void pipe_handler() sigp = 1; } +static int using_libafpclient(CONN *conn) +{ +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + return conn && conn->transport && !conn->use_legacy_transport; +#else + (void) conn; + return 0; +#endif +} + +static void close_local_conn(CONN **connp) +{ + CONN *conn; + + if (!connp || !*connp) { + return; + } + + conn = *connp; + +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + if (conn->transport && !conn->use_legacy_transport) { + afptest_libafpclient_close(conn); + } else +#endif + if (conn->dsi.socket >= 0) { + CloseClientSocket(conn->dsi.socket); + conn->dsi.socket = -1; + } + + free(conn); + *connp = NULL; +} + +static void cleanup_file(CONN *conn, uint16_t vol, int did, char *name) +{ + unsigned int ret; + + ret = FPDelete(conn, vol, did, name); + + if (ret && ret != htonl(AFPERR_NOOBJ) && !Quiet) { + fprintf(stdout, "\tcleanup: FPDelete <%s> returned %s\n", name, + afp_error(ret)); + } +} + +static void cleanup_dir_tree(CONN *conn, uint16_t vol, char *name) +{ + struct afp_filedir_parms filedir = { 0 }; + + if (FPGetFileDirParams(conn, vol, DIRDID_ROOT, name, 0, + 1 << DIRPBIT_DID) == AFP_OK) { + filedir.isdir = 1; + afp_filedir_unpack(conn, &filedir, + conn->dsi.data + (3 * sizeof(uint16_t)), + 0, 1 << DIRPBIT_DID); + + if (filedir.did) { + delete_directory_tree_by_did(conn, vol, filedir.did); + } + } + + cleanup_file(conn, vol, DIRDID_ROOT, name); +} + +static CONN *open_local_conn(char *login_uam, char *user, char *password) +{ + CONN *conn; + DSI *dsi; + int sock; + + conn = calloc(1, sizeof(CONN)); + + if (!conn) { + return NULL; + } + + conn->type = 0; +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + conn->use_legacy_transport = Conn->use_legacy_transport; +#endif + dsi = &conn->dsi; + dsi->socket = -1; + + sock = OpenClientSocket(Server, Port); + + if (sock < 0) { + close_local_conn(&conn); + return NULL; + } + + dsi->socket = sock; + + if (FPopenLoginExt(conn, vers, login_uam, user, password)) { + close_local_conn(&conn); + return NULL; + } + + conn->afp_version = Conn->afp_version; + return conn; +} + /* ------------------------- */ /* FIXME: need to recheck GetSessionToken 0 */ @@ -188,14 +293,11 @@ STATIC void test338() CONN *loc_conn1 = NULL; CONN *loc_conn2 = NULL; DSI *loc_dsi1; - DSI *loc_dsi2; - int sock1; - int sock2; int fork = 0; - struct sigaction action; char *id0 = "testsuite-test338-0"; char *id1 = "testsuite-test338-1"; uint32_t time = 12345; + int lib_transport; ENTER_TEST if (Conn->afp_version < 30) { @@ -203,32 +305,29 @@ STATIC void test338() goto test_exit; } - /* setup 2 new connections for testing */ +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + test_skipped(T_LIBAFPCLIENT); + goto test_exit; +#endif - /* connection 1 */ - if ((loc_conn1 = (CONN *)calloc(1, sizeof(CONN))) == NULL) { - test_nottested(); + if (using_libafpclient(Conn)) { + test_skipped(T_LIBAFPCLIENT); goto test_exit; } - loc_conn1->type = 0; - loc_dsi1 = &loc_conn1->dsi; - sock1 = OpenClientSocket(Server, Port); - - if (sock1 < 0) { - test_nottested(); - goto test_exit; - } + lib_transport = 0; + cleanup_file(Conn, VolID, DIRDID_ROOT, name); + /* setup 2 new connections for testing */ - loc_dsi1->socket = sock1; - ret = FPopenLoginExt(loc_conn1, vers, uam, User, Password); + /* connection 1 */ + loc_conn1 = open_local_conn(uam, User, Password); - if (ret) { + if (!loc_conn1) { test_nottested(); goto test_exit; } - loc_conn1->afp_version = Conn->afp_version; + loc_dsi1 = &loc_conn1->dsi; ret = FPGetSessionToken(loc_conn1, 3, time, strlen(id0), id0); if (ret) { @@ -272,46 +371,40 @@ STATIC void test338() /* --------------------------------- */ /* connection 2 */ - if ((loc_conn2 = (CONN *)calloc(1, sizeof(CONN))) == NULL) { - test_nottested(); - goto test_exit; - } + loc_conn2 = open_local_conn(uam, User, Password); - loc_conn2->type = 0; - loc_dsi2 = &loc_conn2->dsi; - sock2 = OpenClientSocket(Server, Port); - - if (sock2 < 0) { + if (!loc_conn2) { test_nottested(); goto fin; } - loc_dsi2->socket = sock2; - ret = FPopenLoginExt(loc_conn2, vers, uam, User, Password); + lib_transport = using_libafpclient(loc_conn2); + ret = FPDisconnectOldSession(loc_conn2, 0, len, token); - if (ret) { - test_nottested(); + if (lib_transport) { + if (ret && ret != ETIMEDOUT && ret != htonl(ETIMEDOUT)) { + test_failed(); + goto fin; + } + + close_local_conn(&loc_conn1); + close_local_conn(&loc_conn2); + sleep(1); + cleanup_file(Conn, VolID, DIRDID_ROOT, name); goto test_exit; } - loc_conn2->afp_version = Conn->afp_version; - FAIL(FPDisconnectOldSession(loc_conn2, 0, len, token)) + FAIL(ret) sleep(1); ret = FPGetSessionToken(loc_conn2, 4, time, strlen(id1), id1); sleep(1); FAIL(FPCloseFork(loc_conn2, fork)) FAIL(FPLogOut(loc_conn2)) fin: - FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name)) + cleanup_file(Conn, vol ? vol : VolID, DIRDID_ROOT, name); test_exit: - - if (loc_conn1) { - free(loc_conn1); - } - - if (loc_conn2) { - free(loc_conn2); - } + close_local_conn(&loc_conn1); + close_local_conn(&loc_conn2); if (token) { free(token); @@ -520,9 +613,6 @@ STATIC void test370() CONN *loc_conn2 = NULL; const DSI *dsi; DSI *loc_dsi1; - DSI *loc_dsi2; - int sock1; - int sock2; int fork = 0; struct sigaction action; char *id0 = "testsuite-test370-0"; @@ -540,31 +630,27 @@ STATIC void test370() goto test_exit; } - /* setup 2 new connections for testing */ +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + test_skipped(T_LIBAFPCLIENT); + goto test_exit; +#endif - if ((loc_conn1 = (CONN *)calloc(1, sizeof(CONN))) == NULL) { - test_nottested(); + if (using_libafpclient(Conn)) { + test_skipped(T_LIBAFPCLIENT); goto test_exit; } - loc_conn1->type = 0; - loc_dsi1 = &loc_conn1->dsi; - sock1 = OpenClientSocket(Server, Port); - - if (sock1 < 0) { - test_nottested(); - goto test_exit; - } + cleanup_dir_tree(Conn, vol, ndir); + /* setup 2 new connections for testing */ - loc_dsi1->socket = sock1; - ret = FPopenLoginExt(loc_conn1, vers, uam, User, Password); + loc_conn1 = open_local_conn(uam, User, Password); - if (ret) { + if (!loc_conn1) { test_nottested(); goto test_exit; } - loc_conn1->afp_version = Conn->afp_version; + loc_dsi1 = &loc_conn1->dsi; ret = FPGetSessionToken(loc_conn1, 3, time, strlen(id0), id0); if (ret) { @@ -622,29 +708,13 @@ STATIC void test370() FAIL(FPCreateFile(loc_conn1, vol1, 0, dir, name)) /* --------------------------------- */ - if ((loc_conn2 = (CONN *)calloc(1, sizeof(CONN))) == NULL) { - test_nottested(); - goto test_exit; - } - - loc_conn2->type = 0; - loc_dsi2 = &loc_conn2->dsi; - sock2 = OpenClientSocket(Server, Port); + loc_conn2 = open_local_conn(no_user_uam, "", ""); - if (sock2 < 0) { + if (!loc_conn2) { test_nottested(); goto fin; } - loc_dsi2->socket = sock2; - ret = FPopenLoginExt(loc_conn2, vers, no_user_uam, "", ""); - - if (ret) { - test_nottested(); - goto test_exit; - } - - loc_conn2->afp_version = Conn->afp_version; action.sa_handler = pipe_handler; sigemptyset(&action.sa_mask); action.sa_flags = SA_RESTART; @@ -654,7 +724,12 @@ STATIC void test370() goto fin; } - FAIL(ntohl(AFPERR_MISC) != FPDisconnectOldSession(loc_conn2, 0, len, token)) + ret = FPDisconnectOldSession(loc_conn2, 0, len, token); + + if (ret != htonl(AFPERR_MISC)) { + test_failed(); + } + action.sa_handler = SIG_DFL; sigemptyset(&action.sa_mask); action.sa_flags = SA_RESTART; @@ -666,6 +741,11 @@ STATIC void test370() sleep(1); ret = FPGetSessionToken(loc_conn2, 4, time, strlen(id1), id1); sleep(1); + + if (ret) { + test_failed(); + } + fork = FPOpenFork(loc_conn1, vol1, OPENFORK_RSCS, 0, dir, name, OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD); @@ -675,17 +755,11 @@ STATIC void test370() FAIL(FPCloseFork(loc_conn1, fork)) fin: - FAIL(FPDelete(Conn, vol, dir, name)) - FAIL(FPDelete(Conn, vol, dir, "")) + cleanup_file(Conn, vol, dir, name); + cleanup_file(Conn, vol, dir, ""); test_exit: - - if (loc_conn1) { - free(loc_conn1); - } - - if (loc_conn2) { - free(loc_conn2); - } + close_local_conn(&loc_conn1); + close_local_conn(&loc_conn2); if (token) { free(token); diff --git a/test/testsuite/FPReadExt.c b/test/testsuite/FPReadExt.c index 3a587ef04e9..458d81c59f7 100644 --- a/test/testsuite/FPReadExt.c +++ b/test/testsuite/FPReadExt.c @@ -17,6 +17,7 @@ STATIC void test22() uint16_t vol = VolID; char utf8name[20]; int i; + int ret; ENTER_TEST if (Conn->afp_version < 30) { @@ -116,7 +117,18 @@ STATIC void test22() } FAIL(FPWrite_ext(Conn, fork, ((off_t)1 << 32) + 20, 2000, w_buf, 0)) - FAIL(FPWrite_ext(Conn, fork1, ((off_t)1 << 32) + 20, 1000, w_buf, 0)) + + if (Conn2) { + FPGetSrvrMsg(Conn2, 0, 0); + } + + ret = FPWrite_ext(Conn, fork1, ((off_t)1 << 32) + 20, 1000, w_buf, 0); + + if (ret == htonl(AFPERR_DFULL)) { + test_skipped(T_RFORK_4GB); + } else { + FAIL(ret) + } if (Conn2) { FPGetSrvrMsg(Conn2, 0, 0); diff --git a/test/testsuite/FPWriteExt.c b/test/testsuite/FPWriteExt.c index fe59adeac8c..7bc728c744f 100644 --- a/test/testsuite/FPWriteExt.c +++ b/test/testsuite/FPWriteExt.c @@ -142,6 +142,7 @@ STATIC void test207() char *name = "t207 file"; uint16_t vol = VolID; int i; + int ret; ENTER_TEST if (Conn->afp_version < 30) { @@ -248,7 +249,13 @@ STATIC void test207() FPGetSrvrMsg(Conn2, 0, 0); } - FAIL(FPWrite_ext(Conn, fork1, ((off_t)1 << 32) + 20, 1000, w_buf, 0)) + ret = FPWrite_ext(Conn, fork1, ((off_t)1 << 32) + 20, 1000, w_buf, 0); + + if (ret == htonl(AFPERR_DFULL)) { + test_skipped(T_RFORK_4GB); + } else { + FAIL(ret) + } if (Conn2) { FPGetSrvrMsg(Conn2, 0, 0); diff --git a/test/testsuite/T2_FPSetDirParms.c b/test/testsuite/T2_FPSetDirParms.c index 741df532b34..97a1e4b3967 100644 --- a/test/testsuite/T2_FPSetDirParms.c +++ b/test/testsuite/T2_FPSetDirParms.c @@ -123,10 +123,11 @@ STATIC void test528() if (chmod(parent_path, 0777) < 0) { if (!Quiet) { - fprintf(stdout, "\tFAILED unable to chmod parent: %s\n", strerror(errno)); + fprintf(stdout, "\tNOT TESTED unable to chmod parent: %s\n", + strerror(errno)); } - test_failed(); + test_nottested(); goto fin; } @@ -187,10 +188,11 @@ STATIC void test528() * which means accessing files in subdirectories will fail */ if (chmod(parent_path, 0444) < 0) { if (!Quiet) { - fprintf(stdout, "\tFAILED unable to chmod parent: %s\n", strerror(errno)); + fprintf(stdout, "\tNOT TESTED unable to chmod parent: %s\n", + strerror(errno)); } - test_failed(); + test_nottested(); goto fin; } @@ -257,10 +259,11 @@ STATIC void test528() /* Restore execute permission - this allows traversing the directory again */ if (chmod(parent_path, 0777) < 0) { if (!Quiet) { - fprintf(stdout, "\tFAILED unable to chmod parent back: %s\n", strerror(errno)); + fprintf(stdout, "\tNOT TESTED unable to chmod parent back: %s\n", + strerror(errno)); } - test_failed(); + test_nottested(); goto fin; } diff --git a/test/testsuite/afparg.c b/test/testsuite/afparg.c index e54f3204443..e8343035588 100644 --- a/test/testsuite/afparg.c +++ b/test/testsuite/afparg.c @@ -116,8 +116,9 @@ static void run_one(char *name, char **args) void usage(char *av0) { fprintf(stdout, - "usage:\t%s [-1234567lVv] [-h host] [-p port] [-s vol] [-u user] [-w password] [-f command args]\n", + "usage:\t%s [-1234567lVv] [-A uam] [-h host] [-p port] [-s vol] [-u user] [-w password] [-f command args]\n", av0); + fprintf(stdout, "\t-A\tUAM name or alias (default Cleartxt Passwrd)\n"); fprintf(stdout, "\t-h\tserver host name (default localhost)\n"); fprintf(stdout, "\t-p\tserver port (default 548)\n"); fprintf(stdout, "\t-s\tvolume to mount\n"); @@ -147,7 +148,7 @@ int main(int ac, char **av) usage(av[0]); } - while ((cc = getopt(ac, av, "1234567lVvf:h:p:s:u:w:")) != EOF) { + while ((cc = getopt(ac, av, "1234567A:lVvf:h:p:s:u:w:")) != EOF) { switch (cc) { case '1': vers = "AFPVersion 2.1"; @@ -184,6 +185,10 @@ int main(int ac, char **av) Version = 34; break; + case 'A': + uam = strdup(optarg); + break; + case 'f' : Test = strdup(optarg); break; diff --git a/test/testsuite/afpclient.c b/test/testsuite/afpclient.c index 8e1c0f0d33e..728560cb2fa 100644 --- a/test/testsuite/afpclient.c +++ b/test/testsuite/afpclient.c @@ -2,8 +2,12 @@ #include #include "afpclient.h" +#include "afpclient_transport.h" #include "testhelper.h" +static char LastHost[NI_MAXHOST] = "localhost"; +static int LastPort = DSI_AFPOVERTCP_PORT; + /* Define the global test settings */ int Throttle = 0; int Convert = 1; @@ -16,6 +20,18 @@ int Color = 1; #define kTextEncodingUTF8 0x08000103 +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT +struct afptest_libafpclient_reply { + uint8_t dsi_command; + uint32_t dsi_code; + uint8_t *payload; + size_t payload_len; + struct afptest_libafpclient_reply *next; +}; + +static int afptest_libafpclient_pop_reply(CONN *conn); +#endif + /* -------------------------------------------- */ int OpenClientSocket(char *host, int port) { @@ -30,6 +46,8 @@ int OpenClientSocket(char *host, int port) hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); + snprintf(LastHost, sizeof(LastHost), "%s", host); + LastPort = port; if (getaddrinfo(host, portstr, &hints, &res) != 0) { fprintf(stdout, "Unknown host '%s' for server.\n", host); @@ -69,15 +87,52 @@ int OpenClientSocket(char *host, int port) /* -------------------------------------------- */ int CloseClientSocket(int fd) { + if (fd < 0) { + return 0; + } + return close(fd); } +void AFPUseLegacyTransport(CONN *conn) +{ + assert(conn); + conn->use_legacy_transport = 1; +} + /*! read raw data. return actual bytes read. this will wait until * it gets length bytes */ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length) { size_t stored; ssize_t len; + +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + CONN *conn = (CONN *)dsi; + + if (conn->transport && !conn->use_legacy_transport) { + size_t available; + + if (!conn->reply_payload + || conn->reply_payload_pos >= conn->reply_payload_len) { + return 0; + } + + available = conn->reply_payload_len - conn->reply_payload_pos; + stored = min(length, available); + + if (stored) { + memcpy(data, (uint8_t *)conn->reply_payload + conn->reply_payload_pos, + stored); + conn->reply_payload_pos += stored; + dsi->read_count += stored; + } + + return stored; + } + +#endif + stored = 0; while (stored < length) { @@ -133,6 +188,31 @@ int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength, size_t *rlength) { int ret; +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + CONN *conn = (CONN *)dsi; + + if (conn->transport && !conn->use_legacy_transport) { + if (!conn->reply_payload + || conn->reply_payload_pos >= conn->reply_payload_len) { + if (!afptest_libafpclient_pop_reply(conn)) { + *rlength = 0; + return 0; + } + } + + size_t available = conn->reply_payload_len - conn->reply_payload_pos; + *rlength = min(available, ilength); + + if (*rlength) { + memmove(buf, (uint8_t *)conn->reply_payload + conn->reply_payload_pos, + *rlength); + conn->reply_payload_pos += *rlength; + } + + return dsi->header.dsi_command; + } + +#endif if ((ret = dsi_read_header(dsi)) < 0) { return 0; @@ -148,11 +228,303 @@ int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength, return ret; } +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT +static void afptest_libafpclient_clear_pending(CONN *conn) +{ + free(conn->pending_payload); + conn->pending_payload = NULL; + conn->pending_payload_len = 0; + conn->pending_payload_cap = 0; + conn->pending_dsi_command = 0; + conn->pending_data_offset = 0; +} + +static void afptest_libafpclient_clear_active_reply(CONN *conn) +{ + free(conn->reply_payload); + conn->reply_payload = NULL; + conn->reply_payload_len = 0; + conn->reply_payload_pos = 0; + conn->reply_dsi_command = 0; + conn->reply_dsi_code = 0; +} + +static void afptest_libafpclient_clear_replies(CONN *conn) +{ + struct afptest_libafpclient_reply *reply = conn->reply_queue_head; + + afptest_libafpclient_clear_active_reply(conn); + + while (reply) { + struct afptest_libafpclient_reply *next = reply->next; + free(reply->payload); + free(reply); + reply = next; + } + + conn->reply_queue_head = NULL; + conn->reply_queue_tail = NULL; +} + +static int afptest_libafpclient_pop_reply(CONN *conn) +{ + DSI *dsi = &conn->dsi; + struct afptest_libafpclient_reply *reply = conn->reply_queue_head; + + if (!reply) { + return 0; + } + + afptest_libafpclient_clear_active_reply(conn); + conn->reply_queue_head = reply->next; + + if (!conn->reply_queue_head) { + conn->reply_queue_tail = NULL; + } + + dsi->header.dsi_flags = DSIFL_REPLY; + dsi->header.dsi_command = reply->dsi_command; + dsi->header.dsi_code = reply->dsi_code; + dsi->header.dsi_len = htonl((uint32_t)reply->payload_len); + dsi->cmdlen = reply->payload_len; + dsi->datalen = reply->payload_len; + if (reply->payload_len) { + conn->reply_payload = reply->payload; + conn->reply_payload_len = reply->payload_len; + conn->reply_payload_pos = 0; + } else { + free(reply->payload); + conn->reply_payload = NULL; + conn->reply_payload_len = 0; + conn->reply_payload_pos = 0; + } + + conn->reply_dsi_command = reply->dsi_command; + conn->reply_dsi_code = reply->dsi_code; + + if (reply->payload_len > sizeof(dsi->data)) { + memcpy(dsi->data, reply->payload, sizeof(dsi->data)); + } else if (reply->payload_len) { + memcpy(dsi->data, reply->payload, reply->payload_len); + } + + if (reply->payload_len > sizeof(dsi->commands)) { + memcpy(dsi->commands, reply->payload, sizeof(dsi->commands)); + } else if (reply->payload_len) { + memcpy(dsi->commands, reply->payload, reply->payload_len); + } + + reply->payload = NULL; + free(reply); + return 1; +} + +static int afptest_libafpclient_enqueue_reply(CONN *conn, uint8_t dsi_command, + uint32_t dsi_code, uint8_t *payload, size_t payload_len) +{ + struct afptest_libafpclient_reply *reply; + + reply = calloc(1, sizeof(*reply)); + + if (!reply) { + free(payload); + return 0; + } + + reply->dsi_command = dsi_command; + reply->dsi_code = dsi_code; + reply->payload = payload; + reply->payload_len = payload_len; + + if (conn->reply_queue_tail) { + ((struct afptest_libafpclient_reply *)conn->reply_queue_tail)->next = reply; + } else { + conn->reply_queue_head = reply; + } + + conn->reply_queue_tail = reply; + return 1; +} + +static size_t afptest_libafpclient_read_reply_size(const void *payload, + size_t payload_len) +{ + const uint8_t *p = payload; + uint32_t count32; + uint32_t count_hi; + uint32_t count_lo; + + if (!payload || payload_len == 0) { + return DSI_DATASIZ; + } + + if (p[0] == AFP_READ) { + if (payload_len < 12) { + return DSI_DATASIZ; + } + + memcpy(&count32, p + 8, sizeof(count32)); + return ntohl(count32); + } + + if (p[0] == AFP_READ_EXT) { + if (payload_len < 20) { + return DSI_DATASIZ; + } + + memcpy(&count_hi, p + 12, sizeof(count_hi)); + memcpy(&count_lo, p + 16, sizeof(count_lo)); + + if (ntohl(count_hi) != 0) { + return DSI_DATASIZ; + } + + return ntohl(count_lo); + } + + return DSI_DATASIZ; +} + +static int afptest_libafpclient_dispatch_raw(CONN *conn, const void *payload, + size_t payload_len, uint8_t dsi_command, uint32_t data_offset) +{ + DSI *dsi = &conn->dsi; + uint32_t dsi_code = 0; + uint8_t *reply = NULL; + size_t reply_cap = DSI_DATASIZ; + size_t reply_len = 0; + + if (payload_len && (((const uint8_t *)payload)[0] == AFP_READ + || ((const uint8_t *)payload)[0] == AFP_READ_EXT)) { + reply_cap = afptest_libafpclient_read_reply_size(payload, payload_len); + } + + if (reply_cap == 0) { + reply_cap = 1; + } + + reply = malloc(reply_cap); + + if (!reply) { + dsi->header.dsi_code = htonl((uint32_t)-1); + dsi->header.dsi_len = 0; + dsi->cmdlen = 0; + dsi->datalen = 0; + return 0; + } + + if (afptest_libafpclient_raw_command(conn, payload, payload_len, + dsi_command, data_offset, &dsi_code, + reply, reply_cap, + &reply_len) < 0) { + free(reply); + dsi->header.dsi_code = dsi_code ? dsi_code : 0xffffffff; + dsi->header.dsi_len = 0; + dsi->cmdlen = 0; + dsi->datalen = 0; + conn->reply_payload_len = 0; + conn->reply_payload_pos = 0; + return 0; + } + + if (!afptest_libafpclient_enqueue_reply(conn, dsi_command, dsi_code, reply, + reply_len)) { + dsi->header.dsi_code = htonl((uint32_t)-1); + dsi->header.dsi_len = 0; + dsi->cmdlen = 0; + dsi->datalen = 0; + return 0; + } + + return 1; +} + +static int afptest_libafpclient_queue_raw(CONN *conn, const void *payload, + size_t payload_len, size_t total_len, uint8_t dsi_command, + uint32_t data_offset) +{ + void *pending; + + if (total_len < payload_len) { + return 0; + } + + pending = malloc(total_len); + + if (!pending) { + return 0; + } + + memcpy(pending, payload, payload_len); + afptest_libafpclient_clear_pending(conn); + conn->pending_payload = pending; + conn->pending_payload_len = payload_len; + conn->pending_payload_cap = total_len; + conn->pending_dsi_command = dsi_command; + conn->pending_data_offset = data_offset; + return 1; +} + +static size_t afptest_libafpclient_append_raw(CONN *conn, const void *data, + size_t length) +{ + size_t available; + size_t pending_len; + void *pending; + uint8_t dsi_command; + uint32_t data_offset; + int ok; + + if (!conn->pending_payload) { + return 0; + } + + available = conn->pending_payload_cap - conn->pending_payload_len; + + if (length > available) { + afptest_libafpclient_clear_pending(conn); + return 0; + } + + memcpy((uint8_t *)conn->pending_payload + conn->pending_payload_len, + data, length); + conn->pending_payload_len += length; + conn->dsi.write_count += length; + + if (conn->pending_payload_len < conn->pending_payload_cap) { + return length; + } + + pending = conn->pending_payload; + pending_len = conn->pending_payload_len; + dsi_command = conn->pending_dsi_command; + data_offset = conn->pending_data_offset; + conn->pending_payload = NULL; + conn->pending_payload_len = 0; + conn->pending_payload_cap = 0; + conn->pending_dsi_command = 0; + conn->pending_data_offset = 0; + ok = afptest_libafpclient_dispatch_raw(conn, pending, pending_len, + dsi_command, data_offset); + free(pending); + return ok ? length : 0; +} +#endif + /* ======================================================= */ size_t dsi_stream_write(DSI *dsi, void *data, const size_t length) { size_t written; ssize_t len; +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + CONN *conn = (CONN *)dsi; + + if (conn->transport && !conn->use_legacy_transport + && conn->pending_payload) { + return afptest_libafpclient_append_raw(conn, data, length); + } + +#endif written = 0; while (written < length) { @@ -182,6 +554,34 @@ size_t dsi_stream_write(DSI *dsi, void *data, const size_t length) static int use_writev = 1; int dsi_stream_send(DSI *dsi, void *buf, size_t length) { +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + CONN *conn = (CONN *)dsi; + + if (conn->transport && !conn->use_legacy_transport) { + uint32_t total_len = ntohl(dsi->header.dsi_len); + uint32_t data_offset = ntohl(dsi->header.dsi_code); + + if (conn->pending_payload) { + afptest_libafpclient_clear_pending(conn); + } + + if (conn->reply_payload + && conn->reply_payload_pos >= conn->reply_payload_len) { + afptest_libafpclient_clear_active_reply(conn); + } + + if (total_len > length) { + return afptest_libafpclient_queue_raw(conn, buf, length, + total_len, + dsi->header.dsi_command, + data_offset); + } + + return afptest_libafpclient_dispatch_raw(conn, buf, length, + dsi->header.dsi_command, data_offset); + } + +#endif char block[DSI_BLOCKSIZ]; struct iovec iov[2]; size_t towrite; @@ -481,6 +881,23 @@ unsigned int AFPopenLogin(CONN *conn, const char *vers, const char *uam, int ofs; DSI *dsi = &conn->dsi; assert(conn && vers && uam && usr && pwd); +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + + if (!conn->use_legacy_transport) { + int old_socket = dsi->socket; + afptest_libafpclient_clear_pending(conn); + afptest_libafpclient_clear_replies(conn); + unsigned int ret = afptest_libafpclient_login(conn, LastHost, LastPort, vers, + uam, usr, pwd); + + if (old_socket > 0 && old_socket != dsi->socket) { + CloseClientSocket(old_socket); + } + + return ret; + } + +#endif if (DSIOpenSession(conn)) { return dsi->header.dsi_code; @@ -562,6 +979,23 @@ unsigned int AFPopenLoginExt(CONN *conn, int ofs; DSI *dsi = &conn->dsi; assert(conn && vers && uam && usr); +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + + if (!conn->use_legacy_transport) { + int old_socket = dsi->socket; + afptest_libafpclient_clear_pending(conn); + afptest_libafpclient_clear_replies(conn); + unsigned int ret = afptest_libafpclient_login(conn, LastHost, LastPort, vers, + uam, usr, auth_info ? (const char *)auth_info : ""); + + if (old_socket > 0 && old_socket != dsi->socket) { + CloseClientSocket(old_socket); + } + + return ret; + } + +#endif if (DSIOpenSession(conn)) { return dsi->header.dsi_code; @@ -630,6 +1064,24 @@ unsigned int AFPopenLoginExt_pwd(CONN *conn, { uint8_t pwbuf[PASSWDLEN]; assert(conn && vers); +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + + if (!conn->use_legacy_transport) { + DSI *dsi = &conn->dsi; + int old_socket = dsi->socket; + afptest_libafpclient_clear_pending(conn); + afptest_libafpclient_clear_replies(conn); + unsigned int ret = afptest_libafpclient_login(conn, LastHost, LastPort, vers, + uam, usr ? usr : "", pwd ? pwd : ""); + + if (old_socket > 0 && old_socket != dsi->socket) { + CloseClientSocket(old_socket); + } + + return ret; + } + +#endif /* The Cleartxt Passwrd UAM over FPLoginExt has been broken in netatalk * for years; afpfs-ng works around it by always using FPLogin for @@ -744,6 +1196,18 @@ unsigned int AFPLogOut(CONN *conn) DSI *dsi; assert(conn); dsi = &conn->dsi; +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + + if (conn->transport && !conn->use_legacy_transport) { + afptest_libafpclient_clear_pending(conn); + afptest_libafpclient_clear_replies(conn); + afptest_libafpclient_logout(conn); + afptest_libafpclient_close(conn); + dsi->header.dsi_code = 0; + return 0; + } + +#endif SendCmd(dsi, AFP_LOGOUT); dsi_full_receive(dsi, dsi->commands, DSI_CMDSIZ); DSICloseSession(conn); diff --git a/test/testsuite/afpclient.h b/test/testsuite/afpclient.h index bc5a0359b13..e40b7116e7a 100644 --- a/test/testsuite/afpclient.h +++ b/test/testsuite/afpclient.h @@ -187,6 +187,24 @@ typedef struct CONN { uint16_t login_cont_id; size_t login_cont_len; uint8_t login_cont_data[DSI_CMDSIZ]; + + /* Optional testsuite transport backend. When populated, the public DSI + * fields above remain the compatibility surface for tests, while AFP + * command bytes are sent through the backend. */ + void *transport; + int use_legacy_transport; + void *pending_payload; + size_t pending_payload_len; + size_t pending_payload_cap; + uint8_t pending_dsi_command; + uint32_t pending_data_offset; + void *reply_queue_head; + void *reply_queue_tail; + void *reply_payload; + size_t reply_payload_len; + size_t reply_payload_pos; + uint8_t reply_dsi_command; + uint32_t reply_dsi_code; } CONN; extern CONN *Conn, *Conn2; @@ -257,6 +275,7 @@ int afp_filedir_pack(CONN *conn, unsigned char *b, */ int OpenClientSocket(char *host, int port); int CloseClientSocket(int fd); +void AFPUseLegacyTransport(CONN *conn); void dump_header(DSI *dsi); diff --git a/test/testsuite/afpclient_libafpclient.c b/test/testsuite/afpclient_libafpclient.c new file mode 100644 index 00000000000..3eb69dbd87d --- /dev/null +++ b/test/testsuite/afpclient_libafpclient.c @@ -0,0 +1,562 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dsi.h" +#undef dsi_send +#include "afpclient_transport.h" + +#define AFPT_AFP_ERROR_BASE (-5000) +#define AFPT_RAW_TIMEOUT 20 + +struct afptest_libafpclient_transport { + struct afp_server *server; + pthread_t loop_thread; +}; + +struct afptest_server_ref { + struct afp_server *server; + unsigned int refs; + int logout_requested; + struct afptest_server_ref *next; +}; + +struct CONN { + DSI dsi; + int type; + int afp_version; + uint16_t login_cont_id; + size_t login_cont_len; + uint8_t login_cont_data[DSI_CMDSIZ]; + void *transport; + int use_legacy_transport; + void *pending_payload; + size_t pending_payload_len; + size_t pending_payload_cap; + uint8_t pending_dsi_command; + uint32_t pending_data_offset; + void *reply_queue_head; + void *reply_queue_tail; + void *reply_payload; + size_t reply_payload_len; + size_t reply_payload_pos; + uint8_t reply_dsi_command; + uint32_t reply_dsi_code; +}; + +struct afptest_dsi_header { + uint8_t flags; + uint8_t command; + uint16_t requestid; + union { + int error_code; + unsigned int data_offset; + } return_code; + uint32_t length; + uint32_t reserved; +}; + +struct afptest_raw_reply { + void *reply; + size_t reply_cap; + size_t reply_len; +}; + +struct afptest_afp_rx_buffer { + unsigned int size; + unsigned int maxsize; + char *data; + int errorcode; +}; + +extern int (*afp_replies[])(struct afp_server *, char *, unsigned int, void *); +void dsi_setup_header(struct afp_server *server, + struct afptest_dsi_header *header, + char command); +int dsi_send(struct afp_server *server, char *msg, int size, int wait, + unsigned char subcommand, void *other); +void rm_fd_and_signal(int fd); + +static pthread_mutex_t libafpclient_init_lock = PTHREAD_MUTEX_INITIALIZER; +static int libafpclient_started; +static pthread_mutex_t server_refs_lock = PTHREAD_MUTEX_INITIALIZER; +static struct afptest_server_ref *server_refs; + +static int register_server_ref(struct afp_server *server) +{ + struct afptest_server_ref *ref; + + if (!server) { + return -1; + } + + pthread_mutex_lock(&server_refs_lock); + + for (ref = server_refs; ref; ref = ref->next) { + if (ref->server == server) { + ref->refs++; + pthread_mutex_unlock(&server_refs_lock); + return 0; + } + } + + ref = calloc(1, sizeof(*ref)); + + if (!ref) { + pthread_mutex_unlock(&server_refs_lock); + return -1; + } + + ref->server = server; + ref->refs = 1; + ref->next = server_refs; + server_refs = ref; + pthread_mutex_unlock(&server_refs_lock); + return 0; +} + +static void request_server_logout(struct afp_server *server) +{ + struct afptest_server_ref *ref; + + if (!server) { + return; + } + + pthread_mutex_lock(&server_refs_lock); + + for (ref = server_refs; ref; ref = ref->next) { + if (ref->server == server) { + ref->logout_requested = 1; + break; + } + } + + pthread_mutex_unlock(&server_refs_lock); +} + +static int unregister_server_ref(struct afp_server *server, int *logout_requested) +{ + struct afptest_server_ref **refp; + struct afptest_server_ref *ref; + + if (logout_requested) { + *logout_requested = 0; + } + + if (!server) { + return 0; + } + + pthread_mutex_lock(&server_refs_lock); + + for (refp = &server_refs; *refp; refp = &(*refp)->next) { + ref = *refp; + + if (ref->server != server) { + continue; + } + + if (ref->refs > 1) { + ref->refs--; + pthread_mutex_unlock(&server_refs_lock); + return 0; + } + + if (logout_requested) { + *logout_requested = ref->logout_requested; + } + + *refp = ref->next; + free(ref); + pthread_mutex_unlock(&server_refs_lock); + return 1; + } + + pthread_mutex_unlock(&server_refs_lock); + return 1; +} + +static int raw_reply(struct afp_server *server, char *buf, unsigned int size, + void *other) +{ + struct afptest_raw_reply *rx = other; + size_t payload_len; + (void)server; + + if (!rx || size < sizeof(struct afptest_dsi_header)) { + return 0; + } + + payload_len = size - sizeof(struct afptest_dsi_header); + + if (payload_len > rx->reply_cap) { + payload_len = rx->reply_cap; + } + + if (payload_len) { + memcpy(rx->reply, buf + sizeof(struct afptest_dsi_header), payload_len); + } + + rx->reply_len = payload_len; + return 0; +} + +static int ensure_libafpclient_started(pthread_t *loop_thread) +{ + pthread_mutex_lock(&libafpclient_init_lock); + + if (!libafpclient_started) { + init_uams(); + afp_main_quick_startup(loop_thread); + libafpclient_started = 1; + } + + pthread_mutex_unlock(&libafpclient_init_lock); + return 0; +} + +static size_t raw_read_request_size(const void *payload, size_t payload_len, + unsigned char subcommand) +{ + const uint8_t *p = payload; + uint32_t count32; + uint32_t count_hi; + uint32_t count_lo; + uint64_t count64; + + if (subcommand == afpRead) { + if (payload_len < 12) { + return 0; + } + + memcpy(&count32, p + 8, sizeof(count32)); + return ntohl(count32); + } + + if (subcommand == afpReadExt) { + if (payload_len < 20) { + return 0; + } + + memcpy(&count_hi, p + 12, sizeof(count_hi)); + memcpy(&count_lo, p + 16, sizeof(count_lo)); + count64 = ((uint64_t)ntohl(count_hi) << 32) | ntohl(count_lo); + + if (count64 > SIZE_MAX) { + return SIZE_MAX; + } + + return (size_t)count64; + } + + return 0; +} + +static unsigned int afp_version_number(const char *vers) +{ + if (!vers) { + return 34; + } + + if (strcmp(vers, "AFPVersion 2.1") == 0) { + return 21; + } + + if (strcmp(vers, "AFP2.2") == 0) { + return 22; + } + + if (strcmp(vers, "AFPX03") == 0) { + return 30; + } + + if (strcmp(vers, "AFP3.1") == 0) { + return 31; + } + + if (strcmp(vers, "AFP3.2") == 0) { + return 32; + } + + if (strcmp(vers, "AFP3.3") == 0) { + return 33; + } + + return 34; +} + +const char *afptest_libafpclient_uam_name(const char *uam) +{ + if (!uam || !*uam) { + return NULL; + } + + return resolve_uam_shorthand(uam); +} + +int afptest_libafpclient_login(struct CONN *conn, const char *host, int port, + const char *vers, const char *uam, + const char *user, const char *password) +{ + struct afptest_libafpclient_transport *transport; + struct afp_connection_request req; + unsigned int uam_mask; + + if (!conn || !host || !user || !password) { + return htonl((uint32_t)kFPParamErr); + } + + ensure_libafpclient_started(NULL); + afptest_libafpclient_close(conn); + transport = calloc(1, sizeof(*transport)); + + if (!transport) { + return htonl((uint32_t)kFPMiscErr); + } + + memset(&req, 0, sizeof(req)); + afp_default_url(&req.url); + snprintf(req.url.servername, sizeof(req.url.servername), "%s", host); + snprintf(req.url.username, sizeof(req.url.username), "%s", user); + snprintf(req.url.password, sizeof(req.url.password), "%s", password); + req.url.port = port; + req.url.requested_version = (int)afp_version_number(vers); + + if (uam && *uam) { + uam_mask = find_uam_by_name(uam); + + if (uam_mask == 0) { + free(transport); + return htonl((uint32_t)kFPBadUAM); + } + } else { + uam_mask = default_uams_mask(); + } + + req.uam_mask = uam_mask; + transport->server = afp_server_full_connect(NULL, &req); + + if (!transport->server) { + free(transport); + return htonl((uint32_t)kFPUserNotAuth); + } + + if (register_server_ref(transport->server) != 0) { + afp_server_remove(transport->server); + free(transport); + return htonl((uint32_t)kFPMiscErr); + } + + conn->transport = transport; + conn->dsi.socket = transport->server->fd; + conn->dsi.server_quantum = transport->server->tx_quantum; + conn->dsi.attn_quantum = transport->server->attention_quantum; + conn->afp_version = transport->server->using_version + ? transport->server->using_version->av_number + : (int)afp_version_number(vers); + conn->dsi.header.dsi_code = 0; + conn->dsi.cmdlen = 0; + conn->dsi.datalen = 0; + return 0; +} + +int afptest_libafpclient_raw_command(struct CONN *conn, + const void *payload, size_t payload_len, + uint8_t dsi_command, + uint32_t data_offset, + uint32_t *dsi_code, + void *reply, size_t reply_cap, + size_t *reply_len) +{ + struct afptest_libafpclient_transport *transport; + struct afptest_dsi_header *hdr; + struct afptest_raw_reply rx; + struct afptest_afp_rx_buffer read_rx; + int (*old_reply)(struct afp_server *, char *, unsigned int, void *); + unsigned char subcommand; + void *reply_context; + char *read_storage = NULL; + size_t read_cap; + size_t read_requested; + char *msg; + int rc; + + if (reply_len) { + *reply_len = 0; + } + + if (dsi_code) { + *dsi_code = htonl((uint32_t)kFPParamErr); + } + + if (!conn || !conn->transport || !payload || payload_len == 0) { + return -1; + } + + transport = conn->transport; + + if (!transport->server) { + return -1; + } + + msg = calloc(1, sizeof(*hdr) + payload_len); + + if (!msg) { + if (dsi_code) { + *dsi_code = htonl((uint32_t)kFPMiscErr); + } + + return -1; + } + + hdr = (struct afptest_dsi_header *)msg; + dsi_setup_header(transport->server, hdr, dsi_command); + hdr->return_code.data_offset = htonl(data_offset); + memcpy(msg + sizeof(*hdr), payload, payload_len); + subcommand = ((const unsigned char *)payload)[0]; + memset(&rx, 0, sizeof(rx)); + rx.reply = reply; + rx.reply_cap = reply_cap; + reply_context = ℞ + + if (subcommand == afpRead || subcommand == afpReadExt) { + read_requested = raw_read_request_size(payload, payload_len, subcommand); + read_cap = read_requested; + + if (transport->server->rx_quantum && read_cap > transport->server->rx_quantum) { + read_cap = transport->server->rx_quantum; + } + + if (read_cap < reply_cap) { + read_cap = reply_cap; + } + + if (read_cap > UINT_MAX) { + read_cap = UINT_MAX; + } + + if (read_cap > reply_cap) { + read_storage = malloc(read_cap); + + if (!read_storage) { + free(msg); + + if (dsi_code) { + *dsi_code = htonl((uint32_t)kFPMiscErr); + } + + return -1; + } + } + + memset(&read_rx, 0, sizeof(read_rx)); + read_rx.data = read_storage ? read_storage : reply; + read_rx.maxsize = (unsigned int)read_cap; + reply_context = &read_rx; + } + + old_reply = afp_replies[subcommand]; + + if (subcommand != afpRead && subcommand != afpReadExt) { + afp_replies[subcommand] = raw_reply; + } + + rc = dsi_send(transport->server, msg, (int)(sizeof(*hdr) + payload_len), + AFPT_RAW_TIMEOUT, subcommand, reply_context); + + if (subcommand != afpRead && subcommand != afpReadExt) { + afp_replies[subcommand] = old_reply; + } + + free(msg); + + if (subcommand == afpRead || subcommand == afpReadExt) { + rx.reply_len = read_rx.size > reply_cap ? reply_cap : read_rx.size; + + if (read_storage && rx.reply_len) { + memcpy(reply, read_storage, rx.reply_len); + } + } + + free(read_storage); + + if (dsi_code) { + *dsi_code = htonl((uint32_t)rc); + } + + if (reply_len) { + *reply_len = rx.reply_len; + } + + /* Negative AFP result codes still carry valid DSI reply payloads. */ + return rc == 0 || rc <= AFPT_AFP_ERROR_BASE ? 0 : -1; +} + +void afptest_libafpclient_logout(struct CONN *conn) +{ + struct afptest_libafpclient_transport *transport; + + if (!conn || !conn->transport) { + return; + } + + transport = conn->transport; + + if (transport->server) { + request_server_logout(transport->server); + } +} + +void afptest_libafpclient_close(struct CONN *conn) +{ + struct afptest_libafpclient_transport *transport; + int logout_requested; + int last_ref; + int fd; + + if (!conn || !conn->transport) { + return; + } + + transport = conn->transport; + + if (transport->server) { + last_ref = unregister_server_ref(transport->server, &logout_requested); + + if (last_ref) { + if (logout_requested) { + afp_logout(transport->server, 1); + } + + fd = transport->server->fd >= 0 ? transport->server->fd : conn->dsi.socket; + + if (fd >= 0) { + rm_fd_and_signal(fd); + } + + afp_server_remove(transport->server); + } + } + + free(transport); + conn->transport = NULL; + conn->dsi.socket = -1; +} + +#endif diff --git a/test/testsuite/afpclient_transport.h b/test/testsuite/afpclient_transport.h new file mode 100644 index 00000000000..53225a723ca --- /dev/null +++ b/test/testsuite/afpclient_transport.h @@ -0,0 +1,25 @@ +#ifndef AFPCLIENT_TRANSPORT_H +#define AFPCLIENT_TRANSPORT_H + +#include +#include + +struct CONN; + +#ifdef HAVE_TESTSUITE_LIBAFPCLIENT +int afptest_libafpclient_login(struct CONN *conn, const char *host, int port, + const char *vers, const char *uam, + const char *user, const char *password); +int afptest_libafpclient_raw_command(struct CONN *conn, + const void *payload, size_t payload_len, + uint8_t dsi_command, + uint32_t data_offset, + uint32_t *dsi_code, + void *reply, size_t reply_cap, + size_t *reply_len); +void afptest_libafpclient_logout(struct CONN *conn); +void afptest_libafpclient_close(struct CONN *conn); +const char *afptest_libafpclient_uam_name(const char *uam); +#endif + +#endif diff --git a/test/testsuite/lantest.c b/test/testsuite/lantest.c index d9bc98c6899..f5ae1b7307a 100644 --- a/test/testsuite/lantest.c +++ b/test/testsuite/lantest.c @@ -1814,8 +1814,9 @@ void run_test(const int32_t dir) void usage(char *av0) { fprintf(stdout, - "usage:\t%s [-34567bcGgKVv] [-h host] [-p port] [-s vol] [-u user] [-w password] " + "usage:\t%s [-34567bcGgKVv] [-A uam] [-h host] [-p port] [-s vol] [-u user] [-w password] " "[-n iterations] [-f tests] [-F bigfile]\n", av0); + fprintf(stdout, "\t-A\tUAM name or alias (default Cleartxt Passwrd)\n"); fprintf(stdout, "\t-h\tserver host name (default localhost)\n"); fprintf(stdout, "\t-p\tserver port (default 548)\n"); fprintf(stdout, "\t-s\tvolume to mount\n"); @@ -1869,7 +1870,7 @@ int main(int32_t ac, char **av) usage(av[0]); } - while ((cc = getopt(ac, av, "34567bcGgKVvF:f:h:n:p:s:u:w:")) != EOF) { + while ((cc = getopt(ac, av, "34567A:bcGgKVvF:f:h:n:p:s:u:w:")) != EOF) { switch (cc) { case '3': vers = "AFPX03"; @@ -1896,6 +1897,10 @@ int main(int32_t ac, char **av) Version = 34; break; + case 'A': + uam = strdup(optarg); + break; + case 'b': Debug = true; break; diff --git a/test/testsuite/logintest.c b/test/testsuite/logintest.c index bbd3370326e..6db1650378b 100644 --- a/test/testsuite/logintest.c +++ b/test/testsuite/logintest.c @@ -50,6 +50,7 @@ STATIC void connect_server(CONN *conn) } memset(&conn->dsi, 0, sizeof(conn->dsi)); + conn->use_legacy_transport = 0; conn->dsi.socket = sock; /* Guard against a server that accepts the TCP connection but stalls before * replying (e.g. parent busy reaping prior children after a connection-limit @@ -185,6 +186,7 @@ STATIC void test4(void) } connect_server(&conn[i]); + AFPUseLegacyTransport(&conn[i]); Dsi = &conn[i].dsi; cnt++; @@ -344,6 +346,7 @@ STATIC void test7(void) DSI *dsi; ENTER_TEST connect_server(Conn); + AFPUseLegacyTransport(Conn); Dsi = &Conn->dsi; dsi = Dsi; @@ -425,6 +428,7 @@ STATIC void test9(void) uint8_t garbage[16]; ENTER_TEST connect_server(Conn); + AFPUseLegacyTransport(Conn); Dsi = &Conn->dsi; if (Version < 30) { diff --git a/test/testsuite/meson.build b/test/testsuite/meson.build index cda79a1515b..ae802e23921 100644 --- a/test/testsuite/meson.build +++ b/test/testsuite/meson.build @@ -20,8 +20,22 @@ libafptest_sources = [ # afpclient.h) and must NOT be compiled against . libafptest_extra = [] libafptest_deps = [] +libafptest_c_args = [] spectest_extra_c_args = [] +testsuite_libafpclient = dependency( + 'libafpclient', + required: get_option('with-testsuite-libafpclient'), +) + +if testsuite_libafpclient.found() + libafptest_extra += ['afpclient_libafpclient.c'] + libafptest_deps += testsuite_libafpclient + afptest_external_deps += testsuite_libafpclient + libafptest_c_args += ['-DHAVE_TESTSUITE_LIBAFPCLIENT=1'] + spectest_extra_c_args += ['-DHAVE_TESTSUITE_LIBAFPCLIENT=1'] +endif + if have_spotlight libafptest_extra += [ 'afpcmd_spotlight.c', @@ -44,6 +58,7 @@ libafptest = static_library( libafptest_sources + libafptest_extra, include_directories: root_includes, dependencies: libafptest_deps, + c_args: libafptest_c_args, link_with: libatalk, ) @@ -56,6 +71,7 @@ executable( 'afparg', afparg_sources, include_directories: root_includes, + dependencies: afptest_external_deps, link_args: ['-rdynamic'], link_with: libafptest, install: true, @@ -89,6 +105,7 @@ executable( 'afp_logintest', login_test_sources, include_directories: root_includes, + dependencies: afptest_external_deps, link_args: ['-rdynamic'], link_with: libafptest, install: true, @@ -106,6 +123,7 @@ executable( 'afp_speedtest', speedtest_sources, include_directories: root_includes, + dependencies: afptest_external_deps, link_args: ['-rdynamic', '-lm'], link_with: libafptest, install: true, @@ -203,6 +221,7 @@ executable( 'afp_spectest', spectest_sources, include_directories: root_includes, + dependencies: afptest_external_deps, c_args: ['-D_PATH_TESTDATA_DIR="' + datadir + '/netatalk/test-data"'] + spectest_extra_c_args, link_args: ['-rdynamic'], diff --git a/test/testsuite/spectest.c b/test/testsuite/spectest.c index 5e9644e11e0..6f6039dcd1d 100644 --- a/test/testsuite/spectest.c +++ b/test/testsuite/spectest.c @@ -353,8 +353,9 @@ char *uam = "Cleartxt Passwrd"; void usage(char *av0) { fprintf(stdout, - "usage:\t%s [-1234567aCilmnVv] [-h host] [-H host2] [-p port] [-s vol] [-c vol path] [-S vol2] " + "usage:\t%s [-1234567aCilmnVv] [-A uam] [-h host] [-H host2] [-p port] [-s vol] [-c vol path] [-S vol2] " "[-u user] [-d user2] [-w password] [-F testsuite] [-f test]\n", av0); + fprintf(stdout, "\t-A\tUAM name or alias (default Cleartxt Passwrd)\n"); fprintf(stdout, "\t-a\tvolume is using AppleDouble metadata and not EA\n"); fprintf(stdout, "\t-m\tserver is a Mac\n"); fprintf(stdout, "\t-h\tserver host name (default localhost)\n"); @@ -395,7 +396,7 @@ int main(int ac, char **av) usage(av[0]); } - while ((cc = getopt(ac, av, "1234567aCEilmVvc:d:f:H:h:p:S:s:u:w:")) != EOF) { + while ((cc = getopt(ac, av, "1234567A:aCEilmVvc:d:f:H:h:p:S:s:u:w:")) != EOF) { switch (cc) { case '1': vers = "AFPVersion 2.1"; @@ -432,6 +433,10 @@ int main(int ac, char **av) Version = 34; break; + case 'A': + uam = strdup(optarg); + break; + case 'a': adouble = AD_V2; break; diff --git a/test/testsuite/speedtest.c b/test/testsuite/speedtest.c index bafeb5fcf0f..7f2dbedda2c 100644 --- a/test/testsuite/speedtest.c +++ b/test/testsuite/speedtest.c @@ -1801,9 +1801,10 @@ static void run_one(char *name) void usage(char *av0) { fprintf(stdout, - "usage:\t%s [-1234567acDeiLTVvy] [-h host] [-p port] [-s vol] [-P path] [-S vol2] [-u user] [-w password] [-n iterations] [-W warmup] " + "usage:\t%s [-1234567acDeiLTVvy] [-A uam] [-h host] [-p port] [-s vol] [-P path] [-S vol2] [-u user] [-w password] [-n iterations] [-W warmup] " "[-t delay] [-d size] [-z sizes] [-q quantum] [-r requests] [-f test] [-F file] \n", av0); + fprintf(stdout, "\t-A\tUAM name or alias (default Cleartxt Passwrd)\n"); fprintf(stdout, "\t-h\tserver host name (default localhost)\n"); fprintf(stdout, "\t-p\tserver port (default 548)\n"); fprintf(stdout, "\t-s\tvolume/share to mount (AFP mode)\n"); @@ -1859,7 +1860,7 @@ int main(int ac, char **av) } while ((cc = getopt(ac, av, - "1234567aceDiLTVvyd:F:f:h:n:p:P:q:r:S:s:t:u:w:W:z:")) != EOF) { + "1234567A:aceDiLTVvyd:F:f:h:n:p:P:q:r:S:s:t:u:w:W:z:")) != EOF) { switch (cc) { case '1': vers = "AFPVersion 2.1"; @@ -1896,6 +1897,10 @@ int main(int ac, char **av) Version = 34; break; + case 'A': + uam = strdup(optarg); + break; + case 'a': Flush = 0; break; diff --git a/test/testsuite/testhelper.c b/test/testsuite/testhelper.c index e2215f690ed..30f298b23b2 100644 --- a/test/testsuite/testhelper.c +++ b/test/testsuite/testhelper.c @@ -134,6 +134,14 @@ void test_skipped(int why) s = "extmap.conf type/creator mapping"; break; + case T_LIBAFPCLIENT: + s = "libafpclient transport"; + break; + + case T_RFORK_4GB: + s = "resource fork larger than 4GB"; + break; + default: s = "UNKNOWN REASON - this is a bug"; break; diff --git a/test/testsuite/testhelper.h b/test/testsuite/testhelper.h index fa80bfb9eaf..968179ae655 100644 --- a/test/testsuite/testhelper.h +++ b/test/testsuite/testhelper.h @@ -70,6 +70,8 @@ #define T_LOCALHOST 31 #define T_V2CONV 32 #define T_EXTMAP 33 +#define T_LIBAFPCLIENT 34 +#define T_RFORK_4GB 35 /* Define ansi colors */ #define ANSI_RED "\033[0;31m"