Thursday, May 7, 2009

Cycle 3: Implement a Subnet of FTP using TCP/IP :: Part 2

Address Structure

The Berkeley socket interface provides a set of defined C structures that helps you handle different endpoint addresses and other socket programming duties.The most important structure you
will work with is the sockaddr_in structure. Its purpose is to provide a standard way of handling endpoint addresses for network communications. The sockaddr_in structure contains both an IP address and a protocol port number. The structure looks like this:

struct sockaddr_in {
short sin_family; /* type of address */
u_short sin_port; /* protocol port number */
/* network byte ordered */
struct in_addr sin_addr; /* net address for the remote host */
/* network byte ordered */
char sin_zero[8]; /* unused, set to zero */
};

struct in_addr {
uint32_t s_addr; /* Internet address */
};


Using Socket Functions

Core Functions

You can’t have a client without having a server first.


socket()

socket() is a critical function. Without it, your application cannot communicate with a network. socket() is used to create a network endpoint, and it returns a socket descriptor that is used later by other functions.

int socket(int domain, int type, int protocol);

socket() returns a –1 if there is an error. Otherwise, the value returned is the descriptor to the socket.


bind()

Now that we’ve created our socket, we need to bind it to an address. Simply creating a socket doesn’t do anything—you have to give it a place to go, much like creating a file doesn’t do much unless you save it to disk somewhere. The bind() function is used to bind the socket to a given address once the socket is created.


int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

The first value bind() needs is our socket descriptor. The second parameter is a pointer to the sockaddr structure we discussed earlier, while the third parameter is the length of the sockaddr structure. In this example, we’ll use the constant INADDR_ANY to signal that we want to bind to all of our local host’s addresses.


listen()

The next function we need is listen(). This function tells our socket that we’re ready to accept connections, and it also specifies a maximum number of connections that can be queued before connections are refused.


int listen(int s, int backlog);

backlog is the value that determines the connection queue. A typical value for backlog is 5, though it can be larger as needed. Some systems, however, such as BSD-based systems, limit the value at 5, so if you’re going to port your application to other environments besides Linux, don’t rely on backlog being greater than 5. Note that with Linux versions after 2.2, only completely established sockets are counted in the queue, instead of incomplete connection requests.

The call to listen() is successful, a value of 0 is returned:


accept()

int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

accept() takes our socket descriptor, a pointer to the address structure, and
the length of the address structure as its parameters. The key thing to remember
with this function is that it will typically run in an endless loop. The only time
you want a network server to stop listening is when you shut it down manually.
Otherwise, your application should be listening and accepting connections con-
stantly.

accept() is a blocking function. That means your application will wait at the accept() function call until a connection request is received from a client. This behavior is configurable, but the default blocking behavior is typically the desired behavior.

The structures passed to accept() are client related, not server related. As you can see in the preceding example, the second and third parameters passed to accept() are locations for storing information about the client, not about the server. When started, the value for the client name is set to 0, as is the length of the name. When a call from accept() returns, both of the structures should be populated with correct information. On success, accept() returns a new socket descriptor for the new connection.


write()

ssize_t write(int fd, const void *buf, size_t count);

write() writes up to count bytes of the contents of buf to the designated descriptor, in this case our child socket.


close()

Lastly, we need to do some cleanup. Use the close() function to close your sockets:

int close(int fd)

The first thing to do is close our child socket as soon as the write to the client is done.

Wednesday, May 6, 2009

Cycle 3: Implement a Subnet of FTP using TCP/IP :: Part 1

This look tough..where will we go? thanx to the Unix for the concept of "socket".so lets us detail every thing abt socket.

Socket

Essentially, a socket is an abstraction for network communication, just as a file is
an abstraction for file system communication.In general, an application that performs net-
work input and output needs to perform the five basic functions : open, close, read, write, and control.

Sockets are a basic component of interprocess and intersystem communication. A socket is an endpoint of communication to which a name can be bound. It has a type and one or more associated processes.

The concept of socket was created by the Berkeley Unix team.By extending the file/file descriptor concept, it is easy to visualize communicating across a network. To communicate across a network, a connection (socket) to the network must be opened. Once it’s opened, data is read from or written to the socket. When communication is finished, the connection to the network is closed and the resources used by the socket are released.

Sockets can be used in two ways. Once created, a socket can wait for an incoming connection, or it can initiate a connection to another socket on a remote host, or even its own local host in some cases. A socket used by a client program to initiate a connection to a server is known as an active socket. A socket that acts as a server and waits for an incoming connection is known as a passive socket.

Using Socket

The sequence of function calls for two simple socket applications: a client and a
server is shown below.



On the client side, the application creates the socket with socket(), calls
connect() to connect to the server, and then interacts with the server by using
write() to send requests to the server and read() to read responses from the
server. When the client is finished, it calls close().

On the server side, the application creates the socket with socket(), and then
calls bind() to specify which local address and port to use, and then proceeds to
call listen() to set the length of the connection queue. The connection queue is
the number of requests that the application should hold while waiting for the
server to process any current request. Once the connection queue is set, the
server calls accept() and waits until the next connection request arrives from the
client. When the request arrives, the server uses read() and write() to read the
request and write the response. When finished, the server calls close() to termi-
nate the connection to the client and returns to the accept() function, where it
waits for the next connection request from a client.

The socket() function allow for the possibility that other protocols might be used instead of
TCP/IP .

int socketpair(int domain, int type, int protocol)

Family --> Protocol or address family (AF_INET for TCP/IP; AF_UNIX for internal)
Type --> Type of service (SOCK_STREAM for TCP; SOCK_DGRAM for UDP)
Protocol --> The protocol number to use, typically a zero (0) to use the default for a
given family and type.

A call to socket(), then, for the purposes of opening a connection to another
host and communicating with TCP, would look like this:

mySocket = socket(PF_INET, SOCK_STREAM, 0);

Mailbox or message Queue : Part 3



then when i press the enter button



The first, messagesend.c adds messages to the message queue, and messagercv.c retrieves them.

the code of messagesend.c is

#include stdio.h
#include stdlib.h
#include errno.h
#include sys/types.h
#include sys/ipc.h
#include sys/msg.h

struct my_msgbuf {
long mtype;
char mtext[200];
};

int main(void)
{
struct my_msgbuf buf;
int msqid;
key_t key;

if ((key = ftok("messagesend.c", 'B')) == -1)
{
perror("ftok");
exit(1);
}

if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1)
{
perror("msgget");
exit(1);
}

printf("Enter lines of text, ^D to quit:\n");

buf.mtype = 1; /* we don't really care in this case */
while(gets(buf.mtext), !feof(stdin))
{
if (msgsnd(msqid, (struct msgbuf *)&buf, sizeof(buf), 0) == -1)
perror("msgsnd");
}

if (msgctl(msqid, IPC_RMID, NULL) == -1)
{
perror("msgctl");
exit(1);
}

return 0;
}


the code of messagerecv.c is

#include stdio.h
#include stdlib.h
#include errno.h
#include sys/types.h
#include sys/ipc.h>
#include sys/msg.h

struct my_msgbuf {
long mtype;
char mtext[200];
};

int main(void)
{
struct my_msgbuf buf;
int msqid;
key_t key;

if ((key = ftok("messagesend.c", 'B')) == -1)
{ /* same key as kirk.c */
perror("ftok");
exit(1);
}

if ((msqid = msgget(key, 0644)) == -1)
{ /* connect to the queue */
perror("msgget");
exit(1);
}

printf("Ready to receive messages.\n");

for(;;)
{ /* Spock never quits! */
if (msgrcv(msqid, (struct msgbuf *)&buf, sizeof(buf), 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("Reciever : \"%s\"\n", buf.mtext);
}

return 0;
}


the output is interesting ..it is fun..try it..
Run two terminals..type the message where u r sending ...and press enter to see what happens in the other terminal..

Mailbox or message Queue : Part 2

Sending a message to the queue

Each message is made up of two parts, which are defined in the template structure struct msgbuf, as defined in sys/msg.h:

struct msgbuf {
long mtype;
char mtext[1];
};

The field mtype is used later when retrieving messages from the queue, and can be set to any positive number. mtext is the data that will be added to the queue.

Look,the above struct has data type mtext of size 1 byte.Well,it is not a big problem.We 'll create a struct like tht below

typedef struct msgbuf {
long mtype;
char mtext[MSGSZ];
} message_buf;

MSGSZ set to 128.

Ok, so how do we pass this information to a message queue? Just use msgsnd():

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid is the message queue identifier returned by msgget(). The pointer msgp is a pointer to the data you want to put on the queue. msgsz is the size in bytes of the data to add to the queue. Finally, msgflg allows you to set some optional flag parameters, which we'll ignore for now by setting it to 0.

the code snippnet showing msgsnd()

key_t key;
int msqid;
message_buf pmb = {1,"Hello I'm here"};

key = ftok("/home/beej/somefile", 'b');
msqid = msgget(key, 0666 | IPC_CREAT);

msgsnd(msqid, &pmb, sizeof(pmb), 0); /* stick him on the queue */


Receiving from the queue

there is a counterpart to msgsnd(): it is msgrcv().A call to msgrcv() that would do it looks something like this:

key_t key;
int msqid;
struct pirate_msgbuf pmb; /* where L'Olonais is to be kept */

key = ftok("/home/beej/somefile", 'b');
msqid = msgget(key, 0666 | IPC_CREAT);

msgrcv(msqid, &pmb, sizeof(pmb), 1, 0); /* get him off the queue! */

There is something new to note in the msgrcv() call: the 1! What does it mean? Here's the synopsis of the call:

int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

The 1 we specified in the call is the requested msgtyp. Recall that we set the mtype arbitrarily to 1 in the msgsnd() section of this document, so that will be the one that is retrieved from the queue.

Additional notes:

The behavior of msgrcv() can be modified drastically by choosing a msgtyp that is positive, negative, or zero
Zero --> Retrieve the next message on the queue, regardless of its mtype.
Positive --> Get the next message with an mtype equal to the specified msgtyp.
Negative --> Retrieve the first message on the queue whose mtype field is less than or equal to the absolute value of the msgtyp argument.

Destroying a message queue

You have to destroy a message queue.It is important that you do this so you don't waste system resources.There are two ways:

1. Use the Unix command ipcs to get a list of defined message queues, then use the command ipcrm to delete the queue.
2. Write a program to do it for you.

Often, the latter choice is the most appropriate, since you might want your program to clean up the queue at some time or another.msgctl() comes as our handy for this.

The synopsis of msgctl() is:

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

Of course, msqid is the queue identifier obtained from msgget(). The important argument is cmd which tells msgctl() how to behave. It can be a variety of things, but we're only going to talk about IPC_RMID, which is used to remove the message queue. The buf argument can be set to NULL for the purposes of IPC_RMID.

the code snipnets will be:msgctl(msqid, IPC_RMID, NULL);

And the message queue is no more.

Mailbox or message Queue : Part 1

The basic idea of a message queue or a mailbox is simple:Two (or more) processes can exchange information via access to a common system message queue. The sending process places via some message-passing module a message onto a queue which can be read by another process.

Each message is given an identification or type so that processes can select the appropriate message. Process must share a common key in order to gain access to the queue in the first place.

IPC messaging lets processes send and receive messages, and queue messages for processing in an arbitrary order. Unlike the file byte-stream data flow of pipes, each IPC message has an explicit length.Messages can be assigned a specific type. Because of this, a server process can direct message traffic between clients on its queue by using the client process PID as the message type.

Before a process can send or receive a message, the queue must be initialized through the msgget function and the operations to send and receive messages are performed by the msgsnd() and msgrcv() functions, respectively.

Initialising a message Queue

The msgget() function initializes a new message queue:

int msgget(key_t key, int msgflg)

msgget() returns the message queue ID on success, or -1 on failure (and it sets errno, of course).The first, key is a system-wide unique identifier describing the queue you want to connect to (or create). Every other process that wants to connect to this queue will have to use the same key. The other argument, msgflg tells msgget() what to do with queue in question. To create a queue, this field must be set equal to IPC_CREAT bit-wise OR'd with the permissions for this queue.


What about this key nonsense? How do we create one? one way is to use the ftok() function which generates a key from two arguments:

key_t ftok(const char *path, int id);

Basically, path just has to be a file that this process can read. The other argument, id is usually just set to some arbitrary char, like 'A'. The ftok() function uses information about the named file and the id to generate a probably-unique key for msgget(). Programs that want to use the same queue must generate the same key, so they must pass the same parameters to ftok().

the example showing the use of ftok() and msgget()

#include sys/msg.h

key = ftok("/home/beej/somefile", 'b');
msqid = msgget(key, 0666 | IPC_CREAT);

In the above example, I set the permissions on the queue to 666 (rw-rw-rw-) ie.,110 110 110.

Note:the three permission possible is r w x...read,write,execute. the above permission rw-rw-rw-
allows the root,user and group respectively to read and write only but not execute.

msqid will be used to send and receive messages from the queue.

Tuesday, May 5, 2009

Pipe() example


pipes are more simple form of IPC. Written in Unix for the first time .Now, let us clear some useful points.
you know about "FILE *" from stdio.h, right? You know how you have all those nice functions like fopen(), fclose(), fwrite(), and so on? Well, those are actually high level functions that are implemented using file descriptors, which use system calls such as open(), creat(), close(), and write(). File descriptors are simply ints that are analogous to FILE *'s in stdio.h.

Open --> Prepare for input or output operations.
Close --> Stop previous operations and return resources.
Read --> Get data and place in application memory.
Write --> Put data from application memory and send control.
Control (ioctl) --> Set options such as buffer sizes and connection behavior.

ok? here some more useful data.....For example, stdin(standard input) is file descriptor "0", stdout(std output) is "1", and stderr(std error) is "2".

Basically, pipe() takes an array of two ints as an argument. Assuming no errors, it connects two file descriptors and returns them in the array. The first element of the array is the reading-end of the pipe, the second is the writing end.

Now,let us work ..

First, we'll have the parent make a pipe. Secondly, we'll fork(). Now, the fork() man page tells us that the child will receive a copy of all the parent's file descriptors, and this includes a copy of the pipe's file descriptors. Alors, the child will be able to send stuff to the write-end of the pipe, and the parent will get it off the read-end. Like this:

the reason i omit <> is tht it is the syntax of html..

#include sys/types.h
#include unistd.h
#include stdio.h
#include stdlib.h

int main()
{

int pfds[2];
pid_t childpid;
char buf[30];
if(pipe(pfds)>= 0)/* pipe() executed and if success*/
{
/* now fork()*/
childpid=fork();
if( childpid >= 0 )
{
if(childpid ==0)
{
/*child process*/
printf("Hi..I'm child process..");
printf("Writing 'HELLO' to the pipe ... ");
/*child write some data */
write(pfds[1],"HELLO",7);
printf("\nChild : Exiting..Bye...");
exit(0);
}

else
{
printf("\n\nHi..I'm parent...Reading from the pipe");
/*parent read data from child*/
read(pfds[0],buf,7);
printf("\nParent: the child say %s",buf);
printf("\nParent: Exiting..Bye\n");
exit(0);
}
}
else
{
perror("Fork");/*error in executing fork()*/
exit(0);
}
}
else
{
perror("pipe");/*error in executing pipe() */
exit(0);
}
}

Fork() example





the fork() is a system call commonly used in Unix/Linux system. the idea is to spawn/create child process. when a program executes the fork() call,let call that program 'parent' and the new created process will be called as 'child'

the fork() when successfully executes, return the child's pid to the parent and return 0 to the child. Now,why the fork() return child's pid to the parent? to hav parent know so that tracking become simple.

In the case of failure the fork() return -1 ,the perror() display error message according to the types of errors encountered.
The errors in executing the fork() are
1) EAGAIN
The system lacked the necessary resources to create another process, or the system-imposed limit on the total number of processes under execution system-wide or by a single user {CHILD_MAX} would be exceeded.

2) ENOMEM
Insufficient storage space is available.

lets peep at the example,well it is a complex but nevertheless u need to know all this..Actually the below code is important...documantation is there...

the reason i omit <> is tht it is the syntax of html..

#include unistd.h /* Symbolic Constants */
#include sys/types.h /* Primitive System Data Types */
#include errno.h /* Errors */
#include stdio.h /* Input/Output */
#include sys/wait.h /* Wait for Process Termination */
#include stdlib.h /* General Utilities */

int main()
{
pid_t childpid; /* variable to store the child's pid */
int retval; /* child process: user-provided return code */
int status; /* parent process: child's exit status */

/* only 1 int variable is needed because each process would have its
own instance of the variable
here, 2 int variables are used for clarity */

/* now create new process */
childpid = fork();

if (childpid >= 0) /* fork succeeded */
{
if (childpid == 0) /* fork() returns 0 to the child process */
{
printf("CHILD: I am the child process!\n");
printf("CHILD: Here's my PID: %d\n", getpid());
printf("CHILD: My parent's PID is: %d\n", getppid());
printf("CHILD: The value of my copy of childpid is: %d\n", childpid);
printf("CHILD: Sleeping for 1 second...\n");
sleep(1); /* sleep for 1 second */
printf("CHILD: Enter an exit value (0 to 255): ");
scanf(" %d", &retval);
printf("CHILD: Goodbye!\n");
exit(retval); /* child exits with user-provided return code */
}
else /* fork() returns new pid to the parent process */
{
printf("PARENT: I am the parent process!\n");
printf("PARENT: Here's my PID: %d\n", getpid());
printf("PARENT: The value of my copy of childpid is %d\n", childpid);
printf("PARENT: I will now wait for my child to exit.\n");
wait(&status); /* wait for child to exit, and store its status */
printf("PARENT: Child's exit code is: %d\n", WEXITSTATUS(status));
printf("PARENT: Goodbye!\n");
exit(0); /* parent exits */
}
}
else /* fork returns -1 on failure */
{
perror("fork"); /* display error message */
exit(0);
}
}