Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /trunk/sub.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (hide annotations) (download) (as text)
Sat Feb 28 13:03:02 2009 UTC (15 years, 1 month ago) by hirohitohigashi
File MIME type: text/x-csrc
File size: 12418 byte(s)
revised comments.

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 29 copy_strerror();
161     return LIBOFTP_ERROR_OS;
162 hirohitohigashi 17 }
163     DEBUGPRINT1( "RESP1: %s", str1 );
164     if( n < 3 ) {
165 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
166 hirohitohigashi 17 }
167 hirohitohigashi 29 ftp->reply_code = atoi( str1 );
168 hirohitohigashi 17
169     /*
170     * if exist next line, receive all response.
171     */
172     if( str1[3] == '-' ) {
173     while( 1 ) {
174     if( (n = recv_line( ftp->socket, str1, sizeof(str1), 0 )) < 0 ) {
175 hirohitohigashi 29 copy_strerror();
176     return LIBOFTP_ERROR_OS;
177 hirohitohigashi 17 }
178     DEBUGPRINT1( "RESP2: %s", str1 );
179     if( n < 3 ) {
180 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
181 hirohitohigashi 17 }
182    
183 hirohitohigashi 29 if( atoi(str1) == ftp->reply_code && str1[3] == ' ' ) {
184 hirohitohigashi 17 break;
185     }
186     }
187     }
188    
189     /*
190     * copy a response strings to user buffer, if need
191     */
192     if( res_buf ) {
193     strncpy( res_buf, str1, bufsiz );
194     res_buf[bufsiz-1] = 0;
195     }
196    
197 hirohitohigashi 29 return ftp->reply_code;
198 hirohitohigashi 17 }
199    
200    
201    
202     /****************************************************************************/
203 hirohitohigashi 21 /*! ������������������������������������������
204 hirohitohigashi 17 *
205     *@param ftp LIBOFTP���������������������
206 hirohitohigashi 26 *@param cmd FTP������������ (ex: RETR, STOR, APPE)
207 hirohitohigashi 17 *@param fname ������������������������������
208 hirohitohigashi 30 *@retval int ������������, ���������������������������������������
209 hirohitohigashi 17 *@note
210 hirohitohigashi 21 ������������������������������������������������������������������������������������������������
211 hirohitohigashi 17 ���) ���������
212 hirohitohigashi 21 (port open) --> PORT --> RETR
213 hirohitohigashi 17 */
214 hirohitohigashi 26 int ftp_getready_active( LIBOFTP *ftp, const char *cmd, const char *fname )
215 hirohitohigashi 20 {
216 hirohitohigashi 29 int sock = 0;
217 hirohitohigashi 20 struct sockaddr_in saddr;
218     int saddr_len;
219     unsigned char *ip, *pt;
220     char str1[256];
221     int res;
222     struct timeval timeout;
223     fd_set rfds, wfds;
224    
225     /*
226     * open data port.
227     * (note)
228     * same command port ip and automatic random port.
229     */
230     sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
231     if( sock < 0 ) {
232     DEBUGPRINT1( "getready_active: can't open socket. %s\n", strerror(errno) );
233 hirohitohigashi 29 goto ERROR_OS;
234 hirohitohigashi 20 }
235    
236     memset( &saddr, 0, sizeof( saddr ) );
237     saddr_len = sizeof( saddr );
238     if( getsockname( ftp->socket, (struct sockaddr *)&saddr, &saddr_len ) < 0 ) {
239     DEBUGPRINT1( "getready_active: can't get control socket name. %s\n", strerror(errno) );
240 hirohitohigashi 29 goto ERROR_OS;
241 hirohitohigashi 20 }
242     saddr.sin_port = htons( 0 );
243    
244     if( bind( sock, (struct sockaddr *)&saddr, sizeof( saddr ) ) < 0 ) {
245     DEBUGPRINT1( "getready_active: can't bind socket. %s\n", strerror(errno) );
246 hirohitohigashi 29 goto ERROR_OS;
247 hirohitohigashi 20 }
248    
249     if( listen( sock, 1 ) < 0 ) {
250     DEBUGPRINT1( "getready_active: can't listen socket. %s\n", strerror(errno) );
251 hirohitohigashi 29 goto ERROR_OS;
252 hirohitohigashi 20 }
253    
254    
255     /*
256     * make PORT command.
257     */
258     memset( &saddr, 0, sizeof( saddr ) );
259     saddr_len = sizeof( saddr );
260     if( getsockname( sock, (struct sockaddr *)&saddr, &saddr_len ) < 0 ) {
261     DEBUGPRINT1( "getready_active: can't get data socket name. %s\n", strerror(errno) );
262 hirohitohigashi 29 goto ERROR_OS;
263 hirohitohigashi 20 }
264     ip = (unsigned char*)&saddr.sin_addr.s_addr;
265     pt = (unsigned char*)&saddr.sin_port;
266     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] );
267    
268     /*
269     * send PORT command and get status.
270     */
271     if( ftp_send_command( ftp, str1 ) < 0 ) {
272 hirohitohigashi 29 DEBUGPRINT1( "getready_active: %s command sending error.\n", "PORT" );
273 hirohitohigashi 20 close( sock );
274 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
275 hirohitohigashi 20 }
276 hirohitohigashi 29 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
277 hirohitohigashi 20 if( res != 200 ) { /* 200: Command okay. */
278     DEBUGPRINT1( "getready_active: get PORT response code %d\n", res );
279     close( sock );
280 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
281 hirohitohigashi 20 }
282    
283     /*
284     * send ftp command.
285     */
286 hirohitohigashi 26 if( fname ) {
287     snprintf( str1, sizeof(str1), "%s %s\r\n", cmd, fname );
288     } else {
289     snprintf( str1, sizeof(str1), "%s\r\n", cmd );
290     }
291 hirohitohigashi 20 if( ftp_send_command( ftp, str1 ) < 0 ) {
292 hirohitohigashi 29 DEBUGPRINT1( "getready_active: %s command sending error.\n", cmd );
293 hirohitohigashi 20 close( sock );
294 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
295 hirohitohigashi 20 }
296    
297     /*
298     * accept data connection with timeout.
299     */
300     timeout.tv_sec = ftp->timeout_sec;
301     timeout.tv_usec = 0;
302    
303 hirohitohigashi 28 do {
304     FD_ZERO( &rfds );
305     FD_ZERO( &wfds );
306     FD_SET( sock, &rfds );
307     FD_SET( sock, &wfds );
308    
309     res = select( sock+1, &rfds, &wfds, 0, &timeout );
310     if( res == 0 ) { /* timeout */
311     DEBUGPRINT1( "getready_active: waiting connection timeout.%s\n", "" );
312     close( sock );
313 hirohitohigashi 29 strncpy( ftp->error_message, "connection timeout.", sizeof( ftp->error_message )-1 );
314     return LIBOFTP_ERROR_TIMEOUT;
315 hirohitohigashi 28 }
316     if( res < 0 ) {
317     if( errno == EINTR ) continue;
318     DEBUGPRINT1( "getready_active: select error. %s\n", strerror(errno) );
319 hirohitohigashi 29 goto ERROR_OS;
320 hirohitohigashi 28 }
321    
322     if( FD_ISSET( sock, &rfds ) || FD_ISSET( sock, &wfds ) ) break;
323     } while( 1 );
324    
325 hirohitohigashi 20 res = accept( sock, (struct sockaddr *)&saddr, &saddr_len );
326     close( sock );
327     if( res < 0 ) {
328     DEBUGPRINT1( "getready_active: socket accept error. %s\n", strerror(errno) );
329 hirohitohigashi 29 goto ERROR_OS;
330 hirohitohigashi 20 }
331     sock = res;
332    
333     /*
334     * get status.
335     */
336 hirohitohigashi 29 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
337 hirohitohigashi 20 if( res != 150 ) { /* 150: File status okay; about to open data connection. */
338     DEBUGPRINT1( "getready_active: get STOR/RETR response code %d\n", res );
339     close( sock );
340 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
341 hirohitohigashi 20 }
342    
343 hirohitohigashi 29 return sock;
344 hirohitohigashi 20
345 hirohitohigashi 29
346     ERROR_OS:
347     copy_strerror();
348     if( sock > 0 ) {
349     close( sock );
350     }
351     return LIBOFTP_ERROR_OS;
352 hirohitohigashi 20 }
353 hirohitohigashi 21
354    
355    
356     /****************************************************************************/
357     /*! ���������������������������������������
358     *
359     *@param ftp LIBOFTP���������������������
360 hirohitohigashi 26 *@param cmd FTP������������ (ex: RETR, STOR, APPE)
361 hirohitohigashi 21 *@param fname ������������������������������
362 hirohitohigashi 30 *@retval int ������������, ���������������������������������������
363 hirohitohigashi 21 *@note
364     ���������������������������������������������������������������������������������������������
365     ���) ���������
366     PASV --> RETR --> (port open)
367     */
368 hirohitohigashi 26 int ftp_getready_pasv( LIBOFTP *ftp, const char *cmd, const char *fname )
369 hirohitohigashi 21 {
370     char str1[256];
371     int res;
372     char *p;
373     int h1, h2, h3, h4, p1, p2;
374     struct sockaddr_in saddr;
375     int sock;
376 hirohitohigashi 29 struct timeval tval;
377 hirohitohigashi 21
378     /*
379     * send "PASV" command and get status.
380     */
381     str1[255] = 0;
382     snprintf( str1, sizeof(str1)-1, "PASV\r\n" );
383     if( ftp_send_command( ftp, str1 ) < 0 ) {
384 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
385 hirohitohigashi 21 }
386 hirohitohigashi 29 res = ftp_receive_response( ftp, str1, sizeof(str1) - 1 );
387 hirohitohigashi 21 if( res != 227 ) { /* 227: Entering Passive Mode */
388     DEBUGPRINT1( "getready_pasv: get ftp response code %d\n", res );
389 hirohitohigashi 29 strncpy( ftp->error_message, str1, sizeof( ftp->error_message ) - 1 );
390     return LIBOFTP_ERROR_PROTOCOL;
391 hirohitohigashi 21 }
392    
393     /*
394     * parse (h1,h2,h3,h4,p1,p2)
395     */
396     p = strchr( str1, '(' );
397     if( p == NULL ) {
398     DEBUGPRINT1( "getready_pasv: response parse error. %d", 1 );
399 hirohitohigashi 29 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
400     return LIBOFTP_ERROR_PROTOCOL;
401 hirohitohigashi 21 }
402     if( sscanf( p+1, "%d,%d,%d,%d,%d,%d", &h1, &h2, &h3, &h4, &p1, &p2 ) != 6 ) {
403     DEBUGPRINT1( "getready_pasv: response parse error. %d", 2 );
404 hirohitohigashi 29 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
405     return LIBOFTP_ERROR_PROTOCOL;
406 hirohitohigashi 21 }
407    
408    
409     /*
410     * send ftp command.
411     */
412 hirohitohigashi 26 if( fname ) {
413     snprintf( str1, sizeof(str1), "%s %s\r\n", cmd, fname );
414     } else {
415     snprintf( str1, sizeof(str1), "%s\r\n", cmd );
416     }
417 hirohitohigashi 21 if( ftp_send_command( ftp, str1 ) < 0 ) {
418 hirohitohigashi 29 DEBUGPRINT1( "getready_pasv: command sending error. %s\n", str1 );
419     return LIBOFTP_ERROR_OS;
420 hirohitohigashi 21 }
421    
422     /*
423     * open data port.
424     */
425     sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
426     if( sock < 0 ) {
427     DEBUGPRINT1( "getready_pasv: can't open socket. %s\n", strerror(errno) );
428 hirohitohigashi 29 copy_strerror();
429     return LIBOFTP_ERROR_OS;
430 hirohitohigashi 21 }
431    
432     memset( &saddr, 0, sizeof( saddr ) );
433     saddr.sin_family = AF_INET;
434     saddr.sin_addr.s_addr = htonl( (((unsigned long)h1) << 24) | (h2 << 16) | (h3 << 8) | h4 );
435     saddr.sin_port = htons( (p1 << 8) | p2 );
436    
437     if( connect( sock, (struct sockaddr *)&saddr, sizeof( saddr ) ) < 0 ) {
438     DEBUGPRINT1( "getready_pasv: can't connect socket. %s\n", strerror(errno) );
439 hirohitohigashi 29 copy_strerror();
440 hirohitohigashi 21 close( sock );
441 hirohitohigashi 29 return LIBOFTP_ERROR_OS;
442 hirohitohigashi 21 }
443 hirohitohigashi 29
444     tval.tv_sec = ftp->timeout_sec;
445     tval.tv_usec = 0;
446     if( setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(struct timeval) ) < 0 ) {
447     DEBUGPRINT1( "setsockopt(SO_RCVTIMEO) failed. %s\n", strerror(errno) );
448     copy_strerror();
449     close( sock );
450     return LIBOFTP_ERROR_OS;
451     }
452 hirohitohigashi 21
453     /*
454     * check response.
455     */
456 hirohitohigashi 29 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
457 hirohitohigashi 21 if( res == 150 || res == 125 ) {
458     return sock;
459     } else {
460     close( sock );
461 hirohitohigashi 29 return LIBOFTP_ERROR_PROTOCOL;
462 hirohitohigashi 21 }
463     }

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