我正在编写一个ftp客户端。我有控制通道工作,因为我可以执行CWD,PASV,USER或PASSWORD等命令。
问题是我想打开数据通道来做例如LIST(ls)。为此,我尝试使用与控制通道相同的函数调用被动(pasv)后打开与指定端口的另一个连接。 我认为连接正在工作,但我没有收到缓冲区的任何内容,程序就像等待阅读的东西一样。我不确定使用相同的连接功能是否合适,但我认为它应该可行。
整个代码有点大。 comando_list函数是一个麻烦的问题 socket_connection是我用来连接的那个。麻烦必须在那里我认为
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/errno.h>
#include <assert.h>
/*Bajar cliente UPnP para manejar las conexiones que vienen desde afuera hacia adentro
/*para obtener el tamaño del archivo usando stat()*/
#include <sys/stat.h>
/*for O_RDONLY*/
#include<fcntl.h>
#define PORT 21 /* El puerto que será abierto */
#define MAXDATASIZE 6000
int * passive;
char * global;
void printHelp(){
printf("USO DE CLIENTE FTP\n");
printf("Sintaxis: clienteFTP [servidor[:puerto]] [-h]\n");
printf("servidor: nombre del servidor FTP al cual se desea conectar\n");
printf("puerto: puerto al que se desea conectar en ese servidor (por defecto 21)\n");
printf("-h para pedir ayuda\n");
printf("\n");
printf("COMANDOS DISPONIBLES\n");
printf("QUIT: Finalizar la ejecucion del cliente\n");
printf("OPEN: Establecer una conexion al servidor especificado como argumento. Este comando tiene como segundo parametro"
"opcional el puerto al cual establecer la conexion\n");
printf("USER: Especificar el usuario bajo el cual se desea establecer la conexion\n");
printf("PASS: Enviar la contraseña en el caso de que el servidor asi lo requiera\n");
printf("PWD: Solicitarle al servidor que nos indique en que directorio nos encontramos actualmente\n");
printf("CD: Solicitar al servidor que cambie al directorio especificado como argumento\n");
printf("LIST: Solicitar al servidor que nos muestre los archivos disponibles en el directorio acutal\n");
printf("PUT: Iniciar el envio al servidor del archivo indicado como argumento\n");
printf("GET: Iniciar la recepcion del archivo indicado como argumento\n");
printf("PASSIVE: Indicar al servidor que queremos hacer uso del modo de transferencia pasivo\n");
printf("ACTIVE: Indicar al servidor que queremos hacer uso del modo de transferencia activo (por defecto)\n");
}
/* Mostrar por pantalla la respuesta del servidor*/
void show_server_answer(int * sockfd, char * buf){
/*cantidad de bytes de la respuesta*/
int numbytes;
/* Obtener respuesta del server */
if ((numbytes=recv(*sockfd,buf,MAXDATASIZE,0)) == -1){
/* llamada a recv() */
printf("Error en recv() \n");
}
buf[numbytes]='\0';
/* muestra el mensaje del servidor =) */
printf("Mensaje del Servidor: %s",buf);
}
int receiveData(int * sockfd, char * buf){
int file_size;
FILE *received_file;
int remain_data = 0;
ssize_t len;
printf("llegue hasta aca\n");
char* buffer[1000];
/* Receiving file size*/
if(recv(*sockfd, buf, MAXDATASIZE, 0)!=0){
printf("Error\n");
}
file_size =atoi(buf);
//fprintf(stdout, "\nFile size : %d\n", file_size);
printf("llegue 2\n");
received_file = fopen("archivo.txt", "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while (((len = recv(*sockfd, buf, BUFSIZ, 0)) > 0) && (remain_data > 0))
{
fwrite(buf, sizeof(char), len, received_file);
remain_data -= len;
fprintf(stdout, "Receive %d bytes and we hope :- %d bytes\n", len, remain_data);
}
fclose(received_file);
close(sockfd);
}
int socket_connection(int * sockfd, char * buf, char * server_name, int puerto ){
/*estructura que recibirá información sobre el servidor*/
struct hostent *server_host = malloc(sizeof(server_host));
/* información sobre la dirección del servidor */
struct sockaddr_in* server = malloc(sizeof(server));
/*cantidad de bytes de la respuesta*/
int numbytes;
/* obtener datos del host a través de su nombre */
server_host = gethostbyname(server_name);
if (server_host == NULL){
perror("nombre de servidor desconocido\n");
exit(-1);
}
printf("puerto en conexion %i\n",puerto);
/* Estructura con datos del server */
server->sin_family = AF_INET;
bzero(&(server->sin_zero),8);
server->sin_port = htons((short) puerto);
server->sin_addr = *((struct in_addr *) server_host->h_addr);
/* Obtener un descriptor de archivo para el socket */
if ((*sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("error al querer abrir el socket\n");
exit(-1);
}
/* Conectar al servidor, que ya debe estar configurado */
if(connect(*sockfd, (struct sockaddr *) server, sizeof(struct sockaddr)) == -1){
printf("%s\n", strerror(errno));
printf("error al querer establecer la conexión con el server\n");
exit(-1);
}
if(*passive==0){
printf("passive: %i\n",*passive);
show_server_answer(sockfd, buf);
}
else{
printf("passive: %i\n",*passive);
}
*passive=0;
}
char** str_split(char* a_str, const char a_delim, int * cantidad){
char** result = 0;
size_t count = 0;
char* tmp = a_str;
char* last_comma = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
*cantidad = count -1;
result = malloc(sizeof(char*) * count);
if (result)
{
size_t idx = 0;
char* token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
int hash_function(char * comando){
int value = -1;
if (strcmp(comando,"quit") == 0) {
value = 1;
}
if (strcmp(comando,"open") == 0) {
value = 2;
}
if (strcmp(comando,"user") == 0) {
value = 3;
}
if (strcmp(comando,"pass") == 0) {
value = 4;
}
if (strcmp(comando,"pwd") == 0) {
value = 5;
}
if (strcmp(comando,"cd") == 0) {
value = 6;
}
if (strcmp(comando,"list") == 0) {
value = 7;
}
if (strcmp(comando,"put") == 0) {
value = 8;
}
if (strcmp(comando,"get") == 0) {
value = 9;
}
if (strcmp(comando,"passive") == 0) {
value = 10;
}
if (strcmp(comando,"active") == 0) {
value = 11;
}
return value;
}
void comando_pwd(int sockfd, char * buf){
send(sockfd,"pwd\r\n",strlen("pwd\r\n"),0);
show_server_answer(&sockfd,buf);
}
void comando_user(int sockfd, char * nombreComando, char** argumentos) {
// printf("%s %s\n",argumentos[0],argumentos[1]);
//Armar comando
/*char comandoCompleto[100];
memset(comandoCompleto, '\0', sizeof(comandoCompleto));
strcpy(comandoCompleto, "USER");
printf("%s\r\n",comandoCompleto);
strcat(comandoCompleto, " ");
printf("%s\r\n",comandoCompleto);
//strcat(comandoCompleto, argumentos[1]);
printf("%s\r\n",comandoCompleto);
strcat(comandoCompleto, "\r\n");
printf("%s\r\n",comandoCompleto);
printf("%s\r\n",comandoCompleto);*/
send(sockfd, "USER anonymous\r\n", strlen("USER anonymous\r\n"), 0);
show_server_answer(&sockfd,nombreComando);
}
void comando_pass(int sockfd, char * nombreComando, char** argumentos){
//Armar comando
/*char comandoCompleto[100];
memset(comandoCompleto, '\0', sizeof(comandoCompleto));
strcpy(comandoCompleto, "PASS");
strcat(comandoCompleto, " ");
//strcat(comandoCompleto, argumentos[1]);
strcat(comandoCompleto, "\r\n");
printf("%s\r\n",comandoCompleto);
*/
send(sockfd, "PASS anonymous\r\n", strlen("PASS anonymous\r\n"), 0);
show_server_answer(&sockfd,nombreComando);
}
void comando_cd(int sockfd, char * buf,char ** argumentos, int cantArgumentos){
if(cantArgumentos != 2){
printf("USO: cd <carpeta/directorio>");
}
else{
//Armar comando
char comandoCompleto[100];
memset(comandoCompleto, '\0', sizeof(comandoCompleto));
strcpy(comandoCompleto, "CD");
strcat(comandoCompleto, " ");
strcat(comandoCompleto, argumentos[1]);
strcat(comandoCompleto, "\r\n");
printf("%s",comandoCompleto);
send(sockfd,comandoCompleto,strlen(comandoCompleto),0);
show_server_answer(&sockfd,buf);
}
}
void comando_open(int sockfd, char * buf){
send(sockfd,"OPEN ftp.debian.com\r\n",strlen("OPEN ftp.debian.com\r\n"),0);
show_server_answer(&sockfd,buf);
}
void comando_list(int passivePort,char * ip){
/* ficheros descriptores */
int sockfd;
/* en donde es almacenará el texto recibido */
char buffer[MAXDATASIZE];
//char serverName[100];
//serverName[0] = '\0';
//memset(serverName, '\0', sizeof(serverName));
//strcat(serverName,"ftp.debian.com\n");
//Using a global variable to have the server for now
//printf("%s\n", global);
socket_connection(&sockfd, buf,global,passivePort);
send(sockfd,"list\r\n",strlen("list\r\n"),0);
recv(socket, buf, MAXDATASIZE, 0); //Here the program keeps waiting
printf("%s",buf);
//show_server_answer(&sockfd,buf);
close(sockfd);
}
void RemoveSpaces(char* source)
{
char* i = source;
char* j = source;
while(*j != 0)
{
*i = *j++;
if(*i != ' ')
i++;
}
*i = 0;
}
int getPort(char * buf, char * ip){
//remove whitespaces from buf
RemoveSpaces(buf);
int port=0;
int i=0;
char *ptr;
printf("trim: %s\n",buf);
ptr = strtok(buf,",");
while(ptr!=NULL){
if(i==0){
strcat(ip,&ptr[23]);
strcat(ip, ".");
}
if (i>0 && i < 3) {
strcat(ip, ptr);
strcat(ip, ".");
}
else if (i == 3) {
strcat(ip, ptr);
}
else if(i==4){
port+=atoi(ptr)*256;
}
else if(i==5){
port+=atoi(ptr);
}
else{
printf("error calculando puerto\n");
}
i++;
ptr = strtok(NULL,",");
}
return port;
}
int comando_passive(int sockfd, char * buf, int * puerto, char * ip){
send(sockfd,"pasv\r\n",strlen("pasv\r\n"),0);
show_server_answer(&sockfd,buf);
ip[0]='\0';
*puerto = getPort(buf,ip);
*passive=1;
// *puerto = atoi(passivePort);
printf("%s\n",ip);
printf("%d\n",*puerto);
}
int runCommand(int * sockfd, char * buf,int * passivePort, char * ip){
int cantArgumentos;
char** argumentos;
//argumentos = str_split(buf, ' ',&cantArgumentos);
char comandoOriginal[100];
strcpy(comandoOriginal, buf);
char* nombreComando = strtok(buf, " ");
printf("NC %s\n", nombreComando);
printf("ori %s\n", comandoOriginal);
switch (hash_function(nombreComando)) {
case 2:
comando_open(*sockfd,comandoOriginal);
break;
case 3:
comando_user(*sockfd, comandoOriginal, argumentos);
break;
case 4:
comando_pass(*sockfd, comandoOriginal, argumentos);
break;
case 5:
comando_pwd(*sockfd, comandoOriginal);
break;
case 6:
comando_cd(*sockfd,comandoOriginal, argumentos,cantArgumentos);
break;
case 7:
comando_list(*passivePort,ip);
break;
case 10:
comando_passive(*sockfd,comandoOriginal,passivePort,ip);
break;
default:
printf("El comando no se reconoce como una accion ftp\n");
break;
}
}
int loop(int * sockfd, char * buf){
char * ip = malloc(sizeof(ip));
int * passivePort = malloc(sizeof(passivePort));
int looping = 1; //true
//comando_user(*sockfd,buf);
//comando_pass(*sockfd,buf);
while(looping){
printf("clienteFTP>> ");
fgets(buf,MAXDATASIZE,stdin);
//Pasar a minuscula el comando
int i;
for(i = 0; buf[i]; i++){
buf[i] = tolower(buf[i]);
}
//Borro el salto de linea del buf en caso de existir
char * bufCR;
if((bufCR = strrchr(buf, '\n')) != NULL){
*bufCR = '\0';
}
//veo que comando es
if(strcmp(buf, "exit") == 0){
looping = 0;
}
else if (strcmp(buf, "help") == 0){
printHelp();
}
else{
runCommand(sockfd,buf,passivePort,ip);
}
}
}
int main(int argc, char *argv[]){
passive=malloc(sizeof(passive));
/* ficheros descriptores */
int sockfd;
/* en donde es almacenará el texto recibido */
char buf[MAXDATASIZE];
if (argc > 3) {
/* Max Quantity of argumens */
printf("Uso: %s [servidor[:puerto]][-h]\n",argv[0]);
exit(-1);
}
global=argv[1];
socket_connection(&sockfd, buf,argv[1],21);
loop(&sockfd, buf);
/* cerramos el descriptor de archivo */
close(sockfd);
}
答案 0 :(得分:0)
最后我解决了这个问题。我对FTP的工作原理有了错误的认识。我知道对于像LIST这样的命令,协议使用数据通道,所以我也使用数据通道发送命令,我应该使用控制通道来做到这一点。
我执行被动模式FTP的步骤是
通过控制通道发送命令(LIST),然后从控制通道缓冲区中的服务器接收响应,最后从数据通道缓冲区获取数据
void command_list(int socketControl, char * bufferControl,int passivePort,char * ip){
int socketData;
/* Buffer to save the data received by data channel */
char bufferData[MAXDATASIZE];
//Make the data connection (this function is in the question)
socket_connection(&socketData, bufferData, ip, passivePort);
//Send the command through control socket (recived by parameter)
send(socketControl,"list\r\n",strlen("list\r\n"), 0);
//Receive confirmation message from control channel
show_controlServer_answer(socketControl, bufferControl);
//Now show the data that the server send through data channel
show_dataServer_answer(socketData, bufferData);
close(socketData);
}
void show_dataServer_answer(int socketData, char * bufferData){
while(recv(socketData, bufferData, MAXDATASIZE, 0) > 0){
//Show answer
printf("%s",bufferData);
//Clean buffer
bzero(bufferData,MAXDATASIZE);
}
}
int show_controlServer_answer(int socketControl, char * bufferControl){
int numbytes;
//Clean buffer
bzero(bufferControl,MAXDATASIZE);
if((numbytes = recv(socketControl, bufferControl,MAXDATASIZE, 0)) < 0){
printf("show_controlServer_answer: Error en recv()\n");
printf("%s\n", strerror(errno));
}
bufferControl[numbytes]='\0';
//Show answer
printf("%s",bufferControl);
//codigoRespuesta means replyCode
int codigoRespuesta = procesar_codigo_respuesta(bufferControl);
//Get the hundred
codigoRespuesta = codigoRespuesta / 100;
//Clean buffer
bzero(bufferControl,MAXDATASIZE);
return codigoRespuesta;
}
int procesar_codigo_respuesta(char * bufferControl){
char *copiaBuffer = malloc(sizeof(char)*MAXDATASIZE);
strcpy(copiaBuffer, bufferControl);
//get leading three digits
copiaBuffer = strtok(copiaBuffer, " ");
//convert to int
int nro = atoi(copiaBuffer);
free(copiaBuffer);
return nro;
}