Sie sind auf Seite 1von 67

Introduction

File Transfer Protocol

1. INTRODUCTION
1.1

Purpose
A file is a fundamental abstraction for long-term storage of information. Transferring files

from one computer to another is one of the most common tasks expected from networking or inter networking environment. The greatest volume of data exchange in Internet today is due to file transfer. It is always essential that information and files are geographically distributed over different locations be shared among the members of work group. Although transferring file from one system other seems simple and straight forward, some problems must be dealt.

Every computer file is a series of numerical values stored as series of single objects. Whether those values represent text (in ASCII format), an image (such as a JPEG or GIF) or any other type of contents. All files require some sort of interpretation. What the file represents, and how the data in the file should be interpreted, depends on the files content type( file type). A files content type is extremely important, since processing an image file with an audio processor would end in a meaningless result .Different system may different ways of representing data and text , may use different filename conversion and may have different directory structures. All these problems have been solved by File transfer protocol. The File Transfer Protocol is an excellent method to transfer (download and send) files from one computer to the other over the Internet. Though you can transfer files using email, it is not a good choice especially when the file size is large or when you need to transfer several files. The main purpose of our project is to understand the working of the connection oriented protocol TCP/IP works and to develop a file transfer protocol. The file transfer protocol is an initial approach to standard file transfer protocol which is generally adopted in the working environment. internet-

Dept. of CSE, R.V.C.E

Feb-June-2012

File Transfer Protocol Introduction

1.2 Scope
File Transfer protocol is the standard mechanism provided by TCP/IP for copying file from one host to another host. It is an application layer protocol.

Promote file (programs or data) sharing Efficiently transfer data from one computer to another Encourage indirect or implicit use of remote computers Provide a common platform for file storages among different
hosts.

FTP transfers arbitrary data, e.g. text and binary files access restrictions

Provides security (before using the client must login with correct
name and password).

FTP hides the details of individual computer system

Dept. of CSE, R.V.C.E

Feb-June-2012

File Transfer Protocol Software Requirement Specification

2. SOFTWARE REQUIREMENT SPECIFICATION


2.1 Overall Description
File transfer protocol is a protocol that enables us to transfer the files from one system to another which is connected in a network. The file transferring can be from either side. The client should request the file name needed, the server checks to see if the file existing or not, and the server transfers the file. We are using Client-Server connection. It uses the services of the TCP. We are setting up the two connection .They are data connection for the transfer of the data and control connection for transfer of the commands. Here connection established in Passive mode .Once the connection is opened in passive mode, the FTP server doesn't wait for the FTP client to send the data transfer port information.

Product perspective:
The file transfer protocol should be able to provide the basic and easy way to communicate between two systems. And the protocol should be able to give the maximum options as possible for the user. The protocol should work between many systems. The protocol should provide many options as possible for the user. The FTP server is able to server the request many client at a time.

2.2. Specific requirements


2.2.1. Functionality
Any authenticated user can use the ftp to retrieve data from server. The user must able to retrieve data from server. The client can put data to server The client can see the files in the working directory of the server. The client can change the working directory of the server.

Dept. of CSE, R.V.C.E

Feb-June-2012

File Transfer Protocol Software Requirement Specification 2.2.2. Design constraints


The ftp server is bind to port no 1234.this port used for control connection. Any arbitrary port no is used for data connection. Few commands supported by ftp are implemented. All clients use the user name as ftp and with password ftp. The user of the client side can delete the files on the server machine. The proper permissions to be given to server files so that any user must not delete files arbitrarily. The client can delete the files of the server if necessary permissions exist.

2.2.3. Interfaces
This section describes how the client interacts with the server.

2.2.3.1. User interface


The any user with the specified username and password can use this file transfer protocol. The user who wants the server information or to upload to the server can use this file transfer protocol

2.2.3.2. Hardware interface Server side


Processor: Intel Pentium 4 or higher version RAM: 256 MB or more Hard disk: 10 GB or more

Client side
Processor: Intel Pentium 4 or higher version RAM: 256 MB or more Hard disk: 5 GB or more

2.2.3.3 Software interface


Dept. of CSE, R.V.C.E Feb-June-2012 4

File Transfer Protocol Detailed Design


Operating system: fedora 7 or Ubuntu Back end: C

3. DETAILED DESIGN
The ftp model developed is based on the client server architecture using the concept of socket programming .ftp setups the two connection one for data and other control connection. The control connection will be opened always but data connection will be opened as and when required. The ftp model contains two model mainly client and server.

3.1 Module 1 (Server module)


3.1.1 Definition
The server module which servers the request by the client. It can handle multiple request at a time .It contains two components 1. Control process 2. Data transfer process.

3.1.2 Purpose
The server module create socket, bind server to port 1234(registered port).it wait for client connection to complete. It is concurrent server which can handle multiple request at a time. After client gets connected to it will send the command using control connection and set ups data connection as an when required.

3.1.3 Functionality
SERVER: 1. Initially server creates socket.

Dept. of CSE, R.V.C.E

Feb-June-2012

File Transfer Protocol Detailed Design


2. It then calls bind function to register itself to the kernel. 3. Next it calls listen function and waits for receiving the client connections. 4. This is followed by accept() system call which takes the first connection request on the queue and creates another socket with the same properties as the socket file descriptor 5. Then the server accepts and processes. It will make the control connection. 6. The server is actively running , if any incoming connections are coming it will accept those by calling forking new child for each connection 7. The file transfer takes place between client and server 8. For each transfer data connection is opened and closed.
9.

Lastly the server closes the connection when request completes.

3.1.4 Input
The server will given specific IP address and the port no 1234 (registered port).

3.1.5 Output
The server will bind to the specific address wait for the connection requset from the client.As per the request it will exectue the different commands of ftp.

3.2 Module 2 (Client Module)


3.2.1 Definition
The client module sends the request through the server using command line argument. It contains two components 1. Control process 2. Data transfer process along with an user interface.

3.2.2 Purpose
The client module create socket, fill in internet socket address structure. It will send the request to server for connection. After client gets connected to server will send the command us-

Dept. of CSE, R.V.C.E

Feb-June-2012

File Transfer Protocol Detailed Design


ing control connection and set ups data connection as an when required. We are implemented in the passive mode client will send his port no to the server to send the data to particular port as when data connection is setup

3.2.3 Functionality
Client:
1.

Initially the client also creates the socket using the socket system call. Authentication is done.

2.It then calls the connect system call for establishing the connection to the server.
3.

4.The file transfer takes place between client and server. (Using series of read and write operations)

3.2.4 Input
The client will be given server IP address and the port no 1234 (registered port).

3.2.5 Output
The client will send to the specific address wait for the connection reply from the server.As per the permission client can ask for the request.

Dept. of CSE, R.V.C.E

Feb-June-2012

File Transfer Protocol Implementation

4. IMPLEMENTATION
4.1

BASIC MODEL OF FTP:

The figure shows basic model of ftp. The client has 3 components: user interface, control process, and client data transfer. The server has 2 components: control process and data transfer process. The control connection is made between the data transfer process and remains open for the entire interactive ftp session. The data connection is opened for each file transferred. It opens each time commands that involve transferring files are used and it closes when the file is transferred.

4.2

Introduction to Sockets

Among the many methods available for sending data or files on network media, Sockets can provide faster access than most of the other methods we study, usually with very little overhead, and it is adaptable to most types of Networks. Though rarely appreciated, sockets make it possible to send any data within the network most efficiently.

Dept. of CSE, R.V.C.E

Feb-June-2012

Implementation

File Transfer Protocol

A socket is actually a function that creates an end point for communication. For two processes to communicate sockets should be created at both ends. After sockets have been created then a path is established between the two processes, using which we can transfer the data from one process to another. Using Sockets we can establish communication between two unrelated processes which are over a network. These advantages of sockets are appreciated when network programming is undertaken. LINUX Operating system while being a very flexible and robust O.S also has a very good support for programming especially with C/C++. Sockets are typed according to the communications properties visible to the user. Applications are presumed to communicate only between sockets of the same type; although there is nothing that prevents communication between sockets of different types should underlying communication protocols support this. Two types of sockets are available to the user. A stream socket provides for the bi-directional, reliable, sequenced, and unduplicated flow of data without record boundaries. A datagram socket supports bi-directional flow of data which is not promised to be sequenced, reliable, or unduplicated.

4.2.1 Opening and Closing Sockets


The primitive for creating a socket is the `socket' function, declared in `sys/socket.h'. - Function: int socket (int family, int type, int protocol) This function creates a socket and specifies communication family, and type which should be one of the socket styles listed in Communication types: The family argument specifies the family; it must be `PF_LOCAL' (*note Local Namespace ::) or `AF_INET' (*note Internet Namespace ::). PROTOCOL designates the specific protocol (*note Socket Concepts ::); zero is usually right for protocol. The return value from `socket' is the file descriptor for the new socket, or `-1' in case of error. The following `errno' error conditions are defined for this function: The file descriptor returned by the `socket' function supports both read and write operations

Dept. of CSE, R.V.C.E

Feb-June-2012

Implementation

File Transfer Protocol

When you have finished using a socket, you can simply close its file descriptor with `close'; see *Note Opening and Closing Files`. If there is still data waiting to be transmitted over the connection, normally `close' tries to complete this transmission. You can control this behavior using the `SO_LINGER' socket option to specify a timeout Period. You can also shut down only reception or transmission on a connection by calling `shutdown', which is declared in `sys/socket.h'. - Function: int shutdown (int SOCKET, int HOW) The `shutdown' function shuts down the connection of socket SOCKET. The argument HOW specifies what action to perform: `0' Stop receiving data for this socket. If further data arrives, reject it. `1' Stop trying to transmit data from this socket. Discard any data waiting to be sent. Stop looking for acknowledgement of data already sent; don't retransmit it if it is lost. `2' Stop both reception and transmission. The return value is `0' on success and `-1' on failure. The following `errno' error conditions are defined for this function

4.2.2 Using Sockets with Connections


The most common communication styles involve making a connection to a particular other socket, and then exchanging data with that socket over and over. Making a connection is asymmetric; one side (the "client") acts to request a connection, while the other side (the "server") makes a socket and waits for the connection request.

Dept. of CSE, R.V.C.E

Feb-June-2012

10

Implementation
4.2.2.1 Making a Connection

File Transfer Protocol

In making a connection, the client makes a connection while the server waits for and accepts the connection. Here we discuss what the client program must do with the `connect' function, which is declared in `sys/socket.h'. - Function: int connect (int SOCKET, struct sockaddr *ADDR, socklen_t LENGTH) The `connect' function initiates a connection from the socket with file descriptor SOCKET to the socket whose address is specified by the ADDR and LENGTH arguments. (This socket is typically on another machine, and it must be already set up as a server.) Normally, `connect' waits until the server responds to the request before it returns. You can set nonblocking mode on the socket SOCKET to make `connect' return immediately without waiting for the response. *Note File Status Flags: For information about nonblocking mode. The normal return value from `connect' is `0'. If an error occurs, `connect' returns `-1'. 4.2.2.2 Listening for connections Now let us consider what the server process must do to accept connections on a socket. First it must use the `listen' function to enable connection requests on the socket, and then accept each incoming connection with a call to `accept' (*note Accepting Connections ::). Once connection requests are enabled on a server socket, the `select' Function reports when the socket has a connection ready to be accepted. The `listen' function is not allowed for sockets using connectionless communication styles. - Function: int listen (int SOCKET, unsigned int N) The `listen' function enables the socket SOCKET to accept connections, thus making it a server socket.

Dept. of CSE, R.V.C.E

Feb-June-2012

11

Implementation

File Transfer Protocol

The argument N specifies the length of the queue for pending connections. When the queue fills, new clients attempting to connect fail with `ECONNREFUSED' until the server calls `accept' to accept a connection from the queue. The `listen' function returns `0' on success and `-1' on failure. 4.2.2.3 Accepting connections When a server receives a connection request, it can complete the connection by accepting the request. Use the function `accepts' to do this. A socket that has been established as a server can accept connection requests from multiple clients. The server's original socket _does not become part of the connection_; instead, `accept' makes a new socket which participates in the connection. `accept' returns the descriptor for this socket. The server's original socket remains available for listening for further connection requests. The number of pending connection requests on a server socket is finite. If connection requests arrive from clients faster than the server can act upon them, the queue can fill up and additional requests are refused with an `ECONNREFUSED' error. You can specify the maximum length of this queue as an argument to the `listen functions, although the system may also impose its own internal limit on the length of this queue. Function: int accept (int SOCKET, struct sockaddr *ADDR, socklen_*LENGTH_PTR) This function is used to accept a connection request on the server socket SOCKET. The `accept' function waits if there are no connections pending, unless the socket SOCKET has nonblocking mode set. (You can use `select' to wait for a pending connection, with a nonblocking socket.) The ADDR and LENGTH-PTR arguments are used to return information about the name of the client socket that initiated the connection SOCKET part of the connection. Instead, it creates a new socket which becomes connected. The normal return value of `accept' is the file descriptor for the new socket. Accepting a connection does not make

Dept. of CSE, R.V.C.E

Feb-June-2012

12

Implementation

File Transfer Protocol

After `accept', the original socket SOCKET remains open and unconnected, and continues listening until you close it. You can accept further connections with SOCKET by calling `accept' again. If an error occurs, `accept' returns `-1'

4.3 SETTING UP A NETWORK:


The steps to be followed to set up a Network can be stated as below: 1. Setting IP Addresses, 2. Testing the Network. These can be briefly explained as below:

4.3.1 Setting up a Network Address:


An IP Address is a unique number which is used to identify every machine individually over a network. The 32-bits of the IP Address. For convenience of being able to give a large number of Addresses this 32-bit number is split into four 8-bit parts. Each Number can then have valid numbers ranging from 0 to 255. In IP Addresses, the four 8-bit parts are separated by a period, a notation called dotted quad. The IP Address is again divided into 2 parts: The network number and The device number.

Dept. of CSE, R.V.C.E

Feb-June-2012

13

Implementation 4.3.2 Testing the Network:


The netstat command:

File Transfer Protocol

Probably the best approach to checking on TCP/IP is to use the netstat command, which gives many different summaries of all network connections and their status like the type of socket being used whether and connected or not..

The ping command: The ping command is used to query another system and ensure a connection is active. The ping program operates by sending a request to the destination machine for reply. If the destination machines IP software receives the request, it issues a reply immediately.

4.4. TCP CLIENT-SERVER CONNECTION PROCEDURE


Once a socket has been connected to a peer, you can use the ordinary `read' and `write' operations (*note I/O Primitives ::) to transfer data. A socket is a two-way communications channel, so read and write operations can be performed at either end. There are also some I/O modes that are specific to socket operations. In order to specify these modes, you must use the `recv' and `send' functions instead of the more generic `read' and `write' functions. The `recv' and `send' functions take an additional argument which you can use to specify various flags to control special I/O modes. , The Socket is created by the Server and goes into listen mode. Then the Client performs a connect function to connect to the Server. After these functions have been performed the Server initializes the stream to begin transmission of data. The Server specifies the protocol (default) to be used. It also initializes the Port numbers and binds to the Clients socket, and then we are ready to transfer data. The SERVER then uses the accept command and creates a descriptor to handle this socket.

Dept. of CSE, R.V.C.E

Feb-June-2012

14

Implementation

File Transfer Protocol

As soon as the Client is executed the list of files in the Server side and as well as the Clients side is displayed on the terminal, looking at which we can decide which to transfer from Server to Client. Now we create a status buffer to hold the status of the current transfer being done. When the Client sends send data in this buffer then the Server should be ready to send data to the Client. This transfer is done by using two buffers sandbur and recvbuf at both Server and Client end. These buffers are used in such a way that the Client reads simultaneously when the Server writes. These buffers are given an appropriate size so as not to overflow the receivers buffer. The whole process of transferring of data is done in an infinite loop at the Server side. Upon receiving this status the server then starts the transmission of file contents. The initial transfer across the Server and Client happens from the Server to Client when we are listing the contents of the Server Directory on the Client side. This is accomplished using a while ( ) loop and reading in the server directory contents through the socket. Then the client asks the user to enter the filename of the File on the server directory to be transferred. This is sent to the server the server is in the read mode i.e.; the Server reads in the filename supplied by the client. The server then opens the File in the server directory and reads into the buffer the file contents (The max. possible amount being the size of the buffer.), This is then sent to the Client which receives and writes immediately into the file and sets the status buffer to send data and ONLY then does the server send the next buffer full of data to the client. This process is repeated until the entire contents of the file are transferred to the client.

Dept. of CSE, R.V.C.E

Feb-June-2012

15

Implementation

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

16

Implementation

File Transfer Protocol

4.5 FTP COMMANDS


The ftp commands which are implemented in the above project are given below:

4.5.1. ACCESS CONTROL COMMANDS


The following commands specify access control identifiers USER NAME (USER) The argument field is a Telnet string identifying the user. The user identification is that which is required by the server for access to its file system. This command will normally be the first command transmitted by the user after the control connections are made (some servers may require this). Additional identification information in the form of a password and/or an account command may also be required by some servers. Servers may allow a new USER command to be entered at any point in order to change the access control and/or accounting information. This has the effect of flushing any user, password, and account information already supplied and beginning the login sequence again. All transfer parameters are unchanged and any file transfer in progress is completed under the old access control parameters.

PASSWORD (PASS) The argument field is a Telnet string specifying the users password. This command must be immediately preceded by the user name command, and, for some sites, completes the user's identification for access control. Since password information is quite sensitive, it is desirable in general to "mask" it or suppress typeout. It appears that the server has no foolproof way to achieve this. It is therefore the responsibility of the user-FTP process to hide the sensitive password information. CHANGE WORKING DIRECTORY (CWD) This command allows the user to work with a different directory or dataset for file storage or retrieval without altering his login or accounting information. Transfer parameters are similarly unchanged. The argument is a pathname specifying a directory or other system dependent file group design.

Dept. of CSE, R.V.C.E

Feb-June-2012

17

Implementation File Transfer Protocol

LOGOUT (QUIT) This command terminates a USER and if file transfer is not in progress, the server closes the control connection. If file transfer is in progress, the connection will remain open for result response and the server will then close it. If the user-process is transferring files for several USER but does not wish to close and then reopen connections for each, then the REIN command should be used instead of QUIT. An unexpected close on the control connection will cause the server to take the effective action of an abort (ABOR) and a logout (QUIT).

4.5.2. FTP Service Commands


The FTP service commands define the file transfer or the file system function requested by the user. The argument of an FTP service command will normally be a pathname. The syntax of pathnames must conform to server site conventions (with standard defaults applicable), and the language conventions of the control connection. The suggested default handling is to use the last specified device, directory or file name, or the standard default defined for local users. The commands may be in any order except that a "rename from" command must be followed by a "rename to" command and the restart command must be followed by the interrupted service command (e.g., STOR or RETR). The data, when transferred in response to FTP service commands, shall always be sent over the data connection, except for certain informative replies. The following commands specify FTP service requests. RETRIEVE (RETR) This command causes the server-DTP to transfer a copy of the file, specified in the pathname, to the server- or user-DTP at the other end of the data connection. The status and contents of the file at the server site shall be unaffected.

Implementation
STORE (STOR) This command causes the server-DTP to accept the data transferred via the data connection and to store the data as a file at the server site. If the file specified in the pathname exists at the

Dept. of CSE, R.V.C.E

Feb-June-2012

18

File Transfer Protocol


server site, then its contents shall be replaced by the data being transferred. A new file is created at the server site if the file specified in the pathname does not already exist. DELETE (DEL) This command causes the file specified in the pathname to be deleted at the server site. If an extra level of protection is desired (such as the query, "Do you really wish to delete?"), it should be provided by the user-FTP process. PRINT WORKING DIRECTORY (PWD) This command causes the name of the current working directory to be returned in the reply. LIST (LIST) This command causes a list to be sent from the server to the passive DTP. If the pathname specifies a directory or other group of files, the server should transfer a list of files in the specified directory. If the pathname specifies a file then the server should send current information on the file. A null argument implies the user's current working or default directory. The data transfer is over the data connection in type ASCII or type EBCDIC. (The user must ensure that the TYPE is appropriately ASCII or EBCDIC). Since the information on a file may vary widely from system to system, this information may be hard to use automatically in a program, but may be quite useful to a human user.

Testing

5. TESTING
Dept. of CSE, R.V.C.E Feb-June-2012 19

File Transfer Protocol

5.1 Unit testing


Unit testing is done to verify and validate whether individual units of source code are fit for use. A unit is the smallest testable part of an application.

5.2. Test cases


5.2.1 Unit test Case 1
Sl No. of test case Item/feature Description Sample input 1 get command Transfer file from server to client ftp>get (remote file) hello.c (local file) hello1.c Expected output The contents of hello.c will be present in hello1.c Actual output The contents of hello.c will be present in hello1.c Remarks Test succeeded

Testing

5.2.2 Unit test Case 2


Sl No. of test case Item/feature 2 put command

Dept. of CSE, R.V.C.E

Feb-June-2012

20

File Transfer Protocol


Description Sample input Transfer file from client to server ftp>put (local file) abc1.c (remote file) abc.c Expected output The contents of abc1.c will be present in the abc.c Actual output The contents of abc1.c will be present in the abc.c Remarks Test succeeded

5.2.3 Unit test Case 3


Sl No. of test case Item/feature Description Sample input Expected output Actual output 3 Ls list all files in current directory ftp>ls Server.c client.c a.out Server.c client.c a.out Test succeeded

Testing

Remarks

5.2.4 Unit test Case 4


Sl No. of test case Item/feature Description Sample input Expected output Actual output 4 Delete command Delete the specified file in server ftp>delete dummy.c Delete command was successful Delete command was successful

Dept. of CSE, R.V.C.E

Feb-June-2012

21

File Transfer Protocol


Remarks Test succeeded

5.2.5 Unit test Case 5


Sl No. of test case Item/feature Description 5 Pwd(print working directory) command The current working directory will be displayed Sample input Expected output Actual output Remarks ftp>pwd Home/cs6c02/testing Home/cs6c02/testing Test succeeded

Testing 5.2.6 Unit test Case 6


Sl No. of test case Item/feature Description 6 cwd(change working directory) command The current working directory will be changed root directory Sample input Expected output Actual output Remarks ftp>pwd / / Test succeeded

Dept. of CSE, R.V.C.E

Feb-June-2012

22

File Transfer Protocol

Conclusion

6. CONCLUSION
6.1 Summary:
The project is an earnest attempt to create a network utility application that can facilitate file transferring and communication between server and client at the LAN level. The purpose of the project is to build an interface for file transfer between two or more terminals running on the same operating system. The scope of this is to have user friendly protocol at the client end that allows file transfer, changing the directory, listing files of server computer which or working on the same or different terminals(of same operating system). The project has been a great experience for both of us as such in learning the intricate details of writing code for network applications. The project also gave us an insight into the working of sockets as such and the file transfer in networking in general. It has given us lot of confidence to handle similar projects in the future.

Dept. of CSE, R.V.C.E

Feb-June-2012

23

File Transfer Protocol

6.2 Limitations:
The ftp has the following limitations It does not provide all the ftp commands. It doesnt provide more security options
The client can delete the files on the server computer.

The client using should know the knowledge about ftp commands

6.3 Further enhancements:


We had intended to improve this project by some enhancements. But due to lack of time we could not implement many of those features. The additional features that will make the project more effective are:
1. Implementing all the ftp commands

Conclusion

2. Providing a Graphical User Interface (GUI) for the users.

7. REFERENCES
[1] W. Richard Stevens, Advanced Programming in the UNIX Environment, Second Edition, Addison Wesley. [2] Behrouz A. Forouzan, Data Communication and Networking, Fourth edition, TMH [3] W. Richard Stevens, Network Programming in the UNIX using sockets and TLI, Volume 1, Second Edition, Addison Wesley [4] Andrew.S.Tanenbaum,Computer Networks, Fourth Edition, prentice Hall

Dept. of CSE, R.V.C.E

Feb-June-2012

24

File Transfer Protocol

Appendices

8. APPENDIX A SOURCE CODE LISTING


Header file:
//common.h #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdarg.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h>

Dept. of CSE, R.V.C.E

Feb-June-2012

25

File Transfer Protocol


#include <sys/wait.h> #include <signal.h> #define BUFLEN 100 void sendstring(int sockfd, const char* str); int readline(int clientfd, char* buf, int buflen); void print_all_that_you_can_read(FILE *write_to, int read_from_socket_fd); // common file common .c #include "common.h" void sendstring(int sockfd, const char* str) { int n = strlen(str); int left = n;

Appendices
{

while (left) int sent = send(sockfd, str, left, 0); if (sent == -1) { perror("send error"); exit(1); } left -= sent; str += sent; }

} int readline(int clientfd, char* buf, int buflen) { int len = 0;

Dept. of CSE, R.V.C.E

Feb-June-2012

26

File Transfer Protocol


char* ptr = buf; int left = buflen - 1; while (left > 0) { len = recv(clientfd, ptr, left, 0); if (len == 0 || len == -1) { perror("receive"); exit(1); } left -= len; if(ptr[len-2] == '\r' && ptr[len-1] == '\n') { ptr[len] = '\0'; return (buflen - left);

Appendices
}

ptr += len; } exit(1); } void print_all_that_you_can_read(FILE *write_to, int read_from_socket_fd) { char buffer[BUFLEN]; int len = 0; while ((len = recv(read_from_socket_fd, buffer, BUFLEN, 0)) != 0) { buffer[len] = '\0'; fputs(buffer, write_to); } fflush(stdout);

Dept. of CSE, R.V.C.E

Feb-June-2012

27

File Transfer Protocol


}

Server:
#include "common.h" #define SERVER_PORT 1234 #define LISTEN_SIZE 5 #define DATA_PORT_RANGE_START 20000 #define DATA_PORT_RANGE_END 20100 static const char* HELLO_MSG = "220 Welcome to my FTP server\r\n"; static char *CONTEXT = "parent";

// This server's external IP char *server_ip;

Appendices

// FTP passive mode implementation related info int data_port_open = 0; int data_port_fd = 0; int next_data_port = DATA_PORT_RANGE_START; // Type: ASCII (A) or Binary (I) char transfer_type = 'A'; int init_server(); void handle_client_connection(int clientfd, char* client_ip, int client_port); void handle_retr(int clientfd, const char*); void handle_auth(int clientfd); void handle_put(int clientfd, const char*); void handle_list(int clientfd); void handle_pwd(int clientfd); void handle_cwd(int clientfd, const char*);

Dept. of CSE, R.V.C.E

Feb-June-2012

28

File Transfer Protocol


void handle_quit(int clientfd); void handle_pasv (int clientfd); void handle_type (int clientfd, const char *); void handle_del (int clientfd, const char*); void handle_pass(int clientfd, const char*); void handle_user(int clientfd, const char*); int get_next_data_port(); void str_replace(char *str, char c, char replacechar); void logmsg(const char* format, ...) { va_list ap; va_start(ap, format); printf("%s: Appendices ", CONTEXT); vprintf(format, ap); } void set_my_server_ip() { // TODO: Determine server IP server_ip = "127.0.0.1"; } int main() { int serverfd, clientfd; struct sockaddr_in clientinfo; size_t clientinfolen = 0; pid_t pid; char client_ip[BUFLEN] = ""; int client_port; const char *ret = 0;

Dept. of CSE, R.V.C.E

Feb-June-2012

29

File Transfer Protocol

set_my_server_ip(); serverfd = init_server(); if (serverfd == -1) { logmsg("Initializing server failed\n"); exit(1); } while (1) { logmsg("Waiting for client connection...\n"); clientinfolen = sizeof(clientinfo); clientfd = accept(serverfd, (struct sockaddr *)&clientinfo, &clientinfolen); if (clientfd == -1) { perror("accept"); exit(1);

Appendices
}

ret = inet_ntop(AF_INET, &(clientinfo.sin_addr), client_ip, sizeof(client_ip)); if (ret == 0) { perror("inet_ntop"); } client_port = ntohs(clientinfo.sin_port); logmsg("Got connection from client IP=%s port=%d\n", client_ip, client_port); pid = fork(); if (pid == -1) { perror("fork"); exit(1); } else if (pid != 0) { // Parent

Dept. of CSE, R.V.C.E

Feb-June-2012

30

File Transfer Protocol


logmsg("Child process with PID %d created\n", pid); } else { // Child logmsg("In child process\n"); handle_client_connection(clientfd, client_ip, client_port); exit(0); } } } int init_server() { int sockfd = 0; int res = 0; int yes = 1; struct sockaddr_in servinfo;

Appendices

sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket"); logmsg("Error creating socket\n"); return -1; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } memset(&servinfo, 0, sizeof(servinfo)); servinfo.sin_family = AF_INET; servinfo.sin_port = htons(SERVER_PORT); servinfo.sin_addr.s_addr = INADDR_ANY;

Dept. of CSE, R.V.C.E

Feb-June-2012

31

File Transfer Protocol

res = bind(sockfd, (struct sockaddr*)&servinfo, sizeof (servinfo)); if (res == -1) { perror("bind"); return -1; } logmsg("Server listening on port %d\n", SERVER_PORT); res = listen(sockfd, LISTEN_SIZE); if (res == -1) { perror("listen"); return -1; }

Appendices
}

return sockfd;

int open_data_port(int *port) { int fd = socket(AF_INET, SOCK_STREAM, 0); int p = 0; int ret = 0; int yes = 1; struct sockaddr_in datasock; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } memset(&datasock, 0, sizeof(datasock));

Dept. of CSE, R.V.C.E

Feb-June-2012

32

File Transfer Protocol


datasock.sin_family = AF_INET; datasock.sin_addr.s_addr = INADDR_ANY; while (1) { logmsg("In open_data_port\n"); p = get_next_data_port(); logmsg("Next data port: %d\n", p); datasock.sin_port = htons(p); ret = bind(fd, (struct sockaddr *)&datasock, sizeof(datasock)); if (ret == 0) { ret = listen(fd, LISTEN_SIZE); if (ret == -1) { perror("listen"); return -1; } Appendices *port = p; return fd; } } logmsg("Failed to open data port"); exit(1); } int get_next_data_port() { int port = next_data_port++; if (port > DATA_PORT_RANGE_END) { port = DATA_PORT_RANGE_START; } return port; }

Dept. of CSE, R.V.C.E

Feb-June-2012

33

File Transfer Protocol

void process_request (int clientfd, const char* cmd, const char* args) { logmsg("Command = %s Args = %s\n", cmd, args); if (strcmp(cmd, "AUTH") == 0) { handle_auth(clientfd); } else if (strcmp(cmd, "USER") == 0) { handle_user(clientfd, args); } else if (strcmp(cmd, "TYPE") == 0) { handle_type(clientfd, args);

Appendices
} {

else if (strcmp(cmd, "PASS") == 0) handle_pass(clientfd, args); } else if (strcmp(cmd, "RETR") == 0) { handle_retr (clientfd, args); } else if (strcmp(cmd, "STOR") == 0) { handle_put (clientfd, args); } else if (strcmp(cmd, "LIST") == 0) { handle_list (clientfd);

Dept. of CSE, R.V.C.E

Feb-June-2012

34

File Transfer Protocol


} else if (strcmp(cmd, "PWD") == 0) { handle_pwd (clientfd); } else if (strcmp(cmd, "CWD") == 0) { handle_cwd (clientfd, args); } else if (strcmp(cmd, "QUIT") == 0) { handle_quit (clientfd); } else if (strcmp(cmd, "PASV") == 0) { } else if (strcmp(cmd, "DEL") == 0) { handle_del (clientfd, args); } else { logmsg("unknown command '%s'\n", cmd); sendstring (clientfd, "Invalid command sent to the server.\r\n"); } // sendstring (clientfd, "200 OK\r\n"); }

Appendices

handle_pasv (clientfd);

void handle_del (int clientfd, const char* args)

Dept. of CSE, R.V.C.E

Feb-June-2012

35

File Transfer Protocol


{ char filename[BUFLEN]; int len = strlen (args); int ret; strncpy (filename, args, len -1); filename[len-1] = '\0'; logmsg("Attempt to delete '%s'\n", args); ret = remove(filename); if (ret == 0) { sendstring (clientfd, "260 File successfully deleted\r\n"); } else {

Appendices

sendstring (clientfd, "421 File delete error\r\n"); logmsg ("File delete %s failed", args);

} } void handle_auth (int clientfd) { sendstring (clientfd, "530 User name and pass\r\n"); } void handle_user (int clientfd, const char* args) { if(strncmp(args, "ftp", 3) == 0) { sendstring (clientfd, "331 Enter password\r\n"); }

Dept. of CSE, R.V.C.E

Feb-June-2012

36

File Transfer Protocol


else { sendstring(clientfd, "425 Invalid user\r\n"); } } void handle_pass (int clientfd, const char* args) { if(strncmp(args, "adiarsh", 3) == 0) { sendstring (clientfd, "230 Welcome user\r\n"); } else { sendstring (clientfd, "426 Invalid password\r\n");

Appendices
} }

void handle_type (int clientfd, const char* args) { if (args[0] == 'A') { transfer_type = args[0]; sendstring (clientfd, "200 Switching to ASCII mode\r\n"); } else if (args[0] == 'I') { transfer_type = args[0]; sendstring (clientfd, "200 Switching to Binary mode\r\n"); } } void handle_pasv (int clientfd) {

Dept. of CSE, R.V.C.E

Feb-June-2012

37

File Transfer Protocol


char buf[BUFLEN] = ""; char *ip = strdup(server_ip); int data_port = 0; // Find a free port and bind it data_port_fd = open_data_port(&data_port); data_port_open = 1; str_replace(ip, '.', ','); int lowbyte = data_port & 0xFF; int highbyte = (data_port >> 8) & 0xFF; logmsg("Data port is: %d %d %d\n", data_port, highbyte, lowbyte); snprintf(buf, BUFLEN, "227 Entering Passive Mode (%s,%d,%d)\r\n", ip, highbyte, lowbyte); logmsg("Sending output: %s\n", buf); sendstring(clientfd, buf);

Appendices
}

void str_replace(char *str, char c, char replacechar) { char *ptr = str; for (ptr = str; *ptr != '\0'; ptr++) { if (*ptr == c) { *ptr = replacechar; } } } void handle_list (int clientfd) { struct sockaddr_in clientinfo;

Dept. of CSE, R.V.C.E

Feb-June-2012

38

File Transfer Protocol


size_t len = sizeof(clientinfo); FILE* fp; char buf[BUFLEN] = ""; int fd; char *ptr; logmsg("Waiting for client connection\n"); fd = accept(data_port_fd, (struct sockaddr *)&clientinfo, &len); if (fd == -1) { perror("accept"); exit (1); } logmsg("Client connected\n"); sendstring (clientfd, "150 Sending listing\r\n"); fp = popen ("ls -l", "r"); if (fp == NULL) { logmsg("File listing failed\n"); exit(1); } while ((ptr = fgets(buf, BUFLEN-1, fp))) { int buflen = strlen(buf); if (buf[buflen-1] == '\n') { buf[buflen-1] = '\r'; buf[buflen] = '\n'; buf[buflen+1] = '\0'; } sendstring(fd, buf);

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

39

File Transfer Protocol


} sendstring (clientfd, "226 Sent listing\r\n"); fclose(fp); close(fd); shutdown(fd, SHUT_RDWR); } void handle_cwd(int clientfd, const char* args) { char dir[BUFLEN]; int len = strlen (args); int ret; strncpy (dir, args, len -1); dir[len-1] = '\0'; logmsg("Attempt to chdir to '%s'\n", args); ret = chdir(dir); if (ret == 0) { sendstring (clientfd, "250 Directory successfully changed\r\n"); } else { sendstring (clientfd, "420 Dir change error\r\n"); logmsg ("Dir change %s failed", args); } } void handle_pwd (int clientfd) { char buffer[BUFLEN] = ""; char print_msg[BUFLEN] = ""; getcwd (buffer, BUFLEN);

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

40

File Transfer Protocol


snprintf (print_msg, BUFLEN, "257 \"%s\"\r\n", buffer); sendstring (clientfd, print_msg); } void handle_quit (int clientfd) { sendstring (clientfd, "221 QUIT\r\n"); shutdown(clientfd, SHUT_RDWR); close(clientfd); exit(0); } void handle_retr (int clientfd, const char* args) { struct sockaddr_in clientinfo; size_t len = sizeof(clientinfo); FILE* fp; char buf[BUFLEN] = ""; int fd; char *ptr; logmsg("Waiting for client connection\n"); fd = accept(data_port_fd, (struct sockaddr *)&clientinfo, &len); if (fd == -1) { perror("accept"); exit (1); } logmsg("Client connected\n"); fp = fopen (args, "r");

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

41

File Transfer Protocol


if (fp == NULL) { logmsg("File open failed: %s\n", args); sendstring(clientfd, "550 Failed to open file.\r\n"); close(fd); shutdown(fd, SHUT_RDWR); return; } sendstring (clientfd, "150 Getting file contents\r\n"); while ((ptr = fgets(buf, BUFLEN-1, fp))) { int buflen = strlen(buf); if (buflen > 0 && buf[buflen-1] == '\n' && transfer_type == 'A') { buf[buflen-1] = '\r'; buf[buflen] = '\n'; buf[buflen+1] = '\0'; } sendstring(fd, buf); } sendstring (clientfd, "226 File successfully received from server\r\n"); fclose(fp); close(fd); shutdown(fd, SHUT_RDWR); } void handle_put (int clientfd, const char* args) { struct sockaddr_in clientinfo; size_t len = sizeof(clientinfo);

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

42

File Transfer Protocol


FILE* fp; //char buf[BUFLEN] = ""; int fd;

logmsg("Waiting for client connection\n"); fd = accept(data_port_fd, (struct sockaddr *)&clientinfo, &len); if (fd == -1) { perror("accept"); exit (1); } logmsg("Client connected\n");

Appendices

fp = fopen (args, "w"); if (fp == NULL) { logmsg("File open failed: %s\n", args); sendstring(clientfd, "555 Failed to open file.\r\n"); close(fd); shutdown(fd, SHUT_RDWR); return; } printf("%s this is the file\n", args); print_all_that_you_can_read(fp, fd); sendstring(clientfd, "231 Successfully sent to server\r\n"); fclose(fp); close(fd); shutdown(fd, SHUT_RDWR);

Dept. of CSE, R.V.C.E

Feb-June-2012

43

File Transfer Protocol

return; } void handle_client_connection(int clientfd, char* client_ip, int client_port) { char buf[BUFLEN] = ""; char* ptr = buf; char* cmd = ""; char* args = ""; char* context = malloc (BUFLEN); snprintf (context, BUFLEN, "Child[%s:%d] ", client_ip, client_port); CONTEXT Appendices = context; logmsg ("Sending hello msg\n"); sendstring (clientfd, HELLO_MSG); while(1) { int argslen; readline (clientfd, buf, sizeof(buf)); logmsg ("Client says: %s", buf); ptr = buf; cmd = strsep(&ptr, " \r\n"); args = ptr; argslen = strlen(args); if (argslen > 0 && args[argslen-1] == '\n') { args[argslen-1] = '\0'; }

Dept. of CSE, R.V.C.E

Feb-June-2012

44

File Transfer Protocol


if (argslen > 1 && args[argslen-2] == '\r') { args[argslen-2] = '\0'; } process_request (clientfd, cmd, args); } }

Client:
#include "common.h" #define BUFLEN 100 int sockfd = -1; int is_connected = 0, is_user = 0, is_verified = 0; int clientfd = -1; char* server_ip; void process_command (const char*,char*); int turn_passive(); int make_connection(char* ip, int port) { struct sockaddr_in serverinfo; int res; socklen_t len; int fd = socket (AF_INET, SOCK_STREAM, 0); if (fd == -1) { printf("socket not created\n"); exit(1); }

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

45

File Transfer Protocol


serverinfo.sin_family = AF_INET; serverinfo.sin_port = htons (port); len = sizeof (serverinfo); inet_pton (AF_INET, ip, &serverinfo.sin_addr); res = connect (fd, (struct sockaddr*)&serverinfo, len); if (res == -1 ) { printf ("could not connect\n"); exit(1); } return fd; } void open_connection (char* args)

Appendices

int server_port; char buffer[BUFLEN]; server_ip = strdup(strsep (&args, " \r\n")); printf ("%s", args); server_port = atoi(args); printf("Server ip is %s port is %d\n", server_ip, server_port); clientfd = make_connection(server_ip, server_port); is_connected = 1; readline (clientfd, buffer, BUFLEN); printf("%s", buffer );

} void send_to_server(const char* cmd, const char* args) { int len = strlen(cmd) + strlen(" ") + strlen(args) + 3;

Dept. of CSE, R.V.C.E

Feb-June-2012

46

File Transfer Protocol


char* command = malloc(len); snprintf(command, len, "%s %s\r\n", cmd, args); sendstring(clientfd, command); free(command); } void handle_get (char* args) { char buffer[BUFLEN]; char* remote_file = NULL, *local_file = NULL; FILE *output = NULL; int serverfd = turn_passive();

Appendices

if (serverfd < 0) return; remote_file = strsep(&args, " "); local_file = args; if (local_file[strlen(local_file) - 1] == '\n') local_file[strlen(local_file) - 1] = '\0'; send_to_server("RETR", remote_file); readline(clientfd, buffer, BUFLEN); if (strncmp(buffer, "550", 3) == 0) { printf("%s", buffer); shutdown(serverfd, SHUT_RDWR); close(serverfd); return; } output = fopen(local_file, "w");

Dept. of CSE, R.V.C.E

Feb-June-2012

47

File Transfer Protocol


if (output == NULL) { printf("Failed to open output file: %s\n", local_file); shutdown(serverfd, SHUT_RDWR); close(serverfd); return; } print_all_that_you_can_read(output, serverfd); fclose(output); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); shutdown(serverfd, SHUT_RDWR); }

Appendices
{

void handle_put (char* args) char buf[BUFLEN]; char buffer[BUFLEN]; char* remote_file = NULL, *local_file = NULL; char * ptr; FILE *output = NULL; int i; int serverfd = turn_passive(); if (serverfd < 0) return; local_file = strsep(&args, " ");

remote_file = strsep(&args, "\r\n");

Dept. of CSE, R.V.C.E

Feb-June-2012

48

File Transfer Protocol

output = fopen(local_file, "r"); if (output == NULL) { printf("Failed to open local file: %s\n", local_file); shutdown(serverfd, SHUT_RDWR); close(serverfd); return; }

snprintf(buffer, BUFLEN, "STOR %s\r\n", remote_file);

Appendices

sendstring(clientfd, buffer); if (strncmp(buffer, "555", 3) == 0) { printf("%s", buffer); shutdown(serverfd, SHUT_RDWR); close(serverfd); return; }

while ((ptr = fgets(buf, BUFLEN-1, output))) { int buflen = strlen(buf); if (buflen > 0 && buf[buflen-1] == '\n') { buf[buflen-1] = '\r'; buf[buflen] = '\n'; buf[buflen+1] = '\0';

Dept. of CSE, R.V.C.E

Feb-June-2012

49

File Transfer Protocol


} sendstring(serverfd, buf); } fclose(output); close(serverfd); shutdown(serverfd, SHUT_RDWR);

readline(clientfd, buffer, BUFLEN); printf("%s", buffer); } void handle_list() { char buffer[BUFLEN]; int serverfd = turn_passive(); if (serverfd < 0) return; sendstring(clientfd, "LIST\r\n"); readline(clientfd, buffer, BUFLEN); print_all_that_you_can_read(stdout, serverfd); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); shutdown(serverfd, SHUT_RDWR); close(serverfd); } char *read_ip(char **buf) {

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

50

File Transfer Protocol


char *result = calloc(16, sizeof(char)); int i = 0; for (i = 0; i < 4; i++) { strncat(result, strsep(buf, ","), 3); if (i < 3) { strncat(result, ".", 1); } } return result; } int turn_passive() { Appendices char buffer[BUFLEN]; char *buf = NULL, *ip = NULL; int port_low_byte = 0, port_high_byte = 0, port_number = 0; sendstring(clientfd, "PASV\r\n"); readline(clientfd, buffer, BUFLEN); if (strncmp(buffer, "227", 3) != 0) { printf("Failed to turn on passive mode."); printf("Got error from server: %s", buffer); return -1; } buf = strchr(buffer, '(') + 1; ip = read_ip(&buf); port_high_byte = atoi(strsep(&buf, ","));

Dept. of CSE, R.V.C.E

Feb-June-2012

51

File Transfer Protocol


port_low_byte = atoi(strsep(&buf, ")")); port_number = (port_high_byte << 8) | port_low_byte;

Appendices
}

return make_connection(server_ip, port_number);

void process_command(const char* cmd, char* args) { char buffer[BUFLEN]; if (strcmp (cmd, "open") == 0) { printf("Opening\n"); open_connection(args); } {

Appendices

else if (is_connected && !is_verified && !is_user)

if(strcmp (cmd, "user") == 0) { send_to_server("USER", args); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); if(strncmp(buffer, "331", 3) == 0) { is_user = 1; }

Dept. of CSE, R.V.C.E

Feb-June-2012

52

File Transfer Protocol


else { printf("Enter user name first.\n"); } } else if(is_user && is_connected && !is_verified) { if(strcmp(cmd, "pass") == 0) { send_to_server("PASS", args); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); if(strncmp(buffer, "230", 3) == 0) { is_verified = 1; } } else printf("Invalid command. Enter correct password\n"); } else if(is_verified && is_user && is_connected) { if(strncmp (cmd, "pwd", 3) == 0) { sendstring(clientfd, "PWD\r\n"); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); } else if(strncmp(cmd, "cd", 2) == 0)

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

53

File Transfer Protocol


{ send_to_server("CWD", args); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); } else if (strncmp(cmd, "del", 3) == 0) { send_to_server("DEL", args); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); } else if(strncmp(cmd, "bye", 3) == 0) { sendstring(clientfd, "QUIT\r\n"); readline(clientfd, buffer, BUFLEN); printf("%s", buffer); shutdown(clientfd, SHUT_RDWR); close(clientfd); is_connected = 0; is_user = is_verified = 0; } else if(strncmp(cmd, "get", 3) == 0) { handle_get(args); } else if(strncmp(cmd, "put", 3) == 0) { handle_put(args); } else if(strncmp(cmd, "ls", 2) == 0) {

Appendices

Dept. of CSE, R.V.C.E

Feb-June-2012

54

File Transfer Protocol


handle_list(); } else { printf("Invalid command.\n"); }

} else { printf ("Not connected to server. Use open.\n"); return; }

Appendices
} int main() { char* ptr; char line[BUFLEN]; const char* cmd; char* args; printf("ftp> "); while((ptr = fgets(line, BUFLEN, stdin)) != NULL) { cmd = strsep (&ptr, " "); args = ptr; process_command (cmd, args); printf ("ftp> "); }

Dept. of CSE, R.V.C.E

Feb-June-2012

55

File Transfer Protocol


return 0; }

Appendices

APPENDIX B SNAPSHOTS

Dept. of CSE, R.V.C.E

Feb-June-2012

56

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

57

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

58

Appendices

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

59

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

60

Appendices

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

61

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

62

Appendices

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

63

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

64

Appendices

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

65

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

66

Appendices

File Transfer Protocol

Dept. of CSE, R.V.C.E

Feb-June-2012

67

Das könnte Ihnen auch gefallen