Hej.
Jeg prøver at udvikle en simpel FTP klient i C++. Mit progrma kan indtil videre forbinde til serveren, og hente velkomstbeskeden. Jeg har forsøgt at implementere en login-funktion, dette virker dog ikke da serveren ikke svare tilbage på min besked. Jeg har prøvet at sniffe hvilket data mit program sender, og jeg har fundet ud af at den sender "USER brugernavn" som den burde, men at serveren ikke svare tilbage. Jeg har desuden prøvet at sende en besked til min klient når den venter på svar fra serveren, og denne besked opganger den fint.
Min kode:
#include <iostream>
#include <stdexcept>
#include <string>
#include <stdlib.h>
#include <vector>
#include <sstream>
#include "winsock2.h"
using namespace std;
struct svr_info
{
string name;
string wlcMsg;
vector<string> aliases;
vector<string> addr_list;
};
template <typename T> string ToString(T value)
{
stringstream ss;
ss << value;
return ss.str();
}
class FTP
{
public:
FTP(int timeout = 30);
~FTP();
svr_info connect(string host, unsigned int port = 21);
void login(string, string);
int read(string &buffer);
int write(string &buffer);
string getAnswer();
private:
string m_answer;
int m_timeout;
SOCKET m_sock;
};
FTP::FTP(int timeout)
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
throw domain_error("Error at WSAStartup()!");
m_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sock == INVALID_SOCKET) {
WSACleanup();
throw domain_error("Could not create socket!");
}
m_answer = "";
m_timeout = timeout;
}
FTP::~FTP()
{
closesocket(m_sock);
}
svr_info FTP::connect(string host, unsigned int port)
{
struct in_addr adr;
struct hostent *entity;
struct svr_info serverInfo;
adr.S_un.S_addr = inet_addr(host.c_str());
if (adr.S_un.S_addr == INADDR_NONE && host != string("255.255.255.255")) {
entity = gethostbyname(host.c_str());
} else {
entity = gethostbyaddr((char*)& adr, sizeof(adr), AF_INET);
}
if (entity == 0) {
switch (WSAGetLastError()) {
case WSAENETDOWN:
throw domain_error("Failour in network component");
break;
case WSAHOST_NOT_FOUND:
throw domain_error(host +" not found");
break;
case WSATRY_AGAIN:
throw domain_error("An error occured on the DNS server! Try again.");
break;
case WSANO_RECOVERY:
throw domain_error("An error occured on the DNS server");
break;
case WSANO_DATA:
throw domain_error(host +" is valid, but it has not an IP address");
break;
case WSAEINPROGRESS:
throw domain_error("The WinSock service can not deliver your call!");
break;
}
} else {
int i = 0;
serverInfo.name = entity->h_name;
while (entity->h_aliases[i]) {
serverInfo.aliases.push_back(entity->h_aliases[i]);
i++;
}
i = 0;
while (entity->h_addr_list[i]) {
serverInfo.addr_list.push_back(inet_ntoa(*((struct in_addr*)entity->h_addr_list[i])));
i++;
}
}
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_port = htons(port);
clientService.sin_addr.s_addr = inet_addr(serverInfo.addr_list[0].c_str());
if (::connect(m_sock, (sockaddr*)& clientService, sizeof(clientService)) == SOCKET_ERROR) {
//int err = WSAGetLastError();
//char buffer[32];
//itoa(err, buffer, 10);
WSACleanup();
//throw domain_error(buffer);
throw domain_error("Could not create socket!");
}
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
recv(m_sock, buffer, sizeof(buffer), 0);
serverInfo.wlcMsg = buffer;
return serverInfo;
}
string FTP::getAnswer()
{
return m_answer;
}
void FTP::login(string usr, string pwd)
{
string sendBuf = string("USER ")+ usr;
int byteSend = write(sendBuf);
cout << "Send: " << sendBuf << " - " << byteSend << " bytes send" << endl;
string recvBuf;
read(recvBuf);
m_answer = recvBuf;
}
int FTP::read(string& buffer)
{
int byteRead;
//Timeout
fd_set set;
struct timeval timeout;
int err;
FD_ZERO(&set);
FD_SET(m_sock, &set);
if (m_timeout > 0) {
timeout.tv_sec = (unsigned int)(m_timeout / 1000);
timeout.tv_usec = (unsigned int)(m_timeout % 1000) * 1000;
err = select(FD_SETSIZE, &set, 0, 0, &timeout);
} else
err = select(FD_SETSIZE, &set, 0,0,0);
if (err == 0)
throw domain_error("Timeout");
else if (err == -1) {
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, 0, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, 0);
string description((char*)lpMsgBuf);
LocalFree(lpMsgBuf);
throw domain_error(description);
}
char recvBuf[1024];
byteRead = recv(m_sock, recvBuf, sizeof(buffer), 0);
buffer = ToString(recvBuf);
if (byteRead == -1)
throw domain_error("An error occured while reciving!");
else if (byteRead == 1)
throw domain_error("Connection resetted by peer.");
return byteRead;
}
int FTP::write(string& buffer)
{
int byteSend;
byteSend = send(m_sock, buffer.c_str(), sizeof(buffer), 0);
if (byteSend == -1)
throw domain_error("Could not send message");
return byteSend;
}
int main(int argc, char *argv[])
{
string host;
if (argc == 2) {
host = argv[1];
} else {
cout << "Wrong parameter count!" << endl;
return 1;
}
try {
struct svr_info serverInfo;
FTP ftpClient;
serverInfo = ftpClient.connect(host);
cout << "Connected to: " << serverInfo.name << endl;
cout << serverInfo.wlcMsg << endl;
ftpClient.login("brugernavn", "adgangskode");
cout << ftpClient.getAnswer() << endl;
} catch (domain_error e) {
cout << e.what() << endl;
}
return 0;
}