Search This Blog

Thursday, March 08, 2012

ftpclient.c


I managed to act as an FTP client in C just using sockets... Its really not too bad.

Now of course the client I made wasn't compatible with ALL ftp servers I am quite sure, I just needed to get it to connect to a solaris box. But it did work testing on some windows ftp server...

remember to wait for the server to send you ALL of the data it needs to, before your client starts spitting commands at it. Take a look at the return code numbers it sends you also. And one very important thing... Be sure to strcat(ftp_cmd,"\r\n"); before you send it, those are the termination characters...
Code:
int ftpRecvResponse(int sock, char * buf) {
   int i;

   if (recv(sock, buf, 5120, 0) == -1) {//receive the data
      perror("recv");
      return 0;;
   }
   for(i=(strlen(buf) - 1);i>0;i--) {
      if(buf[i]=='.' || buf[i]=='\r') { 
         buf[i+1]='\0';
         break;
      }
   }
   printf("%s\n",buf); //print response to the screen
   return 0;
}

int ftpNewCmd(int sock, char * buf, char * cmd, char * param) {
   strcpy(buf,cmd);
   if(strlen(param) > 0) {
      strcat(buf," ");
      strcat(buf,param);
   }
   strcat(buf,"\r\n");
   printf("*%s",buf); //print the cmd to the screen
   if(send(sock, buf, strlen(buf), 0) == -1) {
      perror("send");
      return 0;
   }
   //clear the buffer
   return 0;
}

int ftpConvertAddy(char * buf, char * hostname, int * port) {
   unsigned int i,t=0;
   int flag=0,decCtr=0,tport1,tport2;
   char tmpPort[6];
   //example data in quotes below:
   //"227 Listening on (149,122,52,162,4,20)"
   //4 * 256 + 20 = 1044
   for(i=0;i3)
         hostname[i]='\0';
   }
   return 0;
}

int ftpSendFile(char * buf, char * host, int port) {
   int sd;
   struct sockaddr_in pin;
   struct hostent *hp;

   if ((hp = gethostbyname(host)) == 0) {
      perror("gethostbyname");
      return -1;
   }
   memset(&pin, 0, sizeof(pin));
   pin.sin_family = AF_INET;
   pin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
   pin.sin_port = htons(port);
   if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
      perror("socket");
      return -1;
   }
   if (connect(sd,(struct sockaddr *)  &pin, sizeof(pin)) == -1) {
      perror("connect");
      return -1;
   }
   if(send(sd, buf, strlen(buf), 0) == -1) {
      perror("send");
      return -1;
   }
   closesocket(sd); //close the socket
   return 0;
}

int ftpProcess(char *hostname, char *username, char *password, char *file, char *filename, char *path) {
   int sd;
   struct sockaddr_in pin;
   struct hostent *hp;
   char tmpHost[100];
   int tmpPort;
   char buf[5120];

   if ((hp = gethostbyname(hostname)) == 0) {
      perror("gethostbyname");
      return -1;
   }

   memset(&pin, 0, sizeof(pin));
   pin.sin_family = AF_INET;
   pin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
   pin.sin_port = htons(FTPPORT);

   if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
      perror("socket");
      return -1;
   }
   if (connect(sd,(struct sockaddr *)  &pin, sizeof(pin)) == -1) {
      perror("connect");
      return -1;
   }
   if(ftpRecvResponse(sd,buf)==1) {  //wait for ftp server to start talking
    if(strncmp(buf,"220",3)==0) {  //make sure it ends with a 220
     if(ftpNewCmd(sd,buf,"USER",username)==1) {  //issue the command to login
      if(ftpRecvResponse(sd,buf)==1) {  //wait for response
       if(strncmp(buf,"331",3)==0) {  //make sure response is a 331
        if(ftpNewCmd(sd,buf,"PASS",password)==1) {  //send your password
         if(ftpRecvResponse(sd,buf)==1) { //wait for response
          if(strncmp(buf,"230",3)==0) { //make sure its a 230
           if(ftpNewCmd(sd,buf,"PASV","")==1) {  //notify server we want to pass a file
            if(ftpRecvResponse(sd,buf)==1) {  //wait for response
             if(strncmp(buf,"227",3)==0) {  //make sure it starts with a 227
              ftpConvertAddy(buf,tmpHost,&tmpPort); //then convert the return to usable data
              if(ftpNewCmd(sd,buf,"STOR",filename)==1) {  //set the file name AND
               ftpSendFile(file,tmpHost,tmpPort);
               if(ftpRecvResponse(sd,buf)==1) {        //wait for a response
                if(strncmp(buf,"150",3)==0) {  //make sure its a 150 so we know the server got it all
                 if(ftpRecvResponse(sd,buf)==1) {
                  if(strncmp(buf,"226",3)==0) {
                  .......
//close all if()s or do it some better way, close the socket when done.

i know its not the prettiest, but it works quite well. I plan on cleaning it up and making an example to throw out there for those who don't like 3rd party libraries...

PM or email me if you need anything else.


Last edited by mschoolbus : September 18th, 2003 at 03:08 PM.

FTP

FTP

File Transfer Protocol
Syntax
      FTP [-options] [-s:filename] [-w:buffer] [host]

key   
   -s:filename   Run a text file containing FTP commands.

   host          Host name or IP address of the remote host.

   -g            Disable filename wildcards.

   -n            No auto-login.

   -i            No interactive prompts during ftp.

   -v            Hide remote server responses.

   -w:buffer     Set buffer size to buffer
                 (default=4096)

   -d            Debug
 
   -a            Use any local interface when binding data connection.


Commands to run at the FTP: prompt

append local-file [remote-file]
             Append a local file to a file on the remote computer.

ascii        Set the file transfer type to ASCII, the default. 
             In ASCII text mode, character-set and end-of-line
             characters are converted as necessary.

bell         Toggle a bell to ring after each command. 
             By default, the bell is off.

binary       Set the file transfer type to binary. 
      Use `Binary' for transferring executable program
             files or binary data files e.g. Oracle

bye          End the FTP session and exit ftp

cd           Change the working directory on the remote host.

close        End the FTP session and return to the cmd prompt.

debug        Toggle debugging. When debug is on, FTP will display
             every command.

delete remote-file
             Delete file on remote host.

dir [remote-directory] [local-file]
             List a remote directory's files and subdirectories.
             (or save the listing to local-file)

disconnect   Disconnect from the remote host, retaining the ftp prompt.

get remote-file [local-file]
             Copy a remote file to the local PC.

glob         Toggle the use of wildcard characters in local pathnames.
             By default, globbing is on.

hash         Toggle printing a hash (#) for each 2K data block transferred. 
             By default, hash mark printing is off.

help [command]
             Display help for ftp command.

lcd [directory]
             Change the working directory on the local PC.
             By default, the working directory is the directory in which ftp was started.

literal argument [ ...]
             Send arguments, as-is, to the remote FTP host.

ls [remote-directory] [local-file]
             List a remote directory's files and folders.
             (short format)

mdelete remote-files [ ...]
             Delete files on remote host.

mdir remote-files [ ...] local-file
             Display a list of a remote directory's files and subdirectories.
             (or save the listing to local-file)
             Mdir allows you to specify multiple files.

mget remote-files [ ...]
             Copy multiple remote files to the local PC.

mkdir directory
             Create a directory on the remote host.

mls remote-files [ ...] local-file
             List a remote directory's files and folders.
             (short format)

mput local-files [ ...]
             Copy multiple local files to the remote host.

open computer [port]
             Connects to the specified FTP server. 

prompt       Toggle prompting. Ftp prompts during multiple file transfers to 
             allow you to selectively retrieve or store files;
             mget and mput transfer all files if prompting is turned off. 
             By default, prompting is on.

put local-file [remote-file]
             Copy a local file to the remote host.

pwd          Print Working Directory
             (current directory on the remote host)

quit         End the FTP session with the remote host and exit ftp.

quote argument [ ...]
             Send arguments, as-is, to the remote FTP host.

recv remote-file [local-file]
             Copy a remote file to the local PC.

remotehelp [command]
             Display help for remote commands.

rename filename newfilename
             Rename remote files.

rmdir directory
             Delete a remote directory.

send local-file [remote-file]
             Copy a local file to the remote host.

status       Display the current status of FTP connections and toggles.

trace        Toggles packet tracing; trace displays the route of each packet 

type [type-name]
             Set or display the file transfer type:
             `binary' or `ASCII' (the default)

             If type-name is not specified, the current type is displayed. 
             ASCII should be used when transferring text files.

             In ASCII text mode, character-set and end-of-line
             characters are converted as necessary.

      Use `Binary' for transferring executable files. 

user user-name [password] [account]
             Specifes a user to the remote host.

verbose      Toggle verbose mode. By default, verbose is on.

! command    Run command on the local PC.

? [command]  Display help for ftp command.
Examples
an example FTP Script to retrieve files in binary and then ascii mode:
::GetFiles.ftp

   [User_id]
   [ftp_password]
   binary
   get /usr/file1.exe
   get file2.html
   mget *.jpeg
   ascii
   mget *.txt
   quit
To run the above script:
FTP -s:GetFiles.ftp [hostname]
This will connect as the user:User_id with password:ftp_password

An FTP Script to publish files in binary mode:
::PutFiles.ftp

   [User_id]
   [ftp_password]
   binary
   mput *.html
   cd images
   mput *.gif
   quit
To run the above script:
FTP -s:PutFiles.ftp [hostname]
This will connect as the user:User_id with password:ftp_password
Using the Windows GUI for FTP
Windows Explorer (not Internet Explorer) also has a built in FTP client.
Type in the address bar:
ftp://username@ftpserver.address.com
you will be prompted for the password.
You can also do
ftp://username:password@ftpserver.address.com
This is not recommended as anyone can read the password.
Secure FTP
Standard FTP does not encrypt passwords - they are sent across the network in plain text. A more secure method is to use SecureFTP (SFTP) or SecureCopy (SCP) Freeware clients are available e.g. WinSCP
"Only wimps use tape backup: _real_ men just upload their important stuff on ftp, and let the rest of the world mirror it" - Linus Torvalds
Related commands:

COPY - Copy one or more files to another location
XCOPY - Copy files and folders
REM - Add a comment (includes commenting FTP scripts)
Q271078 - Microsoft FTP does not support passive mode (error 425)
RAW FTP - Full list of RAW FTP commands
Equivalent bash command (Linux): FTP - File Transfer Protocol


Back to the Top
© Copyright SS64.com 1999-2012
Some rights reserved

Command Line FTP


                      

Command Line FTP

Why use Command-Line FTP?
Command line FTP allows you to transfer files between the tdl server and a remote server via the Internet backbone at T1/T3 speeds. This means that the transfer will take place very quickly, and will not use your modem connection at all. One example of use would be transferring images from a remote clip art ftp area to your account for use on your home page.
FTP Commands
Logging in, Logging Out
Command Function
ftp Opens an ftp session from your shell account to a remote server. You must first log into your shell account.
Example: ftp servername
You will be prompted for your user name and password.
bye Closes your ftp session with the remote server.
You will return to your regular shell prompt after closing your ftp session.
Modes
When transferring files, it is very important to make sure you are in the correct mode.
Command
Function
ascii This is the default mode, and this is to be used when transferring text files.
Example: ascii
bin This mode must be used when transfering graphics (jpg, gif files.
Example bin

Listings and Directory Changing
Command Function
ls Lists the current directory contents
Example: ls
cd Performs the same function as clicking an icon in MAC/Windows or cd in DOS -- it changes directories. Alternating cdls, you can find your way down the directory tree of the remote host to the files you are looking for.
Example: cd subdirectory
cd .. Backs you up one directory level (to the parent directory). Otherwise, the syntax is cd [directoryname]. It is helpful to visualize the tree structure of a directory while you are exploring a remote server using ls and cd.
Example: cd ..
lcd Changes your local working directory -- where you are on the machine you are ftp'ing from. This is where files will be put from, and where get will deposit them.
Example lcd subdirectory
lcd .. Backs you up one directory level (to the parent directory) of your local working directory much like cd .. backs you up one directory level on the remote machine.
Example: lcd ..
mkdir Makes a directory on the remote server.
Example: mkdir [newdirectoryname]

Transferring Files
You can transfer one file at a time (by naming the file) or many with the use of the * character.
Command Function
put Puts one file to the remote location
Example: put filename.ext
mput Puts multiple files to the remote location
Example: mput * to put all files in your local current directory to the remote directory)
or mput *.html to put all .html files
or *.jpg to put all jpg images
or *.gif to put all gif images
get Gets a single file.
Example: get filename.ext
mget Gets multiple files. You can use the * as you did with the mput command.
Example: mget *
or mget *.html to get all .html files
or *.jpg to get all jpg images
or *.gif to get all gif images
del Deletes a file or directory.
Example: del filename - deletes a specific file
del * - deletes all files and directories*
del *.html - deletes all html files
del *.jpg - deletes all jpg files
del *.gif - deletes all gif files
del directoryname - to delete a specific directory*
*Note: A directory cannot be deleted unless it is empty.
prompt When you begin a file transfer, by default, you are prompted to confirm the transfer of each and every file. You can turn this off by typing prompt which toggles this feature off. (Typing prompt again turns it back on). This is especially useful when transferring multiple files and want them to go all at once without asking you to confirm each and every one.
Example: prompt
hash The hash command is the equivalent of a status bar in the Windows O/S. hash lets you know the progress of your file transfer if you turn it on. For example, if you are transferring a 200 meg file and you do not have hash toggled on, you have no indication as to whether or not it is transferring. Since hash slows the ftp process, a general rule of thumb is that if you are transferring large files, turn hash on so you can make sure the files are transferring. If you have many small files to transfer, turn it off.
Example: hash
Return to support index.
Return to home.

send(2) - Linux man page


send(2) - Linux man page

Name

send, sendto, sendmsg - send a message on a socket

Synopsis

#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

Description

The system calls send(), sendto(), and sendmsg() are used to transmit a message to another socket.
The send() call may be used only when the socket is in a connected state (so that the intended recipient is known). The only difference between send() and write(2) is the presence of flags. With a zero flags argument, send() is equivalent to write(2). Also, the following call
send(sockfd, buf, len, flags);
is equivalent to
sendto(sockfd, buf, len, flags, NULL, 0);
The argument sockfd is the file descriptor of the sending socket.
If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) socket, the arguments dest_addr and addrlen are ignored (and the error EISCONN may be returned when they are not NULL and 0), and the error ENOTCONN is returned when the socket was not actually connected. Otherwise, the address of the target is given by dest_addr with addrlen specifying its size. For sendmsg(), the address of the target is given by msg.msg_name, with msg.msg_namelen specifying its size.
For send() and sendto(), the message is found in buf and has length len. For sendmsg(), the message is pointed to by the elements of the array msg.msg_iov. The sendmsg() call also allows sending ancillary data (also known as control information).
If the message is too long to pass atomically through the underlying protocol, the error EMSGSIZE is returned, and the message is not transmitted.
No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a return value of -1.
When the message does not fit into the send buffer of the socket, send() normally blocks, unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail with the error EAGAIN or EWOULDBLOCK in this case. The select(2) call may be used to determine when it is possible to send more data.
The flags argument is the bitwise OR of zero or more of the following flags.
MSG_CONFIRM (Since Linux 2.3.15)
Tell the link layer that forward progress happened: you got a successful reply from the other side. If the link layer doesn't get this it will regularly reprobe the neighbor (e.g., via a unicast ARP). Only valid on SOCK_DGRAM and SOCK_RAW sockets and currently only implemented for IPv4 and IPv6. See arp(7) for details.
MSG_DONTROUTE
Don't use a gateway to send out the packet, only send to hosts on directly connected networks. This is usually used only by diagnostic or routing programs. This is only defined for protocol families that route; packet sockets don't.
MSG_DONTWAIT (since Linux 2.2)
Enables nonblocking operation; if the operation would block, EAGAIN or EWOULDBLOCK is returned (this can also be enabled using the O_NONBLOCK flag with the F_SETFL fcntl(2)).
MSG_EOR (since Linux 2.2)
Terminates a record (when this notion is supported, as for sockets of type SOCK_SEQPACKET).
MSG_MORE (Since Linux 2.4.4)
The caller has more data to send. This flag is used with TCP sockets to obtain the same effect as the TCP_CORK socket option (see tcp(7)), with the difference that this flag can be set on a per-call basis. Since Linux 2.6, this flag is also supported for UDP sockets, and informs the kernel to package all of the data sent in calls with this flag set into a single datagram which is only transmitted when a call is performed that does not specify this flag. (See also the UDP_CORK socket option described in udp(7).)
MSG_NOSIGNAL (since Linux 2.2)
Requests not to send SIGPIPE on errors on stream oriented sockets when the other end breaks the connection. The EPIPE error is still returned.
MSG_OOB
Sends out-of-band data on sockets that support this notion (e.g., of type SOCK_STREAM); the underlying protocol must also support out-of-band data.
The definition of the msghdr structure follows. See recv(2) and below for an exact description of its fields.
struct msghdr {
    void         *msg_name;       /* optional address */
    socklen_t     msg_namelen;    /* size of address */
    struct iovec *msg_iov;        /* scatter/gather array */
    size_t        msg_iovlen;     /* # elements in msg_iov */
    void         *msg_control;    /* ancillary data, see below */
    size_t        msg_controllen; /* ancillary data buffer len */
    int           msg_flags;      /* flags on received message */
};
You may send control information using the msg_control and msg_controllen members. The maximum control buffer length the kernel can process is limited per socket by the value in /proc/sys/net/core/optmem_max; see socket(7).

Return Value

On success, these calls return the number of characters sent. On error, -1 is returned, and errno is set appropriately.

Errors

These are some standard errors generated by the socket layer. Additional errors may be generated and returned from the underlying protocol modules; see their respective manual pages.
EACCES (For UNIX domain sockets, which are identified by pathname) Write permission is denied on the destination socket file, or search permission is denied for one of the directories the path prefix. (See path_resolution(7).)
EAGAIN or EWOULDBLOCK
The socket is marked nonblocking and the requested operation would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
EBADF An invalid descriptor was specified.
ECONNRESET
Connection reset by peer.
EDESTADDRREQ
The socket is not connection-mode, and no peer address is set.
EFAULT An invalid user space address was specified for an argument.
EINTR
A signal occurred before any data was transmitted; see signal(7).
EINVAL
Invalid argument passed.
EISCONN
The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)
EMSGSIZE
The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.
ENOBUFS
The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)
ENOMEM No memory available.
ENOTCONN
The socket is not connected, and no target has been given.
ENOTSOCK
The argument sockfd is not a socket.
EOPNOTSUPP
Some bit in the flags argument is inappropriate for the socket type.
EPIPE The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.

Conforming To

4.4BSD, SVr4, POSIX.1-2001. These function calls appeared in 4.2BSD.
POSIX.1-2001 only describes the MSG_OOB and MSG_EOR flags. POSIX.1-2008 adds a specification of MSG_NOSIGNAL. The MSG_CONFIRM flag is a Linux extension.

Notes

The prototypes given above follow the Single UNIX Specification, as glibc2 also does; the flags argument was int in 4.x BSD, but unsigned int in libc4 and libc5; the len argument was int in 4.x BSD and libc4, but size_t in libc5; the addrlen argument was int in 4.x BSD and libc4 and libc5. See also accept(2).
According to POSIX.1-2001, the msg_controllen field of the msghdr structure should be typed as socklen_t, but glibc currently types it as size_t.

Bugs

Linux may return EPIPE instead of ENOTCONN.

Example

An example of the use of sendto() is shown in getaddrinfo(3).

See Also

fcntl(2), getsockopt(2), recv(2), select(2), sendfile(2), shutdown(2), socket(2), write(2), cmsg(3), ip(7), socket(7), tcp(7), udp(7)

Referenced By

forward(1), gnutls_transport_set_push_function(3), netwrite(3), pth(3), select_tut(2), sockatmark(3), socketcall(2), splice(2), syscalls(2), unix(7), xinetd.conf(5)