Line data Source code
1 : /********************************************************************\
2 :
3 : Name: ftplib.c
4 : Created by: Originally written by Oleg Orel (orel@lpuds.oea.ihep.su),
5 : translated from UNIX to NT by Urs Rohrer (rohrer@psi.ch),
6 : simplified and adapted for MIDAS by Stefan Ritt.
7 :
8 : Contents: File Transfer Protocol library
9 :
10 : $Id$
11 :
12 : \********************************************************************/
13 :
14 : #include "midas.h"
15 : #include "msystem.h"
16 : #include "ftplib.h"
17 :
18 : #ifndef FTP_SUCCESS
19 : #define FTP_SUCCESS 1
20 : #define FTP_NET_ERROR 802
21 : #define FTP_FILE_ERROR 803
22 : #define FTP_RESPONSE_ERROR 804
23 : #define FTP_INVALID_ARG 805
24 : #endif
25 :
26 : static char bars[] = "/-\\|";
27 : int (*ftp_debug_func) (const char *message);
28 : int (*ftp_error_func) (const char *message);
29 :
30 : /*------------------------------------------------------------------*/
31 :
32 0 : void ftp_debug(int (*debug_func) (const char *message), int (*error_func) (const char *message))
33 : /* set message display functions for debug and error messages */
34 : {
35 0 : ftp_debug_func = debug_func;
36 0 : ftp_error_func = error_func;
37 0 : }
38 :
39 : /*------------------------------------------------------------------*/
40 :
41 0 : int ftp_connect(FTP_CON ** con, const char *host_name, unsigned short port)
42 : /* Connect to a FTP server on a host at a given port (usually 21).
43 : Return a FTP_CON structure if successful */
44 : {
45 : struct sockaddr_in bind_addr;
46 : int sock;
47 : char str[4000];
48 : int status;
49 : struct hostent *phe;
50 :
51 0 : *con = NULL;
52 :
53 : #ifdef OS_WINNT
54 : {
55 : WSADATA WSAData;
56 :
57 : /* Start windows sockets */
58 : if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
59 : return FTP_NET_ERROR;
60 : }
61 : #endif
62 :
63 0 : if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
64 0 : if (ftp_error_func)
65 0 : ftp_error_func("cannot create socket");
66 0 : return FTP_NET_ERROR;
67 : }
68 :
69 : /* connect to remote node */
70 0 : memset(&bind_addr, 0, sizeof(bind_addr));
71 0 : bind_addr.sin_family = AF_INET;
72 0 : bind_addr.sin_addr.s_addr = 0;
73 0 : bind_addr.sin_port = htons(port);
74 :
75 : #ifdef OS_VXWORKS
76 : {
77 : INT host_addr;
78 :
79 : host_addr = hostGetByName(host_name);
80 : memcpy((char *) &(bind_addr.sin_addr), &host_addr, 4);
81 : }
82 : #else
83 0 : phe = gethostbyname(host_name);
84 0 : if (phe == NULL) {
85 0 : if (ftp_error_func)
86 0 : ftp_error_func("cannot get host name");
87 0 : return RPC_NET_ERROR;
88 : }
89 0 : memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
90 : #endif
91 :
92 : #ifdef OS_UNIX
93 : do {
94 0 : status = connect(sock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
95 :
96 : /* don't return if an alarm signal was cought */
97 0 : } while (status == -1 && errno == EINTR);
98 : #else
99 : status = connect(sock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
100 : #endif
101 :
102 0 : if (status != 0) {
103 0 : sprintf(str, "cannot connect to host %s, port %d", host_name, port);
104 0 : if (ftp_error_func)
105 0 : ftp_error_func(str);
106 0 : return FTP_NET_ERROR;
107 : }
108 :
109 :
110 0 : *con = (FTP_CON *) malloc(sizeof(FTP_CON));
111 0 : (*con)->sock = sock;
112 0 : (*con)->data = 0;
113 :
114 0 : memset(str, 0, sizeof(str));
115 0 : status = ftp_get_message(*con, str);
116 :
117 : /* check for status */
118 0 : if (status == FTP_QUIT || !ftp_good(status, 120, 220, EOF)) {
119 0 : closesocket(sock);
120 0 : free(*con);
121 0 : return FTP_NET_ERROR;
122 : }
123 :
124 0 : return FTP_SUCCESS;
125 : }
126 :
127 : /*------------------------------------------------------------------*/
128 :
129 0 : int ftp_send_message(FTP_CON * con, const char *message)
130 : /* send a message to a FTP server */
131 : {
132 0 : if (send(con->sock, message, strlen(message), 0) == -1)
133 0 : return FTP_NET_ERROR;
134 :
135 0 : if (send(con->sock, "\r\n", 2, 0) == -1)
136 0 : return FTP_NET_ERROR;
137 :
138 0 : if (ftp_debug_func != NULL)
139 0 : ftp_debug_func(message);
140 :
141 0 : return FTP_SUCCESS;
142 : }
143 :
144 : /*------------------------------------------------------------------*/
145 :
146 0 : int ftp_command(FTP_CON * con, const char *command, const char *param, ...)
147 : /* execute FTP command, check for return codes */
148 : {
149 : va_list args;
150 : char str[256];
151 : int status, code;
152 : BOOL result_ok;
153 :
154 : /* compose command string */
155 0 : sprintf(str, command, param);
156 :
157 : /* send command */
158 0 : if (ftp_send_message(con, str) != FTP_SUCCESS)
159 0 : return FTP_NET_ERROR;
160 :
161 : /* read reply */
162 0 : status = ftp_get_message(con, str);
163 0 : if (status == FTP_QUIT)
164 0 : return FTP_NET_ERROR;
165 :
166 : /* check reply code */
167 0 : va_start(args, param);
168 :
169 0 : result_ok = FALSE;
170 : do {
171 0 : code = va_arg(args, int);
172 0 : if (code == EOF)
173 0 : break;
174 :
175 0 : if (code == status)
176 0 : result_ok = TRUE;
177 :
178 0 : } while (!result_ok);
179 :
180 0 : va_end(args);
181 :
182 0 : if (!result_ok) {
183 0 : if (ftp_error_func != NULL)
184 0 : ftp_error_func(str);
185 :
186 0 : return FTP_RESPONSE_ERROR;
187 : }
188 :
189 0 : return -status;
190 : }
191 :
192 : /*------------------------------------------------------------------*/
193 :
194 0 : int ftp_get_message(FTP_CON * con, char *message)
195 : /* read message from FTP server */
196 : {
197 : int i;
198 :
199 0 : for (i = 0;; i++) {
200 0 : if (recv(con->sock, &message[i], 1, 0) != 1)
201 0 : return FTP_QUIT;
202 :
203 0 : if (i > 1 && message[i] == 10 && message[i - 1] == 13)
204 0 : break;
205 : }
206 :
207 0 : message[i - 1] = 0;
208 :
209 0 : con->err_no = atoi(message);
210 :
211 0 : if (ftp_debug_func != NULL)
212 0 : ftp_debug_func(message);
213 :
214 : /* check for continuation message */
215 0 : if (message[3] == '-')
216 0 : ftp_get_message(con, message + strlen(message));
217 :
218 0 : return con->err_no;
219 : }
220 :
221 : /*------------------------------------------------------------------*/
222 :
223 0 : BOOL ftp_good(int number, ...)
224 : /* check if number matches any code from argument list */
225 : {
226 : va_list args;
227 : BOOL result;
228 : int code;
229 :
230 0 : va_start(args, number);
231 0 : result = FALSE;
232 :
233 : do {
234 0 : code = va_arg(args, int);
235 0 : if (code == EOF)
236 0 : break;
237 :
238 0 : if (code == number)
239 0 : result = TRUE;
240 :
241 0 : } while (!result);
242 :
243 0 : va_end(args);
244 :
245 0 : return result;
246 : }
247 :
248 : /*------------------------------------------------------------------*/
249 :
250 0 : int ftp_data(FTP_CON * con, const char *command, const char *file)
251 : /* open data socket */
252 : {
253 : struct sockaddr_in data, from;
254 : struct hostent *host;
255 : char host_name[256];
256 : int listen_socket, data_socket;
257 0 : unsigned int len = sizeof(data), fromlen = sizeof(from);
258 0 : int one = 1, status;
259 : char *a, *b;
260 :
261 0 : memset(&data, 0, sizeof(data));
262 0 : memset(&from, 0, sizeof(from));
263 :
264 0 : if (gethostname(host_name, sizeof(host_name)) == -1)
265 0 : return FTP_NET_ERROR;
266 :
267 0 : if ((host = (struct hostent *) gethostbyname(host_name)) == 0)
268 0 : return FTP_NET_ERROR;
269 :
270 0 : if ((listen_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
271 0 : return FTP_NET_ERROR;
272 :
273 0 : if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR,
274 0 : (char *) &one, sizeof(one)) < 0) {
275 0 : closesocket(listen_socket);
276 0 : return FTP_NET_ERROR;
277 : }
278 :
279 0 : data.sin_family = AF_INET;
280 0 : data.sin_port = htons(0);
281 0 : data.sin_addr.s_addr = *(unsigned long *) *(host->h_addr_list);
282 :
283 0 : if (bind(listen_socket, (struct sockaddr *) &data, sizeof(data)) == -1) {
284 0 : closesocket(listen_socket);
285 0 : return FTP_NET_ERROR;
286 : }
287 :
288 : #ifdef OS_WINNT
289 : if (getsockname(listen_socket, (struct sockaddr *) &data, (int *)&len) < 0) {
290 : #else
291 0 : if (getsockname(listen_socket, (struct sockaddr *) &data, &len) < 0) {
292 : #endif
293 0 : closesocket(listen_socket);
294 0 : return FTP_NET_ERROR;
295 : }
296 :
297 0 : if (listen(listen_socket, 1) != 0) {
298 0 : closesocket(listen_socket);
299 0 : return FTP_NET_ERROR;
300 : }
301 :
302 0 : a = (char *) &data.sin_addr;
303 0 : b = (char *) &data.sin_port;
304 :
305 0 : status = ftp_port(con, FTP_CUT(a[0]), FTP_CUT(a[1]), FTP_CUT(a[2]),
306 0 : FTP_CUT(a[3]), FTP_CUT(b[0]), FTP_CUT(b[1]));
307 0 : if (status != FTP_SUCCESS)
308 0 : return FTP_NET_ERROR;
309 :
310 0 : status = ftp_command(con, command, file, 200, 120, 150, 125, 250, EOF);
311 0 : if (status >= 0)
312 0 : return status;
313 :
314 : #ifdef OS_WINNT
315 : data_socket = accept(listen_socket, (struct sockaddr *) &from, (int *)&fromlen);
316 : #else
317 0 : data_socket = accept(listen_socket, (struct sockaddr *) &from, &fromlen);
318 : #endif
319 :
320 0 : if (data_socket == -1) {
321 0 : closesocket(listen_socket);
322 0 : return FTP_NET_ERROR;
323 : }
324 :
325 0 : closesocket(listen_socket);
326 :
327 0 : con->data = data_socket;
328 :
329 0 : return status;
330 : }
331 :
332 : /*------------------------------------------------------------------*/
333 :
334 0 : int ftp_close(FTP_CON * con)
335 : /* close data connection */
336 : {
337 : char str[256];
338 :
339 0 : closesocket(con->data);
340 :
341 0 : return ftp_get_message(con, str);
342 : }
343 :
344 : /*------------------------------------------------------------------*/
345 :
346 0 : int ftp_send(int sock, const char *buffer, int n_bytes_to_write)
347 : /* send number of bytes over socket */
348 : {
349 : int n_bytes_left, n_written;
350 :
351 0 : n_bytes_left = n_bytes_to_write;
352 :
353 0 : while (n_bytes_left > 0) {
354 0 : n_written = send(sock, buffer, n_bytes_left > 8192 ? 8192 : n_bytes_left, 0);
355 0 : if (n_written <= 0)
356 0 : return n_bytes_to_write - n_bytes_left;
357 :
358 0 : n_bytes_left -= n_written;
359 0 : buffer += n_written;
360 : }
361 :
362 0 : return n_bytes_to_write;
363 : }
364 :
365 : /*------------------------------------------------------------------*/
366 :
367 0 : int ftp_receive(int sock, char *buffer, int bsize)
368 : /* receive buffer from socket, return number of received bytes */
369 : {
370 : int count, i;
371 :
372 0 : i = 0;
373 : while (TRUE) {
374 0 : count = recv(sock, buffer + i, bsize - 1 - i, 0);
375 0 : if (count <= 0)
376 0 : return i;
377 :
378 0 : i += count;
379 0 : buffer[i] = 0;
380 :
381 0 : if (i >= bsize - 1)
382 0 : return i;
383 : }
384 : }
385 :
386 : /*------------------------------------------------------------------*/
387 :
388 0 : int ftp_login(FTP_CON ** con, const char *host, unsigned short port,
389 : const char *user, const char *password, const char *account)
390 : /* FTP login with username and password */
391 : {
392 : int status;
393 :
394 0 : status = ftp_connect(con, host, port);
395 0 : if (status != FTP_SUCCESS)
396 0 : return status;
397 :
398 0 : status = ftp_user(*con, user);
399 0 : if (status >= 0)
400 0 : return status;
401 :
402 0 : if (status == -230)
403 0 : return status;
404 :
405 0 : if (status == -332) {
406 0 : if (account == NULL)
407 0 : return FTP_NET_ERROR;
408 :
409 0 : status = ftp_account(*con, account);
410 0 : if (status < 1)
411 0 : return status;
412 :
413 0 : if (status == -230)
414 0 : return status;
415 : }
416 :
417 0 : return ftp_password(*con, password);
418 : }
419 :
420 : /*------------------------------------------------------------------*/
421 :
422 0 : int ftp_bye(FTP_CON * con)
423 : /* disconnect from FTP server */
424 : {
425 : char str[256];
426 :
427 0 : ftp_send_message(con, "QUIT");
428 0 : ftp_get_message(con, str);
429 :
430 0 : closesocket(con->sock);
431 0 : free(con);
432 :
433 0 : return FTP_SUCCESS;
434 : }
435 :
436 : /*------------------------------------------------------------------*/
437 :
438 0 : int ftp_port(FTP_CON * con, int a, int b, int c, int d, int e, int f)
439 : /* set port for data connection */
440 : {
441 : char cmd[256];
442 : int status;
443 :
444 0 : sprintf(cmd, "PORT %d,%d,%d,%d,%d,%d", a, b, c, d, e, f);
445 0 : if (ftp_send_message(con, cmd) != FTP_SUCCESS)
446 0 : return FTP_NET_ERROR;
447 :
448 0 : status = ftp_get_message(con, cmd);
449 0 : if (status == FTP_QUIT)
450 0 : return FTP_QUIT;
451 :
452 0 : if (!ftp_good(status, 200, EOF))
453 0 : return FTP_NET_ERROR;
454 :
455 0 : return FTP_SUCCESS;
456 : }
457 :
458 : /*------------------------------------------------------------------*/
459 :
460 0 : int ftp_move(FTP_CON * con, const char *oldname, const char *newname)
461 : /* move/rename file */
462 : {
463 : int status;
464 :
465 0 : status = ftp_command(con, "RNFR %s", oldname, 200, 350, EOF);
466 :
467 0 : if (status < 0)
468 0 : return ftp_command(con, "RNTO %s", newname, 200, 250, EOF);
469 : else
470 0 : return status;
471 : }
472 :
473 : /*------------------------------------------------------------------*/
474 :
475 0 : int ftp_get(FTP_CON * con, const char *local_name, const char *remote_name)
476 : /* get file */
477 : {
478 : int fh;
479 : int status;
480 : char buff[8192];
481 : char str[256];
482 : int count, i;
483 0 : long total = 0;
484 : DWORD start, stop;
485 :
486 0 : if (ftp_open_read(con, remote_name) >= 0)
487 0 : return con->err_no;
488 :
489 0 : if ((fh = open(local_name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644)) == -1)
490 0 : return FTP_FILE_ERROR;
491 :
492 0 : start = ss_millitime();
493 :
494 0 : while ((count = ftp_receive(con->data, buff, sizeof(buff))) > 0) {
495 0 : total += write(fh, buff, count);
496 0 : i = 0;
497 0 : if (ftp_debug_func != NULL) {
498 0 : printf("%c\r", bars[(i++) % 4]);
499 0 : fflush(stdout);
500 : }
501 : }
502 :
503 0 : close(fh);
504 0 : stop = ss_millitime();
505 :
506 0 : status = ftp_close(con);
507 0 : if (ftp_debug_func != NULL) {
508 0 : sprintf(str, "%ld bytes received in %1.2f seconds (%1.2lf kB/sec).",
509 0 : total, (stop - start) / 1000.0, total / 1024.0 / ((stop - start) / 1000.0));
510 0 : ftp_debug_func(str);
511 : }
512 :
513 0 : return status;
514 : }
515 :
516 : /*------------------------------------------------------------------*/
517 :
518 0 : int ftp_put(FTP_CON * con, const char *local_name, const char *remote_name)
519 : /* put file */
520 : {
521 : int fh;
522 : int status;
523 : char buff[8193];
524 : char str[256];
525 0 : int count, i = 0;
526 0 : long total = 0;
527 : DWORD start, stop;
528 :
529 0 : if (ftp_open_write(con, remote_name) >= 0)
530 0 : return con->err_no;
531 :
532 0 : if ((fh = open(local_name, O_BINARY)) == -1)
533 0 : return FTP_FILE_ERROR;
534 :
535 0 : start = ss_millitime();
536 :
537 0 : while ((count = read(fh, buff, 8192)) > 0) {
538 0 : total += ftp_send(con->data, buff, count);
539 0 : if (ftp_debug_func != NULL) {
540 0 : printf("%c\r", bars[(i++) % 4]);
541 0 : fflush(stdout);
542 : }
543 : }
544 :
545 0 : close(fh);
546 0 : stop = ss_millitime();
547 :
548 0 : status = ftp_close(con);
549 0 : if (ftp_debug_func != NULL) {
550 0 : sprintf(str, "%ld bytes sent in %1.2f seconds (%1.2lf kB/sec).",
551 0 : total, (stop - start) / 1000.0, total / 1024.0 / ((stop - start) / 1000.0));
552 0 : ftp_debug_func(str);
553 : }
554 :
555 0 : return status;
556 : }
557 :
558 : /*------------------------------------------------------------------*/
559 :
560 0 : char *ftp_pwd(FTP_CON * con)
561 : /* show present working directory */
562 : {
563 : static char str[256];
564 : char tmp[256];
565 : int status;
566 :
567 0 : str[0] = 0;
568 0 : if (ftp_send_message(con, "PWD") != FTP_SUCCESS)
569 0 : return str;
570 :
571 0 : status = ftp_get_message(con, tmp);
572 :
573 0 : if (status != 257) {
574 0 : if (ftp_error_func != NULL)
575 0 : ftp_error_func(tmp);
576 :
577 0 : return str;
578 : }
579 :
580 0 : sscanf(tmp, "%*[^\"]%*c%[^\"]%*s", str);
581 :
582 0 : return str;
583 : }
584 :
585 : /*------------------------------------------------------------------*/
586 :
587 0 : int ftp_dir(FTP_CON * con, const char *file)
588 : /* display directory */
589 : {
590 : char command[256], buffer[8192];
591 :
592 0 : if (file == NULL || *file == '\0')
593 0 : strcpy(command, "LIST");
594 : else
595 0 : sprintf(command, "LIST %s", file);
596 :
597 0 : if (ftp_data(con, command, "") >= 0)
598 0 : return con->err_no;
599 :
600 0 : while (ftp_receive(con->data, buffer, sizeof(buffer)))
601 0 : printf("%s", buffer);
602 :
603 0 : return ftp_close(con);
604 : }
605 :
606 : /*------------------------------------------------------------------*/
|