Thread: netcat like file transfer program

  1. #1
    Registered User
    Join Date
    Apr 2005
    Posts
    9

    netcat like file transfer program

    Hi Folks

    I am not a c programmer .But i need help in writing a program which can do this any ideas on how to go about it .

    i start a server on the target server where files need to be copied

    start-server -port 5006 & ---start the server and listen it on a partcular port

    on the source server do this

    if=/usr/myfile |compress start-client -server target-server -port 500 of=/home/myfile

    I need help in writing the client and the server.

    I looked up the unix forums and netcat was close to what i wanted .But not exactly the prog for my need.Anywhere from where i can start.

    regards
    Hrishy

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    And you don't know any C? Start with "Hello world!" and go from there. When you get a handle on the language, look up Beej's guide to socket programming for a start on sockets.

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    ---
    Join Date
    May 2004
    Posts
    1,379
    ...Or you could try your luck at the Project Recruitment Forum

  4. #4
    Registered User
    Join Date
    Apr 2005
    Posts
    9
    Hi Quzah

    Thanks i will look up that resource.

    regards
    Hrishy

  5. #5
    Registered User
    Join Date
    Apr 2005
    Posts
    9
    Hi Guys

    I made a decent begining with that stuff :-)..and digging into some unix manpages and the beejs guide i am just wundering is this this the function i should be using sendfile() man sendfile

    regards
    Hrishy

  6. #6
    Registered User
    Join Date
    Apr 2005
    Posts
    9
    Hi Guys

    I am lost again i did not see anything called as receivefile ..:-(

    regards
    Hrishy

  7. #7
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    You need to use send () and recv() APIs to transfer files between client and server. There is no sendfile function you can use to send files between client and server. You need to open file for reading . Then you can either read and send every single byte or read in a buffer and send the buffer.

    Read Beej's guide properly. It has two example of sending data from TCP client to TCP Server.

    If you have any code in place now, may be you can post it here. And people will provide their comments on it.

    Thanks,

  8. #8
    Registered User
    Join Date
    Apr 2005
    Posts
    9
    Hi Nkhambal

    Thanks for your response.As i said i am mostly a db administrator that means i do sql prorgamming not C.I am trying to help out a local non-profit making organisation.

    They were using dd for file transfer but due to network security issues they have to resort to this kind of thing so i cam ehere asking for help from C programmers.And so far most of have been very generous.

    Here is the code that i manged in whatever little bit of c i know.The problem is i should now write a client that connects to this server and asks the server to pick the file from a specific location and transfer it to a specific location on the client.

    Code:
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <sys/sendfile.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/stat.h>
    #include <netinet/in.h>
    
    
    int main(int argc, char **argv)
    {
      int port = 9000;           /* port number to use */
      int sock;                  /* socket desciptor */
      int desc;                  /* file descriptor for socket */
      int in_fd;                 /* input file descriptor */
      int out_fd;		     /*  output file descriptor */
      struct sockaddr_in addr;   /* socket parameters for bind */
      struct sockaddr_in addr1;  /* socket parameters for accept */
      int    addrlen;            /* argument to accept */
      struct stat stat_buf;      /* argument to fstat */
      off_t offset = 0;          /* file offset */
      char filename[PATH_MAX];   /* filename to send */
      int rc;                    /* holds return code of system calls */
    
      /* check command line arguments, handling an optional port number */
      if (argc == 2) {
        port = atoi(argv[1]);
        if (port <= 1024) { /* dont want root to run this :-) */
          fprintf(stderr, "invalid port: %s\n", argv[1]);
          exit(1);
        }
      } else if (argc != 1) {
        fprintf(stderr, "usage: %s [port]\n", argv[0]);
        exit(1);
      }
    
      /* create Internet domain socket */
      sock = socket(AF_INET, SOCK_STREAM, 0);
      if (sock == -1) {
        fprintf(stderr, "unable to create socket: %s\n", strerror(errno));
        exit(1);
      }
    
      /* fill in socket structure */
      memset(&addr, 0, sizeof(addr));
      addr.sin_family = AF_INET;
      addr.sin_addr.s_addr = INADDR_ANY;
      addr.sin_port = htons(port);
    
      /* bind socket to the port */
      rc =  bind(sock, (struct sockaddr *)&addr, sizeof(addr));
      if (rc == -1) {
        fprintf(stderr, "unable to bind to socket: %s\n", strerror(errno));
        exit(1);
      }
    
      /* listen for clients on the socket */
      rc = listen(sock, 1);
      if (rc == -1) {
        fprintf(stderr, "listen failed: %s\n", strerror(errno));
        exit(1);
      }
    
      while (1) {
    
        /* wait for a client to connect */
        desc = accept(sock, (struct sockaddr *)  &addr1, &addrlen);
        if (desc == -1) {
          fprintf(stderr, "accept failed: %s\n", strerror(errno));
          exit(1);
        }
    
        /* get the file name from the client */
        rc = recv(desc, filename, sizeof(filename), 0);
        if (rc == -1) {
          fprintf(stderr, "recv failed: %s\n", strerror(errno));
          exit(1);
        }
    
        /* null terminate and strip any \r and \n from filename */
    		filename[rc] = '\0';
        if (filename[strlen(filename)-1] == '\n')
          filename[strlen(filename)-1] = '\0';
        if (filename[strlen(filename)-1] == '\r')
          filename[strlen(filename)-1] = '\0';
    
        /* exit server if filename is "quit" */
        if (strcmp(filename, "quit") == 0) {
          fprintf(stderr, "quit command received, shutting down server\n");
          break;
        }
    
        /* fprintf(stderr, "received request to send file %s\n", filename); */
    
        /* open the file to be sent */
        in_fd = open(filename, O_RDONLY);
        if (in_fd == -1) {
          fprintf(stderr, "unable to open '%s': %s\n", filename, strerror(errno));
          exit(1);
        }
    
        /* get the size of the file to be sent */
        fstat(in_fd, &stat_buf);
    
        /* copy file using sendfile */
        offset = 0;
        rc = sendfile (desc, in_fd, &offset, stat_buf.st_size);
        if (rc == -1) {
          fprintf(stderr, "error from sendfile: %s\n", strerror(errno));
          exit(1);
        }
        if (rc != stat_buf.st_size) {
          fprintf(stderr, "incomplete transfer from sendfile: %d of %d bytes\n",
                  rc,
                  (int)stat_buf.st_size);
          exit(1);
        }
    
        /* close descriptor for file that was sent */
        close(in_fd);
    
        /* close socket descriptor */
        close(desc);
      }
    
      /* close socket */
      close(sock);
      return 0;
    }
    i telnet to that particular code and ask this program to get the specifc file it echoes it on my screen .But my requirement to make it to dump the file at a specified path when i call it from a different host.

    I guess i also have to code a TCP client that requests my server to get the specified file and also put it in the specific path.



    regards
    linuxdba
    Last edited by linuxdba; 04-19-2005 at 04:07 AM.

  9. #9
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    Hi,

    I think you are on the right track. One thing, dont use sendfile(). I am not sure about that function but what I understand from its manpage is that , its used to copy one file to other within the kernel and not across multiple hosts.

    What I would recommend, is to read in a block of data from source file into a buffer (char buffer) and then send the data using send() function. At client end, open the file for writing. Receive the block of data from the server in the buffer and write the buffer into the file.

    Just modifying your send/recv operation. I am chosing 512 bytes of buffer to transfer the file.

    NOTE: I haven't tested this code, but it should work without any problem.

    At server end,
    Code:
    int rd;
    int wr;
    char buffer[512];
    int bytes_copied=0;
    
    /* start reading files in block*/
    
    while ((rd=read(in_fd,buffer, sizeof(buffer)))!=0)
    {
         
      if (rd==-1)
      {
         printf("\nError reading source file\n");
         exit(1);
      }
       
      bytes_copied+=rd;
      /* Send the block to client*/
      wr=send(desc,(char *)buffer,rd,0);
      if (wr<0)
      {
          perror("send error:");
          exit(1);
      }
    }
    At Client end

    Code:
    int dst_handle;
    char buffer[512];
    int bytes_received=0;
    int rd;
    int sock; /*Client socket*/
    /* Create the destination file on client and open it for reading */
    if ((dst_handle=creat(filename,00666))==-1)
    {
       perror("Destination File create");
       exit(0);
    } 
    if ((dst_handle=open(filename,O_WRONLY))==-1)
    {
      perror("Destination File open write");
      exit(0);
    } 
    
    /* Keep reading data from server till the TCP  connection is closed */
    while ((rd=recv(sock,(char *)buffer, sizeof(buffer),0)) !=0)
    {
       if (rd < 0)
       {
           perror("recv error:");
           exit(0);
       }
       bytes_received+=rd; 
       /*Write the received data in the file */
       wr=write(dst_handle,buffer,rd*(sizeof(char)));
       if (wr==-1)
       {
    	printf("\nError writing to destination file\n");
    	exit(0);
       }
    }
    Last edited by nkhambal; 04-19-2005 at 05:24 AM.

  10. #10
    Registered User
    Join Date
    Apr 2005
    Posts
    9
    Hi nkhambal

    Well the manpage the first few lines states
    This call copies data between one file descriptor and another. Either or both of these file descriptors may refer to a socket (but seebelow). in_fd should be a file descriptor opened for reading and out_fd should be a descriptor opened for writing. offset is a pointer.

    So i guess it can be very well used to copy files across network.
    Here is my attempt to write a client (man this is tougher then i though wish they make C in 4Gl :-D)

    Code:
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <sys/sendfile.h>
    #include <sys/stat.h>
    
    int main (int argc, char** argv)
    {
      int src;               	/* file descriptor for source file */
      int dest;              	/* file descriptor for destination file */
      struct stat stat_buf;  	/* hold information about input file */
      off_t offset = 0;      	/* byte offset used by sendfile */
      int rc;                	/* return code from sendfile */
      int port;		 	/* port on the remote server to connect to */
      struct sockaddr_in server;    /* socket address */
      int s ;			/* client socket */
      /* check for two command line arguments */
      if (argc != 4) {
        fprintf(stderr, "usage: %s <hostname> <port> <source> <destination> \n", argv[0]);
        exit(1);
      }
    
      /* check command line arguments, handling an optional port number */
      if (argc == 4) {
        port = atoi(argv[1]);
        if (port <= 1024) { /* dont want root to run this :-) */
          fprintf(stderr, "invalid port: %s\n", argv[1]);
          exit(1);
        }
      } 
    
      if ((he=gethostbyname(argv[1])) == NULL) {  /* get the host info */
                herror("gethostbyname");
                exit(1);
            }
    
      strcpy( buf, "Hello there!"); /* create the message */
    
      /* create stream socket using TCP */
      fprintf(stderr, "Creating datagram socket.\n");
      s = socket(AF_INET, SOCK_STREAM, 0);
      if( s == -1 ) {
      fprintf(stderr, "Socket was not created.\n");
      exit(1);
      }
      else
      fprintf(stderr, "Socket created successfully.\n");
      server.sin_family = AF_INET; /* set up the server name */
      server.sin_port = htons(port);
      server.sin_addr.s_addr = inet_addr( argv[1] );
    
      /* connect to the server */
      if( connect(s, &server, sizeof(server)) < 0) {
      fprintf(stderr, "Failed to connect to socket.\n");
      exit(1);
      }
    
      printf("Sending the message: %s\n", buf); /* send the message */
      if( send(s, buf, sizeof(buf), 0) < 0 ) {
      fprintf(stderr, "Failed to send data to socket.\n");
      exit(1);
      }
    
       /* receive the echoed message from the server */
      if( recv(s, buf, sizeof(buf), 0) < 0 ) {
      fprintf(stderr, "Failed to receive data from socket.\n");
      exit(1);
      }
      printf("The message from the server was: %s\n", buf);
      
      close(s); /* close the socket */
      printf("Client closed successfully\n"); /* successfully exit */
      exit(0);
    }
    The problem i have now is what message the client should pass to the server ?

    I just passed strcpy( buf, "Hello there!"); but i actually need to pass the file descriptor of the file which i need to get .

    And when the server responds i need to copy that file to some path on the client.

    I hope somebody helps me now .Please i have a feeling i am very close.

    regards
    linuxdba

  11. #11
    Registered User
    Join Date
    Apr 2005
    Posts
    9
    Hi

    Will my server be able to accept multiple concurrent connections ?

    regards
    Hrishy

  12. #12
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    Yes it can. You need to multithread it. Spawn a new process after accpet() returns. This new process will handle the new connection.

    Code:
    int newfd;
    pid_t pid;
    
    for (;;)
    {
     newfd=accept(sockfd,/*remaining args*/); /* Blocking accept call */
     /*accept() returned when new client connection arrived */
     /*Spawn a new process*/
     
     if ((pid=fork()) == 0) 
     {
        /* We are in child */
        /*Do send/recv on "newfd" here with client */
      
        close(newfd);   /*Close newfd when done */
        exit(0);             /* Exit child process*/
     } else {
        /* We are in parent */
       close(newfd);    /*We dont need it in Parent process. So close it */
     }
     
    }
    In above code snippet, accept runs in a forever loop and blocks till the client connects. When client connect to the server, accept returns with a new socket descriptor for the received connection.

    We spawn a new child process at this time. This child process receives a copy of parents address space. In this child process we perfrom send/recv with client host using new scoket descriptor returned by accept(). While in parent process, we simply close the "newfd" as we don't need it there.

    Remember, its a copy of "newfd" that we close in parent. Child has its own copy which needs to be closed after we are done in child. Also, dont forget to exit child process using exit() when you are done. Otherwise you will have multiple zombies in you server, when parent exits with child left running. You can employ various available methods to wait for the last child in parent before exit. but taking care of child exit usually does the job.

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    You need to establish a protocol that both server and client use. The file might not exist on the server or might not be accessable so in that case you would probably want the server to send an error message which tells the client to display an error and disconnect. If the file dose exist the server should transmit the file's size before transmiting the file data so the client knows how much to receive and can report if it didn't receive the entire file due to connection closure. When transmiting the filename to be downloaded you should either use a deliminator such as a newline charactor to indicate the end of the file name or send the length first.
    Last edited by Quantum1024; 04-20-2005 at 12:02 PM.

  14. #14
    Registered User
    Join Date
    Apr 2005
    Posts
    9
    Hi Nkambhal,Quantam

    Thank you for your advice..i am not sure i will be able to accomplish this coz its getting too technical for me at the moment.

    i wish somebody had written a receivefile just like they have a sendfile function would have made my taks much easier

    I guess i need more help or tutorials in making the stuff work..gcc is bad it just doesnt point out where the sysntax errors are

    regards
    Hrishy
    Last edited by linuxdba; 04-21-2005 at 12:34 AM.

  15. #15
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by nkhambal
    Yes it can. You need to multithread it.
    No you don't. I guess you've never heard of nonblocking sockets?

    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A development process
    By Noir in forum C Programming
    Replies: 37
    Last Post: 07-10-2011, 10:39 PM
  2. Inventory records
    By jsbeckton in forum C Programming
    Replies: 23
    Last Post: 06-28-2007, 04:14 AM
  3. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM
  4. My program, anyhelp
    By @licomb in forum C Programming
    Replies: 14
    Last Post: 08-14-2001, 10:04 PM