Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/sub.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (show annotations) (download) (as text)
Mon Mar 2 05:17:04 2009 UTC (15 years, 1 month ago) by hirohitohigashi
File MIME type: text/x-csrc
File size: 15444 byte(s)
Merged same process.

1 /*
2 Some global functions for libOftp.
3
4 Copyright (c) 2009-2009 hirohito higashi. All rights reserved.
5 This file is distributed under BSD license.
6 */
7
8
9 /***** Feature test switches ************************************************/
10 /***** System headers *******************************************************/
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <arpa/inet.h>
19 #include <sys/time.h>
20 #include <sys/select.h>
21
22
23 /***** Local headers ********************************************************/
24 #include "liboftp.h"
25 #include "sub.h"
26
27
28 /***** Constat values *******************************************************/
29 #define TRANSFER_SEGMENT_SIZE 4096 /* 一度のrecv()で転送するバイト数 */
30
31
32 /***** Macros ***************************************************************/
33 /***** Typedefs *************************************************************/
34 /***** Function prototypes **************************************************/
35 /***** Local variables ******************************************************/
36 /***** Global variables *****************************************************/
37 /***** Signal catching functions ********************************************/
38 /***** Local functions ******************************************************/
39 /****************************************************************************/
40 /*! read a line
41 *
42 *@param sd socket descriptor
43 *@param buf pointer of receive buffer
44 *@param bufsiz buffer size
45 *@param flags flags of recv()
46 *@retval int number of bytes received, or -1 if an error.
47 *@note
48 *
49 */
50 static int recv_line( int sd, char *buf, int bufsiz, int flags )
51 {
52 int n;
53 char c;
54 char *p = buf;
55 int total_len = 0;
56
57 bufsiz--;
58
59 while( 1 ) {
60 n = recv( sd, &c, 1, flags );
61 if( n < 0 ) {
62 if( errno == EINTR ) continue;
63 *p = 0;
64 DEBUGPRINT1( "recv_line: get minus. %s\n", strerror(errno) );
65 return n;
66 }
67 if( n == 0 ) {
68 DEBUGPRINT1( "recv_line: get zero. %s\n", strerror(errno) );
69 break;
70 }
71
72 *p++ = c;
73 total_len++;
74
75 if( c == '\n' ) break;
76 if( bufsiz < total_len ) break;
77 }
78 *p = 0;
79
80 return total_len;
81 }
82
83
84
85 /***** Global functions *****************************************************/
86
87 /****************************************************************************/
88 /*! send n bytes.
89 *
90 *@param sd socket descriptor
91 *@param buf pointer of send buffer
92 *@param len message length
93 *@param flags flags of send()
94 *@retval int number of bytes sent, or -1 if an error.
95 *@note
96 *
97 */
98 int sendn( int sd, const char *buf, int len, int flags )
99 {
100 int left = len;
101 int n;
102
103 while( left > 0 ) {
104 n = send( sd, buf, left, flags );
105 if( n < 0 ) {
106 if( errno == EINTR ) continue;
107 DEBUGPRINT1( "sendn: get minus. %s\n", strerror(errno) );
108 return n;
109 }
110 buf += n;
111 left -= n;
112 }
113
114 return len;
115 }
116
117
118
119 /****************************************************************************/
120 /*! send ftp command
121 *
122 *@param ftp pointer of LIBOFTP.
123 *@param cmd ftp command.
124 *@retval int 0 is no error, or -1 if an error.
125 *@note
126 *
127 */
128 int ftp_send_command( LIBOFTP *ftp, const char *cmd )
129 {
130 int ret;
131 DEBUGPRINT1( "SENDC: %s", cmd );
132 ret = sendn( ftp->socket, cmd, strlen( cmd ), 0 );
133 if( ret < 0 ) {
134 copy_strerror();
135 return ret;
136 }
137
138 return 0;
139 }
140
141
142
143 /****************************************************************************/
144 /*! receive response
145 *
146 *@param ftp pointer of LIBOFTP.
147 *@param res_buf response buffer ( null ok )
148 *@param bufsiz response buffer size.
149 *@retval int reply code, or error code (minus value)
150 *@note
151 * set reply code to ftp attribute reply_code;
152 */
153 int ftp_receive_response( LIBOFTP *ftp, char *res_buf, int bufsiz )
154 {
155 char str1[256];
156 int n;
157
158 ftp->reply_code = 0;
159 if( res_buf ) {
160 *res_buf = 0;
161 }
162
163 /*
164 * receive 1st line.
165 */
166 if( (n = recv_line( ftp->socket, str1, sizeof(str1), 0 )) < 0 ) {
167 if( errno == EAGAIN ) {
168 return LIBOFTP_ERROR_TIMEOUT;
169 }
170 copy_strerror();
171 return LIBOFTP_ERROR_OS;
172 }
173 DEBUGPRINT1( "RESP1: %s", str1 );
174 if( n < 3 ) {
175 return LIBOFTP_ERROR_PROTOCOL;
176 }
177 ftp->reply_code = atoi( str1 );
178
179 /*
180 * if exist next line, receive all response.
181 */
182 if( str1[3] == '-' ) {
183 while( 1 ) {
184 if( (n = recv_line( ftp->socket, str1, sizeof(str1), 0 )) < 0 ) {
185 if( errno == EAGAIN ) {
186 return LIBOFTP_ERROR_TIMEOUT;
187 }
188 copy_strerror();
189 return LIBOFTP_ERROR_OS;
190 }
191 DEBUGPRINT1( "RESP2: %s", str1 );
192 if( n < 3 ) {
193 return LIBOFTP_ERROR_PROTOCOL;
194 }
195
196 if( atoi(str1) == ftp->reply_code && str1[3] == ' ' ) {
197 break;
198 }
199 }
200 }
201
202 /*
203 * copy a response strings to user buffer, if need
204 */
205 if( res_buf ) {
206 strncpy( res_buf, str1, bufsiz );
207 res_buf[bufsiz-1] = 0;
208 }
209
210 return ftp->reply_code;
211 }
212
213
214
215 /****************************************************************************/
216 /*! 送受信準備 アクティブモード
217 *
218 *@param ftp LIBOFTPへのポインタ。
219 *@param cmd FTPコマンド (ex: RETR, STOR, APPE)
220 *@param fname サーバ上のファイル名
221 *@retval int ソケット, マイナス値ならエラーコード
222 *@note
223 アクティブモードで送受信の際の、以下の3ステートをサポートする。
224 例) 受信時
225 (port open) --> PORT --> RETR
226 */
227 int ftp_getready_active( LIBOFTP *ftp, const char *cmd, const char *fname )
228 {
229 int sock = 0;
230 struct sockaddr_in saddr;
231 int saddr_len;
232 unsigned char *ip, *pt;
233 char str1[256];
234 int res;
235 struct timeval timeout;
236 fd_set rfds, wfds;
237
238 /*
239 * open data port.
240 * (note)
241 * same command port ip and automatic random port.
242 */
243 sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
244 if( sock < 0 ) {
245 DEBUGPRINT1( "getready_active: can't open socket. %s\n", strerror(errno) );
246 goto ERROR_OS;
247 }
248
249 memset( &saddr, 0, sizeof( saddr ) );
250 saddr_len = sizeof( saddr );
251 if( getsockname( ftp->socket, (struct sockaddr *)&saddr, &saddr_len ) < 0 ) {
252 DEBUGPRINT1( "getready_active: can't get control socket name. %s\n", strerror(errno) );
253 goto ERROR_OS;
254 }
255 saddr.sin_port = htons( 0 );
256
257 if( bind( sock, (struct sockaddr *)&saddr, sizeof( saddr ) ) < 0 ) {
258 DEBUGPRINT1( "getready_active: can't bind socket. %s\n", strerror(errno) );
259 goto ERROR_OS;
260 }
261
262 if( listen( sock, 1 ) < 0 ) {
263 DEBUGPRINT1( "getready_active: can't listen socket. %s\n", strerror(errno) );
264 goto ERROR_OS;
265 }
266
267
268 /*
269 * make PORT command.
270 */
271 memset( &saddr, 0, sizeof( saddr ) );
272 saddr_len = sizeof( saddr );
273 if( getsockname( sock, (struct sockaddr *)&saddr, &saddr_len ) < 0 ) {
274 DEBUGPRINT1( "getready_active: can't get data socket name. %s\n", strerror(errno) );
275 goto ERROR_OS;
276 }
277 ip = (unsigned char*)&saddr.sin_addr.s_addr;
278 pt = (unsigned char*)&saddr.sin_port;
279 snprintf( str1, sizeof(str1), "PORT %d,%d,%d,%d,%d,%d\r\n", ip[0], ip[1], ip[2], ip[3], pt[0], pt[1] );
280
281 /*
282 * send PORT command and get status.
283 */
284 if( ftp_send_command( ftp, str1 ) < 0 ) {
285 DEBUGPRINT1( "getready_active: %s command sending error.\n", "PORT" );
286 close( sock );
287 return LIBOFTP_ERROR_OS;
288 }
289 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
290 if( res != 200 ) { /* 200: Command okay. */
291 DEBUGPRINT1( "getready_active: get PORT response code %d\n", res );
292 close( sock );
293 return LIBOFTP_ERROR_PROTOCOL;
294 }
295
296 /*
297 * send ftp command.
298 */
299 if( fname ) {
300 snprintf( str1, sizeof(str1), "%s %s\r\n", cmd, fname );
301 } else {
302 snprintf( str1, sizeof(str1), "%s\r\n", cmd );
303 }
304 if( ftp_send_command( ftp, str1 ) < 0 ) {
305 DEBUGPRINT1( "getready_active: command sending error. %s", str1 );
306 close( sock );
307 return LIBOFTP_ERROR_OS;
308 }
309
310 /*
311 * accept data connection with timeout.
312 */
313 timeout.tv_sec = ftp->timeout_sec;
314 timeout.tv_usec = 0;
315
316 do {
317 FD_ZERO( &rfds );
318 FD_ZERO( &wfds );
319 FD_SET( sock, &rfds );
320 FD_SET( sock, &wfds );
321
322 res = select( sock+1, &rfds, &wfds, 0, &timeout );
323 if( res == 0 ) { /* timeout */
324 DEBUGPRINT1( "getready_active: waiting connection timeout.%s\n", "" );
325 close( sock );
326 strncpy( ftp->error_message, "connection timeout.", sizeof( ftp->error_message )-1 );
327 return LIBOFTP_ERROR_TIMEOUT;
328 }
329 if( res < 0 ) {
330 if( errno == EINTR ) continue;
331 DEBUGPRINT1( "getready_active: select error. %s\n", strerror(errno) );
332 goto ERROR_OS;
333 }
334
335 if( FD_ISSET( sock, &rfds ) || FD_ISSET( sock, &wfds ) ) break;
336 } while( 1 );
337
338 res = accept( sock, (struct sockaddr *)&saddr, &saddr_len );
339 close( sock );
340 if( res < 0 ) {
341 DEBUGPRINT1( "getready_active: socket accept error. %s\n", strerror(errno) );
342 goto ERROR_OS;
343 }
344 sock = res;
345
346 /*
347 * get status.
348 */
349 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
350 if( res != 150 ) { /* 150: File status okay; about to open data connection. */
351 DEBUGPRINT1( "getready_active: get STOR/RETR response code %d\n", res );
352 close( sock );
353 return LIBOFTP_ERROR_PROTOCOL;
354 }
355
356 return sock;
357
358
359 ERROR_OS:
360 copy_strerror();
361 if( sock > 0 ) {
362 close( sock );
363 }
364 return LIBOFTP_ERROR_OS;
365 }
366
367
368
369 /****************************************************************************/
370 /*! 送受信準備 パッシブモード
371 *
372 *@param ftp LIBOFTPへのポインタ。
373 *@param cmd FTPコマンド (ex: RETR, STOR, APPE)
374 *@param fname サーバ上のファイル名
375 *@retval int ソケット, マイナス値ならエラーコード
376 *@note
377 パッシブモードで送受信の際の、以下の3ステートをサポートする。
378 例) 受信時
379 PASV --> RETR --> (port open)
380 */
381 int ftp_getready_pasv( LIBOFTP *ftp, const char *cmd, const char *fname )
382 {
383 char str1[256];
384 int res;
385 char *p;
386 int h1, h2, h3, h4, p1, p2;
387 struct sockaddr_in saddr;
388 int sock;
389 struct timeval tval;
390
391 /*
392 * send "PASV" command and get status.
393 */
394 str1[255] = 0;
395 snprintf( str1, sizeof(str1)-1, "PASV\r\n" );
396 if( ftp_send_command( ftp, str1 ) < 0 ) {
397 return LIBOFTP_ERROR_OS;
398 }
399 res = ftp_receive_response( ftp, str1, sizeof(str1) - 1 );
400 if( res != 227 ) { /* 227: Entering Passive Mode */
401 DEBUGPRINT1( "getready_pasv: get ftp response code %d\n", res );
402 strncpy( ftp->error_message, str1, sizeof( ftp->error_message ) - 1 );
403 return LIBOFTP_ERROR_PROTOCOL;
404 }
405
406 /*
407 * parse (h1,h2,h3,h4,p1,p2)
408 */
409 p = strchr( str1, '(' );
410 if( p == NULL ) {
411 DEBUGPRINT1( "getready_pasv: response parse error. %d", 1 );
412 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
413 return LIBOFTP_ERROR_PROTOCOL;
414 }
415 if( sscanf( p+1, "%d,%d,%d,%d,%d,%d", &h1, &h2, &h3, &h4, &p1, &p2 ) != 6 ) {
416 DEBUGPRINT1( "getready_pasv: response parse error. %d", 2 );
417 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
418 return LIBOFTP_ERROR_PROTOCOL;
419 }
420
421
422 /*
423 * send ftp command.
424 */
425 if( fname ) {
426 snprintf( str1, sizeof(str1), "%s %s\r\n", cmd, fname );
427 } else {
428 snprintf( str1, sizeof(str1), "%s\r\n", cmd );
429 }
430 if( ftp_send_command( ftp, str1 ) < 0 ) {
431 DEBUGPRINT1( "getready_pasv: command sending error. %s", str1 );
432 return LIBOFTP_ERROR_OS;
433 }
434
435 /*
436 * open data port.
437 */
438 sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
439 if( sock < 0 ) {
440 DEBUGPRINT1( "getready_pasv: can't open socket. %s\n", strerror(errno) );
441 copy_strerror();
442 return LIBOFTP_ERROR_OS;
443 }
444
445 memset( &saddr, 0, sizeof( saddr ) );
446 saddr.sin_family = AF_INET;
447 saddr.sin_addr.s_addr = htonl( (((unsigned long)h1) << 24) | (h2 << 16) | (h3 << 8) | h4 );
448 saddr.sin_port = htons( (p1 << 8) | p2 );
449
450 if( connect( sock, (struct sockaddr *)&saddr, sizeof( saddr ) ) < 0 ) {
451 DEBUGPRINT1( "getready_pasv: can't connect socket. %s\n", strerror(errno) );
452 copy_strerror();
453 close( sock );
454 return LIBOFTP_ERROR_OS;
455 }
456
457 tval.tv_sec = ftp->timeout_sec;
458 tval.tv_usec = 0;
459 if( setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(struct timeval) ) < 0 ) {
460 DEBUGPRINT1( "setsockopt(SO_RCVTIMEO) failed. %s\n", strerror(errno) );
461 copy_strerror();
462 close( sock );
463 return LIBOFTP_ERROR_OS;
464 }
465
466 /*
467 * check response.
468 */
469 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
470 if( res == 150 || res == 125 ) {
471 return sock;
472 } else {
473 close( sock );
474 return LIBOFTP_ERROR_PROTOCOL;
475 }
476 }
477
478
479
480 /****************************************************************************/
481 /*! バッファへリスト取得
482 *
483 *@param ftp LIBOFTPへのポインタ。
484 *@param cmd コマンド (RETR|LIST|NLST)
485 *@param fname ファイル名または、グロブ。
486 *@param buf バッファへのポインタ
487 *@param bufsiz バッファサイズ
488 *@retval int 取得したバイト数 マイナス値ならエラーコード
489 *@note
490 */
491 int ftp_get_buffer_main( LIBOFTP *ftp, const char *cmd, const char *fname, char *buf, int bufsiz )
492 {
493 int data_socket;
494 char *p = buf;
495 int res;
496
497 /*
498 * 受信準備
499 */
500 if( ftp->flag_passive ) {
501 data_socket = ftp_getready_pasv( ftp, cmd, fname );
502 } else {
503 data_socket = ftp_getready_active( ftp, cmd, fname );
504 }
505 if( data_socket < 0 ) {
506 return data_socket;
507 }
508
509 /*
510 * タイムアウトが意図通りに働くように、分割してrecvする。
511 */
512 while( 1 ) {
513 int n;
514 int len = bufsiz;
515 if( len > TRANSFER_SEGMENT_SIZE ) {
516 len = TRANSFER_SEGMENT_SIZE;
517 }
518 n = recv( data_socket, p, len, 0 );
519 DEBUGPRINT1( "RECV: n=%d\n", n );
520 if( n < 0 ) {
521 int ret;
522 DEBUGPRINT1( "recv error. %s\n", strerror(errno) );
523 if( errno == EAGAIN ) {
524 ret = LIBOFTP_ERROR_TIMEOUT;
525 } else {
526 ret = LIBOFTP_ERROR_OS;
527 copy_strerror();
528 }
529 close( data_socket );
530 return ret;
531 }
532 if( n == 0 ) {
533 break;
534 }
535 p += n;
536 bufsiz -= n;
537 if( bufsiz <= 0 ) {
538 break; /* buffer too small */
539 }
540 }
541
542 if( bufsiz > 0 ) { /* バッファ不足だったか? */
543 /*
544 * 不足していない
545 */
546 close( data_socket );
547
548 /* receive response. */
549 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message)-1 );
550 if( res != 226 ) { /* 226: Closing data connection. */
551 DEBUGPRINT1( "got illegal response %d\n", res );
552 return res < 0? res: LIBOFTP_ERROR_PROTOCOL;
553 }
554
555 return p - buf; /* return with transfered bytes */
556
557 } else {
558 /*
559 * バッファ不足時
560 */
561 DEBUGPRINT1( "buffer too small. %s\n", "" );
562 strncpy( ftp->error_message, "buffer too small", sizeof( ftp->error_message ) - 1 );
563
564 if( ftp_send_command( ftp, "ABOR\r\n" ) < 0 ) {
565 DEBUGPRINT1( "command sending error. %s\n", "ABOR" );
566 close( data_socket );
567 return LIBOFTP_ERROR_BUFFER;
568 }
569
570 res = ftp_receive_response( ftp, 0, 0 );
571 if( res == 426 ) { /* 426: Connection closed; transfer aborted. */
572 res = ftp_receive_response( ftp, 0, 0 );
573 }
574 close( data_socket );
575 if( res != 226 ) { /* 226: Closing data connection. */
576 DEBUGPRINT1( "got illegal response %d\n", res );
577 return res < 0? res: LIBOFTP_ERROR_PROTOCOL;
578 }
579
580 return LIBOFTP_ERROR_BUFFER;
581 }
582 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26