klient FTP, data connection

0

Gdy chcę ustanowić port dla wysłania danych na serwer dostaję błąd przy próbie połączenia. Scenariusz jest taki, że najpierw sprawdzam na jakim porcie i adresie serwer nasłuchuje a potem się do niego łączę. Fragmenty tej metody:

int Cftp::OpenDataPort(int)
{
	/*
         sprawdzenie flagi połączenia i argumentów
        */

       if(!SendCmd("PASV",'2'))//pobieramy informację o wolnym adresie i porcie dla transmisji danych
	{
		for(int i=0;i<strlen(ftpHandle->cResponse);i++){cout<<ftpHandle->cResponse[i];}
		return 0;
	}

      /*
       trochę magii by przygotować łańcuchy znakowe
      */
      
        int nDataPort=atoi(strDataPort.c_str());

        struct sockaddr_in sin;
	memset(&sin, 0, sizeof(sin));
	sin.sin_family=AF_INET;
	sin.sin_port=htons(nDataPort);
	sin.sin_addr.s_addr = inet_addr(strDataHost.c_str());
	sockfd=socket(PF_INET, SOCK_STREAM,0);

	if(connect(sockfd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0){
		perror("connect");
		return 0;}
return 1;
}

Dostaję cały czas błąd dla connect(). Przy ustanawianiu portu dla odbioru (funckje bind(), listen() i komenda PORT) nie dostaję żadnych błędów.
A może coś źle robię? A może wystarczy jak tylko ustanowię port danych po mojej stronie (klient) a potem tylko STOR i będzie działać?

0

Pokaż jak pozyskujesz strDataPort i strDataHost z odpowiedzi na komendę PASV.

A może wystarczy jak tylko ustanowię port danych po mojej stronie (...)

Nie wystarczy. Lepiej, żeby klient pracował przede wszystkim w trybie passive (problemy z NAT, firewall itp.).

0

To CHYBA nie jest problem. Zamiast zmiennych wstawiałem w miejsce strDataPort numer '20' (to niby domyślny port danych) a zamiast strDataHost wstawiałem adres 127.0.0.1 (serwer stoi na localu) i zawsze przy próbie połączenia dostawałem błąd.
To jest kod którym przygotowuje łancuchy po odpowiedzi na komendę 'PASV'(odpowiedź znajduje się w ftpHandle->cResponse[]):

        int i=0;
	vector<char> vTmp;
	while(ftpHandle->cResponse[i])
	{		
		if(ftpHandle->cResponse[i]=='(')
		{	
			while(ftpHandle->cResponse[i]!=')')//przepisujemy do ostatniego znaku
			{
				vTmp.push_back(ftpHandle->cResponse[i+1]);//przepisujemy odpowiedz
				i++;
			}
			break;
		}
		i++;
	}

	memset(ftpHandle->cResponse, 0, sizeof(ftpHandle->cResponse));//czyscimy nasz bufor
	vTmp.resize((vTmp.size()-1));//pozbywamy się nawiasu na koncu lancucha
	//dalej zamiana odbywa się na zasadzie tranlsacji, nie chcialem tutaj uzywac funckji z stdio
	string strChars[12]={",","0","1","2","3","4","5","6","7","8","9","."};
	char cChars[11]={',','0','1','2','3','4','5','6','7','8','9'};
	string strDataHost;//host dla polaczenia dla danych
	string strDataPort;//port dla polaczenia dla danych     

	int nComCount=0;		      
	for(int i=0;i<vTmp.size();i++)
	{
		for(int j=0;j<11;j++)
		{
			if(vTmp[i]==cChars[j])
			{
				if(vTmp[i]==','){	    
					nComCount+=1;}//liczymy prezcinki, by port przepisac do innego pojemnika
				if(nComCount<4)
				{
					if(vTmp[i]==','){
						strDataHost+=strChars[11];}//zamianimy przecinek na kropke
					else{
						strDataHost+=strChars[j];}				
				}
				else
				{
					if(vTmp[i]!=','){//ignorujemy przecinki
					strDataPort+=strChars[j];}
				}
			}		
		}
	}
	
	int nDataPort=atoi(strDataPort.c_str());

      //dalej jest już to wypełnianie struktury jak w kodzie z pierwszego postu
0

Trochę przekombinowałeś :>

if(*ftpHandle->cResponse == '2') /* <--- tak na wszelki wypadek, bo nie wiem czy to sprawdzasz... powinieneś */
{
	char* p = strchr((char*)ftpHandle->cResponse,'(');
	if(p)
	{
		++p;

		for(int i = 0; *p; ++p)
		{
			if(*p != ',')strDataHost.push_back(*p);
			else
			{
				if(++i == 4){ ++p; break;}
				strDataHost.push_back('.');
			}
		}

		int p1,p2;

		if(sscanf(p,"%i,%i",&p1,&p2) != 2)
		{
			// FUCK!!!
		}
			
		/* tak port wyliczasz */
		nDataPort = p1 * 256 + p2; 
	}
}
0

Pierwszy warunek sprawdzam już w metodzie wysyłającej komendy:

if(!SendCmd("PASV",'2'))//pobieramy informację o wolnym adresie i porcie dla transmisji danych
	{

Jeżeli pierwszy znak odpowiedzi nie zgadza się z drugim argumentem metoda zwróci zero ;) Mój sposób był trochę przekombinowany ale przekładał dobrze (w sensie że wiernie) odpowiedź serwa. Okazało się, że źle wyliczałem port, Ty wyliczasz go prawidłowo bo connect nie zwraca błędu.
Ale popatrz, wyświetliłem po kolei odpowiedź serwa (ftpHandle->cResponse), przetworzony adres hosta(strDataHost) i port (nDataPort).
<image>
http://img706.imageshack.us/img706/457/konsolar.jpg
</image>
Od góry masz odpowiedź serwa, w środku są moje przeliczenia, a ostatni wers to Twoje wyliczenia. Czego nie uwzględniłem przy wyliczaniu numeru portu? Dobrze by było to wiedzieć żeby prawidłowo ułożyć łańcuch dla komendy PORT ;]

0

Czego nie uwzględniłem przy wyliczaniu numeru portu?

Specyfikacji protokołu FTP? :> W moim kodzie masz dość jasno pokazane jak powinno się przeliczać port.

Dobrze by było to wiedzieć żeby prawidłowo ułożyć łańcuch dla komendy PORT

Pomyśl i będziesz wiedział. To prostsze niż wyciąganie danych z odpowiedzi PASV. Mała podpowiedź: ostringstream.

0
0x666 napisał(a)

Czego nie uwzględniłem przy wyliczaniu numeru portu?

Specyfikacji protokołu FTP? :>

W RFC absolutnie nic nie pisze że trzeba odpowiedź przekształcać :> A jeśli tak, to najwidoczniej ten fragment umknął mi co przy tak dużej specyfikacji nie jest takie trudne ;-P
Bardzo Ci dziękuję za pomoc, sam głowiłbym się jeszcze pewnie całe jutrzejsze przedpołudnie, a teraz mogę ruszyć dalej [browar]

1 użytkowników online, w tym zalogowanych: 0, gości: 1