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