Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /trunk/sub.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (hide annotations) (download) (as text)
Sun Mar 1 13:40:55 2009 UTC (15 years, 1 month ago) by hirohitohigashi
File MIME type: text/x-csrc
File size: 12547 byte(s)
added ftp_reset() function and fixed some bugs.

1 hirohitohigashi 17 /*
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 hirohitohigashi 29 #include <stdio.h>
12 hirohitohigashi 17 #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 hirohitohigashi 20 #include <sys/select.h>
21 hirohitohigashi 17
22    
23     /***** Local headers ********************************************************/
24     #include "liboftp.h"
25     #include "sub.h"
26    
27    
28     /***** Constat values *******************************************************/
29     /***** Macros ***************************************************************/
30     /***** Typedefs *************************************************************/
31     /***** Function prototypes **************************************************/
32     /***** Local variables ******************************************************/
33     /***** Global variables *****************************************************/
34     /***** Signal catching functions ********************************************/
35     /***** Local functions ******************************************************/
36     /****************************************************************************/
37     /*! read a line
38     *
39     *@param sd socket descriptor
40     *@param buf pointer of receive buffer
41     *@param bufsiz buffer size
42     *@param flags flags of recv()
43     *@retval int number of bytes received, or -1 if an error.
44     *@note
45     *
46     */
47 hirohitohigashi 29 static int recv_line( int sd, char *buf, int bufsiz, int flags )
48 hirohitohigashi 17 {
49     int n;
50     char c;
51     char *p = buf;
52     int total_len = 0;
53    
54     bufsiz--;
55    
56     while( 1 ) {
57     n = recv( sd, &c, 1, flags );
58     if( n < 0 ) {
59     if( errno == EINTR ) continue;
60     *p = 0;
61     DEBUGPRINT1( "recv_line: get minus. %s\n", strerror(errno) );
62     return n;
63     }
64    
65     *p++ = c;
66     total_len++;
67    
68     if( c == '\n' ) break;
69     if( bufsiz < total_len ) break;
70     }
71     *p = 0;
72    
73     return total_len;
74     }
75    
76    
77    
78 hirohitohigashi 29 /***** Global functions *****************************************************/
79    
80 hirohitohigashi 17 /****************************************************************************/
81 hirohitohigashi 29 /*! send n bytes.
82     *
83     *@param sd socket descriptor
84     *@param buf pointer of send buffer
85     *@param len message length
86     *@param flags flags of send()
87     *@retval int number of bytes sent, or -1 if an error.
88     *@note
89     *
90     */
91     int sendn( int sd, const char *buf, int len, int flags )
92     {
93     int left = len;
94     int n;
95    
96     while( left > 0 ) {
97     n = send( sd, buf, left, flags );
98     if( n < 0 ) {
99     if( errno == EINTR ) continue;
100     DEBUGPRINT1( "sendn: get minus. %s\n", strerror(errno) );
101     return n;
102     }
103     buf += n;
104     left -= n;
105     }
106    
107     return len;
108     }
109    
110    
111    
112     /****************************************************************************/
113 hirohitohigashi 20 /*! send ftp command
114     *
115     *@param ftp pointer of LIBOFTP.
116     *@param cmd ftp command.
117     *@retval int 0 is no error, or -1 if an error.
118     *@note
119     *
120     */
121     int ftp_send_command( LIBOFTP *ftp, const char *cmd )
122     {
123     int ret;
124     DEBUGPRINT1( "SENDC: %s", cmd );
125     ret = sendn( ftp->socket, cmd, strlen( cmd ), 0 );
126     if( ret < 0 ) {
127 hirohitohigashi 29 copy_strerror();
128 hirohitohigashi 20 return ret;
129     }
130    
131     return 0;
132     }
133    
134    
135    
136     /****************************************************************************/
137 hirohitohigashi 17 /*! receive response
138     *
139     *@param ftp pointer of LIBOFTP.
140     *@param res_buf response buffer ( null ok )
141     *@param bufsiz response buffer size.
142 hirohitohigashi 29 *@retval int reply code, or error code (minus value)
143 hirohitohigashi 17 *@note
144 hirohitohigashi 29 * set reply code to ftp attribute reply_code;
145 hirohitohigashi 17 */
146     int ftp_receive_response( LIBOFTP *ftp, char *res_buf, int bufsiz )
147     {
148     char str1[256];
149     int n;
150    
151 hirohitohigashi 29 ftp->reply_code = 0;
152 hirohitohigashi 17 if( res_buf ) {
153     *res_buf = 0;
154     }
155    
156     /*
157     * receive 1st line.
158     */
159     if( (n = recv_line( ftp->socket, str1, sizeof(str1), 0 )) < 0 ) {
160 hirohitohigashi 36 if( errno == EAGAIN ) {
161     return LIBOFTP_ERROR_TIMEOUT;
162     }
163 hirohitohigashi 29 copy_strerror();
164     return LIBOFTP_ERROR_OS;
165 hirohitohigashi 17 }
166     DEBUGPRINT1( "RESP1: %s", str1 );
167     if( n < 3 ) {
168 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
169 hirohitohigashi 17 }
170 hirohitohigashi 29 ftp->reply_code = atoi( str1 );
171 hirohitohigashi 17
172     /*
173     * if exist next line, receive all response.
174     */
175     if( str1[3] == '-' ) {
176     while( 1 ) {
177     if( (n = recv_line( ftp->socket, str1, sizeof(str1), 0 )) < 0 ) {
178 hirohitohigashi 36 if( errno == EAGAIN ) {
179     return LIBOFTP_ERROR_TIMEOUT;
180     }
181 hirohitohigashi 29 copy_strerror();
182     return LIBOFTP_ERROR_OS;
183 hirohitohigashi 17 }
184     DEBUGPRINT1( "RESP2: %s", str1 );
185     if( n < 3 ) {
186 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
187 hirohitohigashi 17 }
188    
189 hirohitohigashi 29 if( atoi(str1) == ftp->reply_code && str1[3] == ' ' ) {
190 hirohitohigashi 17 break;
191     }
192     }
193     }
194    
195     /*
196     * copy a response strings to user buffer, if need
197     */
198     if( res_buf ) {
199     strncpy( res_buf, str1, bufsiz );
200     res_buf[bufsiz-1] = 0;
201     }
202    
203 hirohitohigashi 29 return ftp->reply_code;
204 hirohitohigashi 17 }
205    
206    
207    
208     /****************************************************************************/
209 hirohitohigashi 21 /*! ������������������������������������������
210 hirohitohigashi 17 *
211     *@param ftp LIBOFTP���������������������
212 hirohitohigashi 26 *@param cmd FTP������������ (ex: RETR, STOR, APPE)
213 hirohitohigashi 17 *@param fname ������������������������������
214 hirohitohigashi 30 *@retval int ������������, ���������������������������������������
215 hirohitohigashi 17 *@note
216 hirohitohigashi 21 ������������������������������������������������������������������������������������������������
217 hirohitohigashi 17 ���) ���������
218 hirohitohigashi 21 (port open) --> PORT --> RETR
219 hirohitohigashi 17 */
220 hirohitohigashi 26 int ftp_getready_active( LIBOFTP *ftp, const char *cmd, const char *fname )
221 hirohitohigashi 20 {
222 hirohitohigashi 29 int sock = 0;
223 hirohitohigashi 20 struct sockaddr_in saddr;
224     int saddr_len;
225     unsigned char *ip, *pt;
226     char str1[256];
227     int res;
228     struct timeval timeout;
229     fd_set rfds, wfds;
230    
231     /*
232     * open data port.
233     * (note)
234     * same command port ip and automatic random port.
235     */
236     sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
237     if( sock < 0 ) {
238     DEBUGPRINT1( "getready_active: can't open socket. %s\n", strerror(errno) );
239 hirohitohigashi 29 goto ERROR_OS;
240 hirohitohigashi 20 }
241    
242     memset( &saddr, 0, sizeof( saddr ) );
243     saddr_len = sizeof( saddr );
244     if( getsockname( ftp->socket, (struct sockaddr *)&saddr, &saddr_len ) < 0 ) {
245     DEBUGPRINT1( "getready_active: can't get control socket name. %s\n", strerror(errno) );
246 hirohitohigashi 29 goto ERROR_OS;
247 hirohitohigashi 20 }
248     saddr.sin_port = htons( 0 );
249    
250     if( bind( sock, (struct sockaddr *)&saddr, sizeof( saddr ) ) < 0 ) {
251     DEBUGPRINT1( "getready_active: can't bind socket. %s\n", strerror(errno) );
252 hirohitohigashi 29 goto ERROR_OS;
253 hirohitohigashi 20 }
254    
255     if( listen( sock, 1 ) < 0 ) {
256     DEBUGPRINT1( "getready_active: can't listen socket. %s\n", strerror(errno) );
257 hirohitohigashi 29 goto ERROR_OS;
258 hirohitohigashi 20 }
259    
260    
261     /*
262     * make PORT command.
263     */
264     memset( &saddr, 0, sizeof( saddr ) );
265     saddr_len = sizeof( saddr );
266     if( getsockname( sock, (struct sockaddr *)&saddr, &saddr_len ) < 0 ) {
267     DEBUGPRINT1( "getready_active: can't get data socket name. %s\n", strerror(errno) );
268 hirohitohigashi 29 goto ERROR_OS;
269 hirohitohigashi 20 }
270     ip = (unsigned char*)&saddr.sin_addr.s_addr;
271     pt = (unsigned char*)&saddr.sin_port;
272     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] );
273    
274     /*
275     * send PORT command and get status.
276     */
277     if( ftp_send_command( ftp, str1 ) < 0 ) {
278 hirohitohigashi 29 DEBUGPRINT1( "getready_active: %s command sending error.\n", "PORT" );
279 hirohitohigashi 20 close( sock );
280 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
281 hirohitohigashi 20 }
282 hirohitohigashi 29 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
283 hirohitohigashi 20 if( res != 200 ) { /* 200: Command okay. */
284     DEBUGPRINT1( "getready_active: get PORT response code %d\n", res );
285     close( sock );
286 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
287 hirohitohigashi 20 }
288    
289     /*
290     * send ftp command.
291     */
292 hirohitohigashi 26 if( fname ) {
293     snprintf( str1, sizeof(str1), "%s %s\r\n", cmd, fname );
294     } else {
295     snprintf( str1, sizeof(str1), "%s\r\n", cmd );
296     }
297 hirohitohigashi 20 if( ftp_send_command( ftp, str1 ) < 0 ) {
298 hirohitohigashi 29 DEBUGPRINT1( "getready_active: %s command sending error.\n", cmd );
299 hirohitohigashi 20 close( sock );
300 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
301 hirohitohigashi 20 }
302    
303     /*
304     * accept data connection with timeout.
305     */
306     timeout.tv_sec = ftp->timeout_sec;
307     timeout.tv_usec = 0;
308    
309 hirohitohigashi 28 do {
310     FD_ZERO( &rfds );
311     FD_ZERO( &wfds );
312     FD_SET( sock, &rfds );
313     FD_SET( sock, &wfds );
314    
315     res = select( sock+1, &rfds, &wfds, 0, &timeout );
316     if( res == 0 ) { /* timeout */
317     DEBUGPRINT1( "getready_active: waiting connection timeout.%s\n", "" );
318     close( sock );
319 hirohitohigashi 29 strncpy( ftp->error_message, "connection timeout.", sizeof( ftp->error_message )-1 );
320     return LIBOFTP_ERROR_TIMEOUT;
321 hirohitohigashi 28 }
322     if( res < 0 ) {
323     if( errno == EINTR ) continue;
324     DEBUGPRINT1( "getready_active: select error. %s\n", strerror(errno) );
325 hirohitohigashi 29 goto ERROR_OS;
326 hirohitohigashi 28 }
327    
328     if( FD_ISSET( sock, &rfds ) || FD_ISSET( sock, &wfds ) ) break;
329     } while( 1 );
330    
331 hirohitohigashi 20 res = accept( sock, (struct sockaddr *)&saddr, &saddr_len );
332     close( sock );
333     if( res < 0 ) {
334     DEBUGPRINT1( "getready_active: socket accept error. %s\n", strerror(errno) );
335 hirohitohigashi 29 goto ERROR_OS;
336 hirohitohigashi 20 }
337     sock = res;
338    
339     /*
340     * get status.
341     */
342 hirohitohigashi 29 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
343 hirohitohigashi 20 if( res != 150 ) { /* 150: File status okay; about to open data connection. */
344     DEBUGPRINT1( "getready_active: get STOR/RETR response code %d\n", res );
345     close( sock );
346 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
347 hirohitohigashi 20 }
348    
349 hirohitohigashi 29 return sock;
350 hirohitohigashi 20
351 hirohitohigashi 29
352     ERROR_OS:
353     copy_strerror();
354     if( sock > 0 ) {
355     close( sock );
356     }
357     return LIBOFTP_ERROR_OS;
358 hirohitohigashi 20 }
359 hirohitohigashi 21
360    
361    
362     /****************************************************************************/
363     /*! ���������������������������������������
364     *
365     *@param ftp LIBOFTP���������������������
366 hirohitohigashi 26 *@param cmd FTP������������ (ex: RETR, STOR, APPE)
367 hirohitohigashi 21 *@param fname ������������������������������
368 hirohitohigashi 30 *@retval int ������������, ���������������������������������������
369 hirohitohigashi 21 *@note
370     ���������������������������������������������������������������������������������������������
371     ���) ���������
372     PASV --> RETR --> (port open)
373     */
374 hirohitohigashi 26 int ftp_getready_pasv( LIBOFTP *ftp, const char *cmd, const char *fname )
375 hirohitohigashi 21 {
376     char str1[256];
377     int res;
378     char *p;
379     int h1, h2, h3, h4, p1, p2;
380     struct sockaddr_in saddr;
381     int sock;
382 hirohitohigashi 29 struct timeval tval;
383 hirohitohigashi 21
384     /*
385     * send "PASV" command and get status.
386     */
387     str1[255] = 0;
388     snprintf( str1, sizeof(str1)-1, "PASV\r\n" );
389     if( ftp_send_command( ftp, str1 ) < 0 ) {
390 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
391 hirohitohigashi 21 }
392 hirohitohigashi 29 res = ftp_receive_response( ftp, str1, sizeof(str1) - 1 );
393 hirohitohigashi 21 if( res != 227 ) { /* 227: Entering Passive Mode */
394     DEBUGPRINT1( "getready_pasv: get ftp response code %d\n", res );
395 hirohitohigashi 29 strncpy( ftp->error_message, str1, sizeof( ftp->error_message ) - 1 );
396     return LIBOFTP_ERROR_PROTOCOL;
397 hirohitohigashi 21 }
398    
399     /*
400     * parse (h1,h2,h3,h4,p1,p2)
401     */
402     p = strchr( str1, '(' );
403     if( p == NULL ) {
404     DEBUGPRINT1( "getready_pasv: response parse error. %d", 1 );
405 hirohitohigashi 29 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
406     return LIBOFTP_ERROR_PROTOCOL;
407 hirohitohigashi 21 }
408     if( sscanf( p+1, "%d,%d,%d,%d,%d,%d", &h1, &h2, &h3, &h4, &p1, &p2 ) != 6 ) {
409     DEBUGPRINT1( "getready_pasv: response parse error. %d", 2 );
410 hirohitohigashi 29 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
411     return LIBOFTP_ERROR_PROTOCOL;
412 hirohitohigashi 21 }
413    
414    
415     /*
416     * send ftp command.
417     */
418 hirohitohigashi 26 if( fname ) {
419     snprintf( str1, sizeof(str1), "%s %s\r\n", cmd, fname );
420     } else {
421     snprintf( str1, sizeof(str1), "%s\r\n", cmd );
422     }
423 hirohitohigashi 21 if( ftp_send_command( ftp, str1 ) < 0 ) {
424 hirohitohigashi 29 DEBUGPRINT1( "getready_pasv: command sending error. %s\n", str1 );
425     return LIBOFTP_ERROR_OS;
426 hirohitohigashi 21 }
427    
428     /*
429     * open data port.
430     */
431     sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
432     if( sock < 0 ) {
433     DEBUGPRINT1( "getready_pasv: can't open socket. %s\n", strerror(errno) );
434 hirohitohigashi 29 copy_strerror();
435     return LIBOFTP_ERROR_OS;
436 hirohitohigashi 21 }
437    
438     memset( &saddr, 0, sizeof( saddr ) );
439     saddr.sin_family = AF_INET;
440     saddr.sin_addr.s_addr = htonl( (((unsigned long)h1) << 24) | (h2 << 16) | (h3 << 8) | h4 );
441     saddr.sin_port = htons( (p1 << 8) | p2 );
442    
443     if( connect( sock, (struct sockaddr *)&saddr, sizeof( saddr ) ) < 0 ) {
444     DEBUGPRINT1( "getready_pasv: can't connect socket. %s\n", strerror(errno) );
445 hirohitohigashi 29 copy_strerror();
446 hirohitohigashi 21 close( sock );
447 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
448 hirohitohigashi 21 }
449 hirohitohigashi 29
450     tval.tv_sec = ftp->timeout_sec;
451     tval.tv_usec = 0;
452     if( setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(struct timeval) ) < 0 ) {
453     DEBUGPRINT1( "setsockopt(SO_RCVTIMEO) failed. %s\n", strerror(errno) );
454     copy_strerror();
455     close( sock );
456     return LIBOFTP_ERROR_OS;
457     }
458 hirohitohigashi 21
459     /*
460     * check response.
461     */
462 hirohitohigashi 29 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
463 hirohitohigashi 21 if( res == 150 || res == 125 ) {
464     return sock;
465     } else {
466     close( sock );
467 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
468 hirohitohigashi 21 }
469     }

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