Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/sub.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show 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 /*
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 /***** 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 static int recv_line( int sd, char *buf, int bufsiz, int flags )
48 {
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 /***** Global functions *****************************************************/
79
80 /****************************************************************************/
81 /*! 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 /*! 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 copy_strerror();
128 return ret;
129 }
130
131 return 0;
132 }
133
134
135
136 /****************************************************************************/
137 /*! receive response
138 *
139 *@param ftp pointer of LIBOFTP.
140 *@param res_buf response buffer ( null ok )
141 *@param bufsiz response buffer size.
142 *@retval int reply code, or error code (minus value)
143 *@note
144 * set reply code to ftp attribute reply_code;
145 */
146 int ftp_receive_response( LIBOFTP *ftp, char *res_buf, int bufsiz )
147 {
148 char str1[256];
149 int n;
150
151 ftp->reply_code = 0;
152 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 if( errno == EAGAIN ) {
161 return LIBOFTP_ERROR_TIMEOUT;
162 }
163 copy_strerror();
164 return LIBOFTP_ERROR_OS;
165 }
166 DEBUGPRINT1( "RESP1: %s", str1 );
167 if( n < 3 ) {
168 return LIBOFTP_ERROR_PROTOCOL;
169 }
170 ftp->reply_code = atoi( str1 );
171
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 if( errno == EAGAIN ) {
179 return LIBOFTP_ERROR_TIMEOUT;
180 }
181 copy_strerror();
182 return LIBOFTP_ERROR_OS;
183 }
184 DEBUGPRINT1( "RESP2: %s", str1 );
185 if( n < 3 ) {
186 return LIBOFTP_ERROR_PROTOCOL;
187 }
188
189 if( atoi(str1) == ftp->reply_code && str1[3] == ' ' ) {
190 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 return ftp->reply_code;
204 }
205
206
207
208 /****************************************************************************/
209 /*! ������������������������������������������
210 *
211 *@param ftp LIBOFTP���������������������
212 *@param cmd FTP������������ (ex: RETR, STOR, APPE)
213 *@param fname ������������������������������
214 *@retval int ������������, ���������������������������������������
215 *@note
216 ������������������������������������������������������������������������������������������������
217 ���) ���������
218 (port open) --> PORT --> RETR
219 */
220 int ftp_getready_active( LIBOFTP *ftp, const char *cmd, const char *fname )
221 {
222 int sock = 0;
223 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 goto ERROR_OS;
240 }
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 goto ERROR_OS;
247 }
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 goto ERROR_OS;
253 }
254
255 if( listen( sock, 1 ) < 0 ) {
256 DEBUGPRINT1( "getready_active: can't listen socket. %s\n", strerror(errno) );
257 goto ERROR_OS;
258 }
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 goto ERROR_OS;
269 }
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 DEBUGPRINT1( "getready_active: %s command sending error.\n", "PORT" );
279 close( sock );
280 return LIBOFTP_ERROR_OS;
281 }
282 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
283 if( res != 200 ) { /* 200: Command okay. */
284 DEBUGPRINT1( "getready_active: get PORT response code %d\n", res );
285 close( sock );
286 return LIBOFTP_ERROR_PROTOCOL;
287 }
288
289 /*
290 * send ftp command.
291 */
292 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 if( ftp_send_command( ftp, str1 ) < 0 ) {
298 DEBUGPRINT1( "getready_active: %s command sending error.\n", cmd );
299 close( sock );
300 return LIBOFTP_ERROR_OS;
301 }
302
303 /*
304 * accept data connection with timeout.
305 */
306 timeout.tv_sec = ftp->timeout_sec;
307 timeout.tv_usec = 0;
308
309 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 strncpy( ftp->error_message, "connection timeout.", sizeof( ftp->error_message )-1 );
320 return LIBOFTP_ERROR_TIMEOUT;
321 }
322 if( res < 0 ) {
323 if( errno == EINTR ) continue;
324 DEBUGPRINT1( "getready_active: select error. %s\n", strerror(errno) );
325 goto ERROR_OS;
326 }
327
328 if( FD_ISSET( sock, &rfds ) || FD_ISSET( sock, &wfds ) ) break;
329 } while( 1 );
330
331 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 goto ERROR_OS;
336 }
337 sock = res;
338
339 /*
340 * get status.
341 */
342 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
343 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 return LIBOFTP_ERROR_PROTOCOL;
347 }
348
349 return sock;
350
351
352 ERROR_OS:
353 copy_strerror();
354 if( sock > 0 ) {
355 close( sock );
356 }
357 return LIBOFTP_ERROR_OS;
358 }
359
360
361
362 /****************************************************************************/
363 /*! ���������������������������������������
364 *
365 *@param ftp LIBOFTP���������������������
366 *@param cmd FTP������������ (ex: RETR, STOR, APPE)
367 *@param fname ������������������������������
368 *@retval int ������������, ���������������������������������������
369 *@note
370 ���������������������������������������������������������������������������������������������
371 ���) ���������
372 PASV --> RETR --> (port open)
373 */
374 int ftp_getready_pasv( LIBOFTP *ftp, const char *cmd, const char *fname )
375 {
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 struct timeval tval;
383
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 return LIBOFTP_ERROR_OS;
391 }
392 res = ftp_receive_response( ftp, str1, sizeof(str1) - 1 );
393 if( res != 227 ) { /* 227: Entering Passive Mode */
394 DEBUGPRINT1( "getready_pasv: get ftp response code %d\n", res );
395 strncpy( ftp->error_message, str1, sizeof( ftp->error_message ) - 1 );
396 return LIBOFTP_ERROR_PROTOCOL;
397 }
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 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
406 return LIBOFTP_ERROR_PROTOCOL;
407 }
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 strncpy( ftp->error_message, "Illegal pasv response", sizeof(ftp->error_message) - 1 );
411 return LIBOFTP_ERROR_PROTOCOL;
412 }
413
414
415 /*
416 * send ftp command.
417 */
418 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 if( ftp_send_command( ftp, str1 ) < 0 ) {
424 DEBUGPRINT1( "getready_pasv: command sending error. %s\n", str1 );
425 return LIBOFTP_ERROR_OS;
426 }
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 copy_strerror();
435 return LIBOFTP_ERROR_OS;
436 }
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 copy_strerror();
446 close( sock );
447 return LIBOFTP_ERROR_OS;
448 }
449
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
459 /*
460 * check response.
461 */
462 res = ftp_receive_response( ftp, ftp->error_message, sizeof(ftp->error_message) - 1 );
463 if( res == 150 || res == 125 ) {
464 return sock;
465 } else {
466 close( sock );
467 return LIBOFTP_ERROR_PROTOCOL;
468 }
469 }

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