3 * Copyright (C) 2002 Florin Malita <mali@go.ro>
5 * This file is part of LUFS, a free userspace filesystem implementation.
6 * See http://lufs.sourceforge.net/ for updates.
8 * LUFS is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * LUFS is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <sys/types.h>
29 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
41 FTPConnection::FTPConnection(int act, char *h, unsigned short p, char *u, char *pw){
42 TRACE("in constructor");
48 last_cmd = string("");
54 FTPConnection::~FTPConnection(){
55 TRACE("in destructor");
60 FTPConnection::disconnect(){
75 FTPConnection::connect(){
77 struct sockaddr_in addr;
82 if(!(hst = gethostbyname(host.c_str()))){
83 ERROR("could not resolve host " << host);
87 if((csock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
88 ERROR("socket call failed!");
93 memset(&addr, 0, sizeof(struct sockaddr_in));
94 addr.sin_family = AF_INET;
95 addr.sin_port = htons(port);
97 for(i = 0; hst->h_addr_list[i]; i++){
98 memcpy(&addr.sin_addr.s_addr, hst->h_addr_list[i], 4);
100 TRACE("trying to connect to "<<inet_ntoa(*(struct in_addr*)hst->h_addr_list[i])<<"...");
101 if(!::connect(csock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))){
102 TRACE("connect succeded...");
107 if(! hst->h_addr_list[i]){
108 ERROR("could not connect to server!");
112 if(!(cfd = fdopen(csock, "r+"))){
113 WARN("could not create filestream!");
117 if(get_response() != 220){
118 WARN("protocol error!");
122 if(execute(string("USER ") + user, 0, 0) < 0){
123 WARN("USER failed!");
127 res = get_response();
129 if((res < 0) || ((res != 331) && (res != 230))){
130 WARN("invalid user!");
134 if((res == 331) && (execute(string("PASS ") + pass, 230, 0) < 0)){
135 WARN("login failed!");
139 if((res = execute(string("SYST"), 0, 0)) < 0){
140 WARN("SYST command failed!");
144 if(! fgets(buf, FTP_MAXLINE, cfd)){
145 WARN("no response to SYST!");
149 if((sscanf(buf, "%u %32s", &res, system) != 2) || (res != 215)){
150 WARN("bad response to SYST!");
156 TRACE("logged in. system type is " << system << ".");
166 FTPConnection::get_response(){
168 unsigned multiline = 0;
173 if(!fgets(buf, FTP_MAXLINE, cfd)){
174 WARN("broken control socket!");
178 TRACE("line: " << buf);
181 if(!sscanf(buf, "%u-", &multiline)){
182 WARN("bad response!");
185 TRACE("multiline: " << multiline);
190 if(!fgets(buf, FTP_MAXLINE, cfd)){
191 WARN("broken control socket!");
195 TRACE("line: " << buf);
198 sscanf(buf, "%u ", &res);
199 }while((unsigned)res != multiline);
201 else if(!sscanf(buf, "%u", &res)){
202 WARN("bad response!");
210 FTPConnection::close_data(){
219 return get_response();
226 FTPConnection::execute_retry(string cmd, int r, int reconnect){
230 res = execute(cmd, r, reconnect);
231 }while((res == -EAGAIN) && (tries++ < FTP_MAXTRIES));
237 FTPConnection::execute(string cmd, int r, int reconnect){
243 if((!reconnect) || (connect() < 0)){
244 WARN("could not connect!");
248 TRACE("executing " << cmd);
252 if((res = fwrite(cmd.c_str(), 1, cmd.size(), cfd)) != (int)cmd.size() || (fflush(cfd))){
253 WARN("write error!");
254 if((!reconnect) || ((res = connect()) < 0)){
255 WARN("could not reconnect!");
261 if((res = get_response()) != r){
262 WARN("command failed!");
263 if((reconnect) && ((res < 0) || (res == 421))){
264 if((res = connect()) < 0)
277 FTPConnection::execute_open(string cmd, string type, long long offset){
279 if((!csock) || (!cfd)){
280 TRACE("control socket not connected.");
287 return execute_open_active(cmd, type, offset);
289 return execute_open_passive(cmd, type, offset);
293 FTPConnection::execute_open_active(string cmd, string type, long long offset){
294 struct sockaddr_in addr, ctrl;
295 int res, ssock, tries = 0;
298 if((dsock == 0) || (dfd == NULL) || (offset != last_off) || (cmd != last_cmd)){
302 if(tries++ > FTP_MAXTRIES){
303 WARN("too many failures!");
308 memset(&addr, 0, sizeof(struct sockaddr_in));
309 addr.sin_addr.s_addr = INADDR_ANY;
311 addr.sin_family = AF_INET;
313 if((ssock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
314 WARN("socket call failed!");
318 if((res = bind(ssock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) < 0){
319 WARN("bind call failed!");
324 if((res = listen(ssock, 2)) < 0){
325 WARN("listen call failed!");
330 res = sizeof(struct sockaddr_in);
331 if((res = getsockname(csock, (struct sockaddr*)&ctrl, (socklen_t*)&res)) < 0){
332 WARN("getsockname call failed!");
337 res = sizeof(struct sockaddr_in);
338 if((res = getsockname(ssock, (struct sockaddr*)&addr, (socklen_t*)&res)) < 0){
339 WARN("getsockname call failed!");
344 sprintf(buf, "PORT %u,%u,%u,%u,%u,%u",
345 ctrl.sin_addr.s_addr & 0xff,
346 (ctrl.sin_addr.s_addr >> 8) & 0xff,
347 (ctrl.sin_addr.s_addr >> 16) & 0xff,
348 (ctrl.sin_addr.s_addr >> 24) & 0xff,
349 ntohs(addr.sin_port) >> 8,
350 ntohs(addr.sin_port) & 0xff);
351 TRACE("cmd: " << buf);
353 if((res = execute(string(buf), 200, 1)) < 0){
360 if((res = execute(string("TYPE ") + type, 200, 1)) < 0){
367 sprintf(buf, "REST %llu", offset);
368 if(offset && ((res = execute(string(buf), 350,1)) < 0)){
375 if((res = execute(cmd, 150, 1)) < 0){
382 res = sizeof(struct sockaddr_in);
383 if((res = accept(ssock, (struct sockaddr*)&addr, (socklen_t*)&res)) < 0){
384 WARN("accept call failed!");
392 if((dfd = fdopen(dsock, "r+")) == NULL){
393 WARN("fdopen failed!");
401 TRACE("keepalive...");
407 getIP(char *buf, unsigned long *ip, unsigned short *port){
409 unsigned char i0,i1, i2, i3, p0, p1;
411 if((res = sscanf(buf," (%hhu,%hhu,%hhu,%hhu,%hhu,%hhu)", &i0, &i1, &i2, &i3, &p0, &p1)) != 6){
412 WARN("bad format, res=" << res);
416 TRACE("buf: " << buf);
417 TRACE("(i0,i1,i2,i3,p0,p1)=("<<(int)i0<<","<<(int)i1<<","<<(int)i2<<","<<(int)i3<<","<<(int)p0<<","<<(int)p1<<")");
419 *ip = ntohl((unsigned)i0 + (((unsigned)i1) << 8) + (((unsigned)i2) << 16) + (((unsigned)i3) << 24));
420 *port = ntohs((unsigned)p0 + (((unsigned)p1) << 8));
422 TRACE("IP: " << *ip << "(" << inet_ntoa(*(struct in_addr*)ip) << ")");
423 TRACE("port: " << *port);
429 FTPConnection::execute_open_passive(string cmd, string type, long long offset){
433 struct sockaddr_in addr;
435 TRACE("dsock: "<<dsock<<",dfd: "<<dfd<<",last_off: "<<last_off<<",last_cmd: "<<last_cmd);
437 if((dsock == 0) || (dfd == NULL) || (offset != last_off) || (last_cmd != cmd)){
443 if(tries++ > FTP_MAXTRIES){
444 WARN("too many failures!");
448 TRACE("reopening data connection...");
450 if((res = execute(string("PASV"), 0, 1)) < 0){
451 WARN("PASV command failed!");
458 if(!fgets(buf, FTP_MAXLINE, cfd)){
459 WARN("no response!");
463 if((!sscanf(buf, "%u", &res)) || (res != 227)){
464 WARN("bad response!");
468 if(getIP(strchr(buf, '('), &ip, &port) < 0){
469 WARN("could not extract ip/port information!");
473 if((res = execute(string("TYPE ") + type, 200, 1)) < 0){
479 sprintf(buf, "REST %llu", offset);
480 if(offset && (res = execute(string(buf), 350, 1)) < 0){
481 WARN("could not set offset!");
487 if((res = execute(cmd, 0, 1)) < 0){
493 if((dsock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
494 WARN("socket call failed!");
498 memset(&addr, 0, sizeof(struct sockaddr_in));
499 addr.sin_family = AF_INET;
500 addr.sin_addr.s_addr = htonl(ip);
501 addr.sin_port = htons(port);
503 if(::connect(dsock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0){
504 WARN("could not connect to server!");
508 if(get_response() != 150){
509 WARN("bad server response!");
515 if((dfd = fdopen(dsock, "r+")) == NULL){
516 WARN("fdopen failed!");
524 TRACE("keepalive...");