[Source] Cliente FTP Básico - C

Started by Dark_Side, 23 de September , 2006, 01:03:04 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dark_Side

Lolz,
Uma dia desses um colega me deu uma sugestão sobre um cliente FTP básico,
eu gostei da idéia e fiz o treco.
Segue abaixo o code:


/*
          ##################################################
          ## Hi,                                          ##
          ## Cliente FTP Básico  - C                      ##
          ## by Dark Side                                 ##
          ## wallacediasferreira@hotmail.com              ##
          ## Bye.                                         ##
          ##################################################
*/

#include <stdio.h> // Standard IO
#include <string.h> // strlen(),snprintf(),strncpy()
#include <stdlib.h> //atof(), malloc(),free()
#include <conio.h> // getchar(),getch()
#include <winsock.h> // Winsock Header
 
#define ERRO -1 // Constante de erro

   /*
   resp = retorno de funções;
   bytes = bytes recebidos;
   size = número bytes que podem ser escritos em uma string.
   */
 unsigned long resp=0,bytes=0,size=0;
 long p_id=-1; // Número de incremento da porta local
 
  WSADATA wsadata; // Variável WSADATA
  SOCKET sock,sockdata; //SOCKETS
  struct sockaddr_in sockin,local,sockindata; //Estruturas sockaddr_in
  struct hostent * host; // Estrutruta hostent
 
   /*
   servidor,usuario,senha = informações sobre a conta;
   buffer = buffer para a recepção de dados;
   localip = IP local;
   ftp_ip = representação do IP Local no formato aceito em FTP.
   */
  char servidor[0x32],usuario[0x14],senha[0x14],buffer[0x800],localip[0x10],ftp_ip[0x10];

  char * env = NULL; //Buffer para envio de comandos
  char * buffer_file = NULL; // Buffer para receber armazenar conteúdo de arquivos

  unsigned long chunk = 0x1000,total=0; //Variáveis de controle : enviar e receber de arquivos

   /*
   erro = informa erros;
   fecha_socket = fecha sockets;
   conv_ip = converte o IP Local para o formato aceito no FTP;
   sock_dados = abre conexão de dados;
   iniciar = inicia comunicação com o servidor.
   */

  void erro(const char*),fecha_socket(void),conv_ip(void),sock_dados(void),iniciar(void);
  char * receber(void); // Função para receber dados
 
  void listar(void); // Lista arquivos
  int upload(void); // Faz upload de arquivos
  int download(void); // Baixa arquivos
  void deleta_arquivo(void); // Deleta arquivos
  int ren_arq(void); // Renomeia arquivos
  void muda_dir(void); // Muda de diretório
  void cria_dir(void); // Cria diretório
  void deleta_dir(void); // Deleta diretórios
  void sair(); // Encerra
 
int main(){
iniciar(); // Inicia comunicação
 unsigned char op;
 gogo: // Ponto de partida
   system("cls"); // Limpa a tela
   
   // Tarefas
   puts("\nSelecione uma tarefa:");
   puts("[1] Listar arquivos");
   puts("[2] Fazer upload de um arquivo...");
   puts("[3] Fazer o download de um arquivo...");
   puts("[4] Deletar um arquivo");
   puts("[5] Renomear um arquivo");
   puts("[6] Mudar de diretorio ");
   puts("[7] Criar um diretorio ");
   puts("[8] Deletar um diretorio ");           
   puts("[9] Disconectar ");
   printf("Opcao: ");
 op = getchar(); // Obtém opção

 if(WSAGetLastError() == WSAECONNRESET){ // Verifica se há conexão
    fecha_socket();
    erro("\nA conexão foi perdida!");
    }

switch(op) // Verifica a tarefa selecionada
 {
    case '1': // Listar arquivos
       listar();
       goto gogo; // Volta ao ponto de partida
       break;
               
    case '2': // Upload
        if(upload() == ERRO) goto gogo;
        goto gogo;
        break;
               
    case '3': // Download
         if(download() == -1) goto gogo;
         goto gogo;
         break;
               
    case '4': // Deleta arquivos
         deleta_arquivo();     
         goto gogo;             
         break;
               
   case '5': // Renomeia arquivos
        if(ren_arq() == -1) goto gogo;
        goto gogo;   
        break;
               
   case '6': // Muda de diretório
        muda_dir();
        goto gogo;             
        break;

   case '7': // Cria diretórios
        cria_dir();
        goto gogo;             
        break;
           
   case '8': // Deleta diretórios
        deleta_dir();     
        goto gogo;             
        break;
               
   case '9': // Encerra
        sair();
        break;
   
   default: // Nenhuma das opções acima
       goto gogo;  // Volta ao ponto de partida
       break;
                   
   }     
       
    return 0;
}

////////////////////////////////////////////////////////////////////////////////

void iniciar()
 {
   puts(">> Servidor:"); // Servidor
   scanf("%50s",servidor);

   resp = WSAStartup(MAKEWORD(1,1),&wsadata); // Tenta inicializar Winsock
    if(resp == ERRO)
       erro("Erro ao inicializa WinSock."); // Função que mostra erro

   host = gethostbyname("localhost"); // Obtém host local
   
   // Copia IP para a estrutura sockaddr_in: local
   memcpy(&local.sin_addr,host->h_addr_list[0],host->h_length);

   snprintf(localip,16,"%s",inet_ntoa(local.sin_addr)); // Grava o IP local na variável
   conv_ip();  // Converte o IP para o formato usando no FTP
   
    resp =(sock = socket(AF_INET,SOCK_STREAM,0)); // Tenta criar socket
    if(resp == ERRO)
       erro("Erro ao criar socket.");

    sockin.sin_family = AF_INET; // Família do socket
    sockin.sin_port=htons(21); // Porta do FTP
   
    host = gethostbyname(servidor); // Tenta obter host do servidor
    if(host == NULL)
       erro("Erro ao obter host.");

    memcpy(&sockin.sin_addr,host->h_addr_list[0],host->h_length);

    resp = connect(sock,(struct sockaddr*)&sockin,sizeof(sockin)); // Tenta se conectar
    if(resp == ERRO)
      erro("Erro ao se conectar no servidor.");
     
    puts(receber()); // Mostra o banner => Dados inicias logo após a conexão
     
     printf("Nome de usuario: "); // Usuário
     scanf("%20s",usuario);
     
     printf("Senha: "); // Senha
     scanf("%20s",senha);
     
       // Envia usuário: USER USUARIO   
       size = strlen(usuario)+8;
       env = (char*)malloc(size);
       snprintf(env,size,"USER %s\r\n",usuario);
       send(sock,env,strlen(env),0);
       free(env);
       
       if(strstr(receber(),"331") == 0) // Verifica se não houve pedido da senha
       {
          fecha_socket();
          erro("Erro no processo de login");
       }
       
       // Envia senha: PASS SENHA
       size = strlen(senha) + 8;
       env = (char*)malloc(size);
       snprintf(env,size,"PASS %s\r\n",senha);
       send(sock,env,strlen(env),0);
       free(env);

       if(strstr(receber(),"230") == 0) // Verifica se não houve login
       {
          fecha_socket();
          erro("O login falhou.");
       }
       
}

////////////////////////////////////////////////////////////////////////////////

void sock_dados() // Socket para conexão de dados
{
    p_id++; // Incrementa a porta = 1000 + p_id
   
    resp =(sockdata = socket(AF_INET,SOCK_STREAM,0)); // Tenta criar socket de dados
    if(resp == ERRO){
      fecha_socket();
      erro("Erro ao criar socket.");
      }

    sockindata.sin_family = AF_INET;
    sockindata.sin_port=htons(1000+p_id); // Configura porta local de acordo com 1000 + p_id
   
    // Tenta configurar socket
   resp =  bind(sockdata,(struct sockaddr*)&sockindata,sizeof(sockindata));
   if(resp == ERRO){
       fecha_socket();
       erro("Erro ao configurar socket de dados.");
       }
   listen(sockdata,1); // Aguarda a conexão de dados com o servidor
}

////////////////////////////////////////////////////////////////////////////////

// Recebe dados do socket principal
char * receber()
{
  memset(buffer,0x0,0x800); // Limpa o buffer
  bytes = recv(sock,buffer,0x800,0); // Recebe dados
  if(!bytes){ // Caso não tenha recebido dados, encerra
    fecha_socket();
    erro("Erro ao receber dados");
}
return buffer; // Retorna os dados recebidos
     }
     
////////////////////////////////////////////////////////////////////////////////

// Substitui . por , no ip. Ex: 127.0.0.1 = 127,0,0,1
// O ip deve ser enviado nesse formato para conexões de dados

void conv_ip(){
 int i;
   strncpy(ftp_ip,localip,16);
   for(i=0;i<strlen(ftp_ip);i++)
   if(ftp_ip[i] == '.') ftp_ip[i] = ',';
}

////////////////////////////////////////////////////////////////////////////////

// Lista os arquivos e diretório
void listar()
{
   sock_dados(); // Abre conexão de dados
        size = 0x20;
        env = (char*)malloc(size);
        snprintf(env,size,"PORT %s,3,%d\r\nLIST\r\n",ftp_ip,232+p_id);
       
       
         // Envia comando LIST + PORT:
         /*
         LIST
         PORT xxx,xxx,xxx,xxx,Y,YYY
         
         xxx,xxx,xxx,xxx = IP
         Y,YYY = grupos dos últimos bytes(2 em 2) que formam a porta, em decimal
        */

        send(sock,env,strlen(env),0); // Aqui -> envia
        puts(receber());
       
     while((sockdata = accept(sockdata,0,0)) == ERRO) // Enquanto não houver conexão
     Sleep(10); // Aguarda
   
     bytes = 1; // Bytes = 1 => validar loop

     while(bytes){ // Enquanto estiver recebendo
           memset(buffer,0x0,0x800); // Limpa o buffer
             bytes = recv(sockdata,buffer,0x800,0); // Obtém dados
             puts(buffer); //Mostra-os
          }
               
        closesocket(sockdata); // Fecha socket de conexão
        puts(receber()); // Recebe dados do socket principal
        free(env);
        system("pause"); // Efetua uma pausa
   
}

////////////////////////////////////////////////////////////////////////////////

// Faz upload de um arquivo
int upload()
{
  printf("Fazer upload do arquivo: ");
     char local_file[0x50];
     scanf("%80s",local_file); // Obtém caminho do arquivo local
               
        FILE *fp = fopen(local_file,"rb"); // Tenta abrí-lo
          if(fp ==0){
            printf("Erro ao abrir o arquivo %s\n",local_file);
            system("pause");
            return -1; // Encerra função com código -1
            }
               
       send(sock,"TYPE I\r\n",8,0); // Define conexão binária
       receber();
               
         sock_dados(); // Inicializa conexão de dados
            size = 0x1D;
            env = (char*)malloc(size);
            snprintf(env,size,"PORT %s,3,%d\r\n",ftp_ip,232+p_id);
           
            send(sock,env,strlen(env),0);  //Envia comando LIST + PORT
            puts(receber());
            free(env);
           
            size = strlen(local_file)+8;
            env = (char*)malloc(size);
            snprintf(env,size,"STOR %s\r\n",local_file);
           
            // Envia comando STOR => Upload de arquivos
            // Exemplo: STOR arquivo.lol
           
            send(sock,env,strlen(env),0);
            puts(receber());
            free(env);
   
    while((sockdata = accept(sockdata,0,0)) == ERRO) // Enquanto não houver conexão de dados
    Sleep(10); // Aguarda
   
    puts("Enviando arquivo..."); // Inicia envio do arquivo => fim do loop acima
                 
        fseek(fp,0,SEEK_END); // Seta read/write ao fim
        unsigned long tam = ftell(fp); // Obtém tamanho do arquivo
        rewind(fp); // Seta read/write ao início
   
   while(ftell(fp) < tam){ // Loop até que todo o arquivo seja lido
       if(tam - ftell(fp) < chunk) // Calcula espaço disponível para leitura: 4096 Bytes = padrão
         chunk = tam - ftell(fp);
       
       buffer_file  = (char*)malloc(chunk); // Aloca espaço no buffer
           fread(buffer_file,chunk,1,fp); // Lê bloco de bytes
           Sleep(10); // Pequena pausa
           send(sockdata,buffer_file,chunk,0); // Envia bloco de bytes
           printf("Enviando %lu de %lu\n",ftell(fp),tam); // Mostra status
       free(buffer_file); // Libera espaço previamente alocado
           }
       
   fclose(fp); // Fecha arquivo
   closesocket(sockdata);
   puts(receber());
   system("pause");

return 0;
}

////////////////////////////////////////////////////////////////////////////////

int download(){
     printf("Fazer download do arquivo: ");
     char remote_file[0x32];
     scanf("%50s",remote_file); // Obtém caminho do arquivo remoto
   
     sock_dados();
          size = 0x1D;
          env = (char*)malloc(size);
          snprintf(env,size,"PORT %s,3,%d\r\n",ftp_ip,232+p_id);
         
          // Envia comando LIST + PORT
          send(sock,env,strlen(env),0);
          printf(receber());
          free(env);
             
          send(sock,"TYPE I\r\n",8,0);
          receber();

            size = strlen(remote_file)+8;
            env = (char*)malloc(size);
            snprintf(env,size,"RETR %s\r\n",remote_file);
           
           // Envia comando RETR => Download de arquivos
           // Exemplo: RETR arquivo.lol
   
            send(sock,env,strlen(env),0);
            free(env);
     
           char str_resp[0x32];
           snprintf(str_resp,0x32,"%s",receber()); // Armazena a resposta do servidor no buffer
               
            if(strstr(str_resp,"150")==0){ // Se não tiver código 150 (Sucesso)
               puts(str_resp);  // Mostra erro gerado pelo servidor         
               printf("Erro ao obter o arquivo %s\n",remote_file);
               closesocket(sockdata);
               system("pause");
               return -1; // Encerra função com código -1
               }
               
              FILE *fp2 = fopen(remote_file,"wb");  // Tenta abrir o arquivo local
                 if(fp2 ==0){ //
                   printf("Erro ao abrir o arquivo %s\n",remote_file);
                   system("pause");
                   return -1; // Encerra função com código -1
            }

      while((sockdata = accept(sockdata,0,0)) == ERRO) // Enquanto não houver conexão de dados
            Sleep(10); // Aguarda
     
      buffer_file = (char*)malloc(chunk); // Aloca espaço referente ao chunk (4096 bytes)
      bytes = 1; // Bytes = 1 => validar loop
      total = 0; // Total recebido
      puts("Recebendo arquivo...");
      while(bytes) // Enquanto houverem bytes (bytes > 0)
           {
           memset(buffer_file,0x0,chunk); // Limpa buffer
           bytes = recv(sockdata,buffer_file,chunk,0); // Recebe dados
           fwrite(buffer_file,bytes,1,fp2); // Escreve-os no arquivo local
           total+=bytes; // Incrementa total
           }           

        // Mostra bytes totais
         printf("Total recebido: %lu Bytes\n",total);

              fclose(fp2); // Fecha arquivo local
              closesocket(sockdata);
              puts(receber());
              free(buffer_file); // Libera espaço alocado no buffer
              system("pause");
return 0;
}

////////////////////////////////////////////////////////////////////////////////

void deleta_arquivo()
{
  printf("Deletar arquivo: ");
  char del_file[0x20];
  scanf("%32s",del_file); // Obtém caminho do arquivo remoto

     size = strlen(del_file)+8;
     env = (char*)malloc(size);
     snprintf(env,size,"DELE %s\r\n",del_file);
     
     // Envia comando DELE
     // Exemplo: DELE arquivo.lol
     
     send(sock,env,strlen(env),0);
     puts(receber());

       free(env);
       system("pause");

}

////////////////////////////////////////////////////////////////////////////////

int ren_arq()
{
  printf("Renomear arquivo de: ");
  char ren_file[0x20];
  scanf("%32s",ren_file); // Caminho do arquivo remoto => renomear
               
  printf("Renomear arquivo para: ");
  char to_file[0x20];
  scanf("%32s",to_file); // Novo nome

     size = strlen(ren_file)+8;
     env = (char*)malloc(size);
     
     // Envia comando RNFR
     // Exemplo: RNFR arquivo_de.lol
     
     snprintf(env,size,"RNFR %s\r\n",ren_file);
     send(sock,env,strlen(env),0);
     free(env);

       if(strstr(receber(),"350") == 0){ // Se o código não for 350 (Sucesso)
       puts("O arquivo especificado nao existe.");
       system("pause");
       return -1; // Encerra função com código -1
       }

    size = strlen(to_file)+8;
    env = (char*)malloc(size);
   
    // Envia comando RNTO
    // Exemplo: RNTO arquivo_para.lol
   
    snprintf(env,size,"RNTO %s\r\n",to_file);
    send(sock,env,strlen(env),0);
    free(env);
   
      puts(receber());
      system("pause");

return 0;
}

////////////////////////////////////////////////////////////////////////////////

void muda_dir()
{
   send(sock,"PWD\r\n",5,0); // Mostra diretório atual
   puts(receber());
   
    char dir[0x20];
    printf("Mudar diretorio: "); // Mudar para...
    scanf("%32s",dir);
   
      size = strlen(dir)+7;
      env = (char*)malloc(size);
     
      // Envia comando CWD
      // Exemplo: CWD dir1
     
      snprintf(env,size,"CWD %s\r\n",dir);
      send(sock,env,strlen(env),0);
     
         puts(receber());
         free(env);
         system("pause");
}

////////////////////////////////////////////////////////////////////////////////


void cria_dir()
{
  printf("Criar diretorio: ");
  char cre_dir[0x20];
  scanf("%32s",cre_dir); // Nome do diretório => criar
 
     size = strlen(cre_dir)+7;
     env = (char*)malloc(size);
     snprintf(env,size,"MKD %s\r\n",cre_dir);
     
     // Envia comando MKD
     // Exemplo: MKD meu_dir
     
     send(sock,env,strlen(env),0);
       
         puts(receber());
         free(env);
         system("pause");

}

////////////////////////////////////////////////////////////////////////////////

void deleta_dir()
{
   printf("Deletar diretorio: ");
   char del_dir[0x20];
   scanf("%32s",del_dir); // Nome diretório => deletar
   
     size = strlen(del_dir)+7;
     env = (char*)malloc(size);
     snprintf(env,size,"RMD %s\r\n",del_dir);
   
   // Envia comando RMD
   // Exemplo: RMD meu_dir
   
   send(sock,env,strlen(env),0);
   
         puts(receber());
         free(env);
         system("pause");
}

void sair()
{
  send(sock,"QUIT\r\n",6,0); // Comando QUIT
 
     puts(receber());
     fecha_socket();
     exit(0);
}

////////////////////////////////////////////////////////////////////////////////

// Mostra erros e encerra
void erro(const char * erro)
{
   puts(erro); // Mostra o erro
   getch(); // Pausa
   exit(1); // Encerra programa com código 1
}

////////////////////////////////////////////////////////////////////////////////

// Fecha sockets
void fecha_socket()
{
  closesocket(sock); // Fecha o socket principal
  closesocket(sockdata); // Fecha socket de dados
  WSACleanup(); // Finaliza WinSock
}

Lolz, é isso.
Carry on...
Bye.