Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /trunk/sub.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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