Wednesday, November 27, 2013

Unix Network Programming: Simple Client Server using Sockets

To keep this program simple
  1. The server accepts connection from a single client only
  2. The server doesn't fork new process to handle client requst
  3. Client sends only a single message to server and server replies back with another message

Algorithm

Server

  1. Create socket
  2. Bind
  3. Listen
  4. Accept connection
  5. Read data sent by client
  6. Send data back to client
  7. Close socket descriptors
Client

  1. Create socket
  2. Connect to server
  3. Send data to server
  4. Receive data from server
  5. Close socket descriptors

Program

server
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define SERVERPORT 3098
#define SERVERIP "192.168.1.4"
#define SIZE 10
#define DEFAULT_FLAG 0
int main()
{
    int sockfd, newsockfd, n;
    int addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in *serveraddr = (struct sockaddr_in *)malloc(addrlen);
    struct sockaddr_in *clientaddr = (struct sockaddr_in *)malloc(addrlen);
    char buff[10];

    /* Create socket */
    if((sockfd = socket(AF_INET, SOCK_STREAM, DEFAULT_FLAG))<0)
    {
        printf("Error: Socket creation failed... Exiting...\n");
        return 0;
    }
  
    /* Bind */
    bzero(serveraddr,addrlen);                // Initailize serveraddr as null. defined in <string.h>
    serveraddr->sin_family = AF_INET;        // Set address family as INET
    serveraddr->sin_port = SERVERPORT;
    serveraddr->sin_addr.s_addr = inet_addr(SERVERIP);    // Convert character string to dotted decimal format. Defined in <arpa/inet.h>
    if(bind(sockfd, (struct sockaddr*) serveraddr, addrlen)<0)
    {
        printf("Error: Bind failed... Exiting...\n");
        return 0;
    }
  
    /* listen */
    listen(sockfd,4);
    printf("Server waiting for connection request . . .\n");
  
    /* Accept connection */
    if((newsockfd = accept(sockfd, (struct sockaddr*)clientaddr, &addrlen))<0)
        printf("Error: Accepting connection request failed\n");
    else
        printf("Connection Accepted \n");

    /* Read data sent by client */
    n = recv(newsockfd, buff, SIZE, DEFAULT_FLAG);
    buff[n] = '\0';
    printf("Message Received: %s\n",buff);
  
    /* Send replt to client */
    strcpy(buff,"Thank You");
    send(newsockfd, buff, strlen(buff), DEFAULT_FLAG);

    /* Close both socket descriptors*/
    close(newsockfd);
    close(sockfd);
    return 0;
}


client

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define SERVERPORT 3098
#define SERVERIP "192.168.1.4"
#define SIZE 10
#define DEFAULT_FLAG 0
int main()
{
    int sockfd,n;
    int addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in *serveraddr = (struct sockaddr_in *)malloc(addrlen);
    char buff[10];

    /* Create socket */
    if((sockfd = socket(AF_INET, SOCK_STREAM, DEFAULT_FLAG))<0)
    {
        printf("Error: Socket creation failed... Exiting...\n");
        return 0;
    }
  
    /* Connect to server */
    bzero(serveraddr, addrlen);                // Initailize serveraddr as null. defined in <string.h>
    serveraddr->sin_family = AF_INET;        // Set address family as INET
    serveraddr->sin_port = SERVERPORT;
    serveraddr->sin_addr.s_addr = inet_addr(SERVERIP);    // Convert character string to dotted decimal format defined in <arpa/inet.h>
    if(connect(sockfd, (struct sockaddr*)serveraddr, addrlen)<0)
    {
        printf("Error: Connection failed... Exiting...\n");
        return 0;
    }else
        printf("Connection to server established successfully . . . \n");
  
    /* Send data to Server */
    printf("Enter Message to be sent ");
    scanf("%s",buff);
    send(sockfd, buff, strlen(buff), DEFAULT_FLAG);
  
    /* Read reply from server */
    n = recv(sockfd, buff, SIZE, DEFAULT_FLAG);
    buff[n] = '\0';
    printf("Message from Server: %s\n",buff);

    /* Close socket descriptor */
    close(sockfd);
    return 0;
}


Output

server window
Server waiting for connection request . . .
Connection Accepted
Message Received: Welcome

client window
Connection to server established successfully . . .
Enter Message to be sent Welcome
Message from Server: Thank You


Friday, November 22, 2013

Unix Network Programming: FTP using message queue

Algorithm

Create a structute that defines a message item in the message queue, say messageBuf

Client Side
  1. Get a message queue
  2. Read a filename from the standard input
  3. Set the message type as 1 and send the message
  4. Read messages of type 2 from the mesaage queue
  5. display the contents read
Server Side
  1. Get a message queue
  2. Read the filename from the meassage queue with type as 1
  3. Open requested file
  4. Read contents from the file and write into the message queue with type as 2
  5. Close the file

Program

message.h
 
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

#define PERMS 0666
#define KEY1 2345
#define TYPE1 100
#define TYPE2 111
#define SIZE 20

struct messageBuf{
    int type;
    char msg[SIZE];
}

server
#include<stdio.h>
#include<malloc.h>
#include<fcntl.h>
#include<string.h>
#include "message.h"
main()
{
    int mq1,fd,n;
    struct messageBuf *m1 = (struct messageBuf *)malloc(sizeof(struct messageBuf));
    if(mq1 = msgget(KEY1,PERMS|IPC_CREAT)<0)
        printf("Error: Message Q unavaillable\n");
    msgrcv(mq1,m1,sizeof(struct messageBuf),TYPE1,0);
    printf("File Requested:%s\n",m1->msg);
    fd = open(m1->msg, O_RDONLY, 0);
    if(fd<0)
        printf("Error: Unable to open requested file\n");
    do
    {
        n = read(fd,m1->msg,SIZE);
        m1->type = TYPE2;
        msgsnd(mq1, m1, n, 0);
    }while(n==SIZE);
    close(fd);
}

client
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include "message.h"

main()
{
    int mq1,n;
    struct messageBuf *m1 = (struct messageBuf *)malloc(sizeof(struct messageBuf));
    if(mq1 = msgget(KEY1,PERMS|IPC_CREAT)<0)
        printf("Error: Message Q unavaillable\n");
    printf("Enter Required file name: ");
    scanf("%s",m1->msg);
    m1->type = TYPE1;
    msgsnd(mq1, m1, strlen(m1->msg),0);
    do{
        n = msgrcv(mq1,m1,SIZE,TYPE2,0);
        printf("%s",m1->msg);
    }while(n==SIZE);
}

Run the server and client from two different windows

Output

Client window

Enter Required file name: message.h
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

#define PERMS 0666
#define KEY1 2345
#define TYPE1 100
#define TYPE2 111
#define SIZE 20

struct messageBuf{
    int type;
    char msg[SIZE];
}

Server window
File Requested:message.h

Thursday, November 21, 2013

Unix Network Programming: Process synchronization using semaphore

Algorithm


main() function
  1. Create a semaphore
  2. fork()
  3. In both parent and child
    1. Obtain lock by calling lock() function
    2. sleep for some time
    3. unlock by calling unlock() function
lock() function
  1. Create array of sembuf with size two
    1. First element waiting for semaphore to be zero
    2. Second element incrementing it
  2. Do semop with the created array as argument
unlock() function
  1. Create array of sembuf with size one
    1. The element decrementing semaphore
  2. Do semop with the created array as argument

Program

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#define PERMS 0666
#define KEY 1234

main(){
    int pid,semid,i;
    semid = semget(KEY, 1, IPC_CREAT|PERMS);
    pid = fork();
    if(pid == 0){                // Child Process
        for(i=1;i<=5;i++){
            printf("%d: Child waiting for lock\n",i);
            lock(semid);
                printf("%d: Child has the lock\n",i);
                sleep(1);
                printf("%d: Child unlocking\n",i);
            unlock(semid);
        }
    }else{                        // Parent Process
        for(i=1;i<=5;i++){
            printf("%d: Parent waiting for lock\n",i);
            lock(semid);
                printf("%d: Parent has the lock\n",i);
                sleep(1);
                printf("%d: Parent unlocking\n",i);
            unlock(semid);       
        }
    }
}

lock(int id){
    struct sembuf op_lock[2]={
        0, 0, 0,                   // Wait for id to be 0
        0, 1, 0                    // Then increment it
    };
    semop(id, op_lock,2);
}

unlock(int id){
    struct sembuf op_unlock[1]={
        0, -1, IPC_NOWAIT        // Decrement semid by 1
    };
    semop(id,op_unlock,1);
}

Output

1: Parent waiting for lock
1: Parent has the lock
1: Child waiting for lock
1: Parent unlocking
2: Parent waiting for lock
1: Child has the lock
1: Child unlocking
2: Child waiting for lock
2: Parent has the lock
2: Parent unlocking
3: Parent waiting for lock
2: Child has the lock
2: Child unlocking
3: Child waiting for lock
3: Parent has the lock
3: Parent unlocking
4: Parent waiting for lock
3: Child has the lock
3: Child unlocking
4: Child waiting for lock
4: Parent has the lock
4: Parent unlocking
5: Parent waiting for lock
4: Child has the lock
4: Child unlocking
5: Child waiting for lock
5: Parent has the lock
5: Parent unlocking
5: Child has the lock
5: Child unlocking

Unix: File permissions


File Permissions in Unix


Every user on a Unix system has a unique username, and is a member of at least one group. This group information is held in the password file (/etc/passwd). A user can also be a member of one or more other groups. The auxiliary group information is held in the file /etc/group. Only the administrator can create new groups or add/delete group members.
Every directory and file on the system has an owner, and also an associated group. It also has a set of permission flags which specify separate read(r), write(w) and execute(x) permissions for the 'user' (owner), 'group', and 'other' (everyone else with an account on the computer) The 'ls -l' command can be used to view the permissions and group associated with files in current directory.
An example of the output produced by ls -l is shown below.
drwxr-xr-x 2 teacher staff 4096 Nov 21 15:05 Desktop
drwxr-xr-x 2 teacher staff 4096 Nov 12 10:32 Documents
drwxr-xr-x 2 teacher staff 4096 Nov 21 15:44 Downloads
drwxr-xr-x 2 teacher staff 4096 Nov 12 10:32 Music
-rw-r--r-- 1 teacher staff 406558 Nov 21 10:23 NPrecord.odt
drwxr-xr-x 2 teacher staff 4096 Nov 22 11:14 Unix Programming
Each line in the output has the following fields
Field 1: a set of ten permission flags.
Field 2: link count (don't worry about this)
Field 3: owner of the file
Field 4: associated group for the file
Field 5: size in bytes
Field 6-8: date and time of last modification
Field 9: name of file
The permission flags are interpreted as follows
Position         Meaning
1                        directory flag, 'd' if a directory, '-' if a normal file, something   else occasionally may appear here for special devices.
2,3,4                  read, write, execute permission for User (Owner) of file
5,6,7                  read, write, execute permission for Group
8,9,10                read, write, execute permission for Other
Given below is the interpretation for the symbols used in permission flag
Value             Meaning
-                        in any position means that flag is not set
r                       file is readable
w                      file is writable. On a directory, means you can add or delete files
x                       file is executable. On a directory, means you can list the files in that directory
So if we interpret the very first line of the output given above, we can understand that: Desktop is a directory owned by teacher, who belongs to the group staff, the size of the folder is 4096 bytes and was modified on Nov 21 15:05 hours. The permissions for owner is read, write and execute while the other members of the group staff has permissions only for reading and executing(i.e. no write permissions) and users who doesn't belong to the group also has permissions for reading and executing. 

Setting permissions

chmod command can be used to change the permissions of a file.
syntax: chmod {a,u,g,o} {+,-} {r,w,x} files
      Value   Meaning
       
       a           all users 
      u           the owner 
      g           the owner group 
      o           others (neither u, nor g)
      +           give permission 
      -            remove permission
e.g. chmod g+rw files give the group read and write permission
 

Numbers can also be used to set the permissions
The number equivalents of r, w, x are:
                              r        w        x
OWNER(USER)    400    200    100
GROUP                40      20      10
PUBLIC                4        2        1
      e.g. (i) 700 means read write and execute permissions for owner(400 + 200 + 100) and no permissions for group(0) and others(0).
             (ii) 666 means r and w for owner, group and others   
The real stuff behind this is that the permissions for each are defined using 3 bits, with 9 bits defining the whole permission. where the last bit specifying an execute permission, the middle bit specifing write permission and the last bit read permission so a binary 100(octal 4) means r for owner and 111(octal 7). represents rwx for owner.