1 /* $Id: test_ncbi_ftp_connector.c 597284 2019-11-19 18:55:42Z lavr $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Anton Lavrentiev
27 *
28 * File Description:
29 * Test case for FTP-based CONNECTOR
30 *
31 */
32
33 #include <connect/ncbi_connutil.h>
34 #include <connect/ncbi_ftp_connector.h>
35 #include "../ncbi_ansi_ext.h"
36 #include "../ncbi_priv.h" /* CORE logging facilities */
37 #include <stdlib.h>
38 #ifdef HAVE_GETTIMEOFDAY
39 # include <sys/time.h>
40 #endif /*HAVE_GETTIMEOFDAY*/
41 #include <time.h>
42
43 #include "test_assert.h" /* This header must go last */
44
45 #define CONN_NCBI_FTP_HOST "ftp-ext.ncbi.nlm.nih.gov"
46
47 #define TEST_HOST CONN_NCBI_FTP_HOST
48 #define TEST_PORT 0
49 #define TEST_USER "ftp"
50 #define TEST_PASS "none"
51 #define TEST_PATH ((char*) 0)
52
53
s_GetTime(void)54 static double s_GetTime(void)
55 {
56 #ifdef HAVE_GETTIMEOFDAY
57 struct timeval t;
58 return gettimeofday(&t, 0) == 0 ? t.tv_sec + t.tv_usec / 1000000.0 : 0.0;
59 #else
60 time_t t = time(0);
61 return (double)((unsigned long) t);
62 #endif /*HAVE_GETTIMEOFDAY*/
63 }
64
65
main(int argc,char * argv[])66 int main(int argc, char* argv[])
67 {
68 static const char kChdir[] = "CWD /toolbox/ncbi_tools++\n";
69 static const char kFile[] = "DATA/Misc/test_ncbi_conn_stream.FTP.data";
70 int/*bool*/ cancel = 0, first;
71 TFTP_Flags flag = 0;
72 SConnNetInfo* net_info;
73 char buf[1024];
74 CONNECTOR connector;
75 FILE* data_file;
76 size_t size, n;
77 double elapsed;
78 EIO_Status status;
79 CONN conn;
80
81 g_NCBI_ConnectRandomSeed
82 = (unsigned int) time(0) ^ NCBI_CONNECT_SRAND_ADDEND;
83 srand(g_NCBI_ConnectRandomSeed);
84
85 /* Log and data-log streams */
86 CORE_SetLOGFormatFlags(fLOG_None | fLOG_Level |
87 fLOG_OmitNoteLevel | fLOG_DateTime);
88 CORE_SetLOGFILE(stderr, 0/*false*/);
89 data_file = fopen("test_ncbi_ftp_connector.dat", "wb");
90 assert(data_file);
91
92 assert((net_info = ConnNetInfo_Create(0)) != 0);
93 if (net_info->debug_printout == eDebugPrintout_Some)
94 flag |= fFTP_LogControl;
95 else if (net_info->debug_printout == eDebugPrintout_Data) {
96 char val[32];
97 ConnNetInfo_GetValue(0, REG_CONN_DEBUG_PRINTOUT, val, sizeof(val),
98 DEF_CONN_DEBUG_PRINTOUT);
99 flag |= strcasecmp(val, "all") == 0 ? fFTP_LogAll : fFTP_LogData;
100 }
101 flag |= fFTP_UseFeatures;
102
103 if (TEST_PORT) {
104 sprintf(buf, ":%hu", TEST_PORT);
105 } else {
106 *buf = 0;
107 }
108 CORE_LOGF(eLOG_Note, ("Connecting to ftp://%s:%s@%s%s/",
109 TEST_USER, TEST_PASS, TEST_HOST, buf));
110 /* Run the tests */
111 connector = FTP_CreateConnectorSimple(TEST_HOST, TEST_PORT,
112 TEST_USER, TEST_PASS,
113 TEST_PATH, flag, 0);
114
115 if (CONN_CreateEx(connector,
116 fCONN_Supplement | fCONN_Untie, &conn) != eIO_Success) {
117 CORE_LOG(eLOG_Fatal, "Cannot create FTP download connection");
118 }
119
120 assert(CONN_SetTimeout(conn, eIO_Open, net_info->timeout)
121 == eIO_Success);
122 assert(CONN_SetTimeout(conn, eIO_ReadWrite, net_info->timeout)
123 == eIO_Success);
124 assert(CONN_SetTimeout(conn, eIO_Close, net_info->timeout)
125 == eIO_Success);
126
127 if (CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain) != eIO_Closed)
128 CORE_LOG(eLOG_Fatal, "Test failed in empty READ");
129
130 if (CONN_Write(conn, "aaa", 3, &n, eIO_WritePlain) != eIO_Success)
131 CORE_LOG(eLOG_Fatal, "Cannot write FTP command");
132
133 if (CONN_Wait(conn, eIO_Read, net_info->timeout) != eIO_NotSupported)
134 CORE_LOG(eLOG_Fatal, "Test failed in waiting for READ");
135 CORE_LOG(eLOG_Note, "Unrecognized command correctly rejected");
136
137 if (CONN_Write(conn, "LIST\nSIZE", 9, &n, eIO_WritePlain) != eIO_Unknown)
138 CORE_LOG(eLOG_Fatal, "Test failed to reject multiple commands");
139 CORE_LOG(eLOG_Note, "Multiple commands correctly rejected");
140
141 status = CONN_Write(conn, "SIZE 1GB", 9, &n, eIO_WritePlain);
142 if (status == eIO_Success) {
143 char buf[128];
144 CONN_ReadLine(conn, buf, sizeof(buf) - 1, &n);
145 CORE_LOGF(eLOG_Note, ("SIZE file: %.*s", (int) n, buf));
146 } else {
147 CORE_LOGF(eLOG_Note, ("SIZE command not accepted: %s",
148 IO_StatusStr(status)));
149 }
150
151 if (CONN_Write(conn, "LIST", 4, &n, eIO_WritePlain) != eIO_Success)
152 CORE_LOG(eLOG_Fatal, "Cannot write LIST command");
153
154 CORE_LOG(eLOG_Note, "LIST command output:");
155 first = 1/*true*/;
156 do {
157 status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain);
158 if (n != 0) {
159 printf("%.*s", (int) n, buf);
160 first = 0/*false*/;
161 fflush(stdout);
162 }
163 } while (status == eIO_Success);
164 if (first || status != eIO_Closed) {
165 printf("<%s>\n", status != eIO_Success ? IO_StatusStr(status) : "EOF");
166 fflush(stdout);
167 }
168
169 if (CONN_Write(conn, "NLST\r\n", 6, &n, eIO_WritePlain) != eIO_Success)
170 CORE_LOG(eLOG_Fatal, "Cannot write NLST command");
171
172 CORE_LOG(eLOG_Note, "NLST command output:");
173 first = 1/*true*/;
174 do {
175 status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain);
176 if (n != 0) {
177 printf("%.*s", (int) n, buf);
178 first = 0/*false*/;
179 fflush(stdout);
180 } else
181 assert(status != eIO_Success);
182 } while (status == eIO_Success);
183 if (first || status != eIO_Closed) {
184 printf("<%s>\n", status != eIO_Success ? IO_StatusStr(status) : "EOF");
185 fflush(stdout);
186 }
187
188 if (CONN_Write(conn, "SIZE ", 5, &n, eIO_WritePersist) != eIO_Success)
189 CORE_LOG(eLOG_Fatal, "Cannot write SIZE directory command");
190 size = strlen(kChdir + 4);
191 if (CONN_Write(conn, kChdir + 4, size, &n, eIO_WritePlain) == eIO_Success){
192 CONN_ReadLine(conn, buf, sizeof(buf) - 1, &n);
193 CORE_LOGF(eLOG_Note, ("SIZE directory returned: %.*s", (int) n, buf));
194 } else {
195 CORE_LOGF(eLOG_Note, ("SIZE directory not accepted: %s",
196 IO_StatusStr(status)));
197 }
198
199 if (CONN_Write(conn, kChdir, sizeof(kChdir) - 1, &n, eIO_WritePlain)
200 != eIO_Success) {
201 CORE_LOGF(eLOG_Fatal, ("Cannot execute %.*s",
202 (int) sizeof(kChdir) - 2, kChdir));
203 }
204 if (CONN_Write(conn, "PWD\n", 4, &n, eIO_WritePlain) == eIO_Success) {
205 CONN_ReadLine(conn, buf, sizeof(buf) - 1, &n);
206 CORE_LOGF(eLOG_Note, ("PWD returned: %.*s", (int) n, buf));
207 } else
208 CORE_LOG(eLOG_Fatal, "Cannot execute PWD");
209
210 if (CONN_Write(conn, "CDUP\n", 5, &n, eIO_WritePlain) != eIO_Success)
211 CORE_LOG(eLOG_Fatal, "Cannot execute CDUP");
212 if (CONN_Write(conn, "XCUP\n", 5, &n, eIO_WritePlain) != eIO_Success)
213 CORE_LOG(eLOG_Fatal, "Cannot execute XCUP");
214
215 if (CONN_Write(conn, kChdir, sizeof(kChdir) - 1, &n, eIO_WritePlain)
216 != eIO_Success) {
217 CORE_LOGF(eLOG_Fatal, ("Cannot re-execute %.*s",
218 (int) sizeof(kChdir) - 2, kChdir));
219 }
220
221 size = sizeof(kFile) - 1;
222 if ((status = CONN_Write(conn, "MDTM ", 5, &n, eIO_WritePersist))
223 == eIO_Success && n == 5 &&
224 (status = CONN_Write(conn, kFile, size, &n, eIO_WritePlain))
225 == eIO_Success && n == size) {
226 unsigned long val;
227 char buf[128];
228 CONN_ReadLine(conn, buf, sizeof(buf) - 1, &n);
229 if (n && sscanf(buf, "%lu", &val) > 0) {
230 struct tm* tm;
231 time_t t = (time_t) val;
232 if ((tm = localtime(&t)) != 0)
233 n = strftime(buf, sizeof(buf), "%m/%d/%Y %H:%M:%S", tm);
234 }
235 CORE_LOGF(eLOG_Note, ("MDTM returned: %.*s", (int) n, buf));
236 } else {
237 CORE_LOGF(eLOG_Note, ("MDTM command not accepted: %s",
238 IO_StatusStr(status)));
239 }
240
241 if ((status = CONN_Write(conn, "RETR ", 5, &n, eIO_WritePersist))
242 != eIO_Success || n != 5 ||
243 (status = CONN_Write(conn, kFile, size, &n, eIO_WritePersist))
244 != eIO_Success || n != size) {
245 CORE_LOGF(eLOG_Fatal, ("Cannot write 'RETR %s': %s",
246 kFile, IO_StatusStr(status)));
247 }
248
249 size = 0;
250 elapsed = s_GetTime();
251 do {
252 status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain);
253 if (n != 0) {
254 fwrite(buf, n, 1, data_file);
255 fflush(data_file);
256 size += n;
257 rand();
258 if (argc > 1 && rand() % 100000 == 55555) {
259 cancel = 1;
260 break;
261 }
262 } else {
263 assert(status != eIO_Success);
264 if (status != eIO_Closed || !size)
265 CORE_LOGF(eLOG_Error, ("Read error: %s",IO_StatusStr(status)));
266 }
267 } while (status == eIO_Success);
268 if (status != eIO_Success)
269 cancel = 0;
270 elapsed = s_GetTime() - elapsed;
271
272 if (!cancel || !(rand() & 1)) {
273 if (cancel)
274 CORE_LOG(eLOG_Note, "Cancelling download by a command");
275 if (CONN_Write(conn, "NLST blah*", 10, &n, eIO_WritePlain)
276 != eIO_Success) {
277 CORE_LOG(eLOG_Fatal, "Cannot write garbled NLST command");
278 }
279
280 CORE_LOG(eLOG_Note, "Garbled NLST command output (expected empty):");
281 first = 1/*true*/;
282 do {
283 status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain);
284 if (n != 0) {
285 printf("%.*s", (int) n, buf);
286 first = 0/*false*/;
287 fflush(stdout);
288 }
289 } while (status == eIO_Success);
290 if (first) {
291 printf("<EOF>\n");
292 fflush(stdout);
293 }
294 } else if (cancel)
295 CORE_LOG(eLOG_Note, "Closing with download still in progress");
296
297 if (CONN_Close(conn) != eIO_Success)
298 CORE_LOG(eLOG_Fatal, "Error in closing FTP connection");
299
300 /* Cleanup and exit */
301 fclose(data_file);
302 if (!cancel) {
303 CORE_LOGF(size ? eLOG_Note : eLOG_Fatal,
304 ("%lu byte(s) downloaded in %.2f second(s) @ %.2fKB/s",
305 (unsigned long) size, elapsed,
306 (unsigned long) size / (1024 * (elapsed ? elapsed : 1.0))));
307 } else
308 remove("test_ncbi_ftp_connector.dat");
309 ConnNetInfo_Destroy(net_info);
310
311 CORE_LOG(eLOG_Note, "TEST completed successfully");
312 CORE_SetLOG(0);
313 return 0;
314 }
315