Interprocess Communication
   - A process is an instance of a program that is being executed by the OS.
 
   - In UNIX, the *only* way to create a process is with the fork()
     system call.
 
          -  The operating system creates the "init" process (that's
             PID 1).  The init process reads /etc/inittab to figure
             out what process to run next.
 
          -  Two important processes are "ttymon" that monitors terminals
             and "inetd" that starts networking programs.
 
   - Every process has a process ID (a PID) and a parent process ID
 
There are several ways that two prcessses can communicate:
 
    If the processes are on the same machine:
 
    1. A process can send a "signal" to another process (the OS can
       send a signal as well).
 
       - A signal is a notification to a process that an event has
         occurred.
 
       - Signals are "asynchronous".  That means a process does not know
         when they will occur.
 
       - Every signal has a signal number.
         Some examples:
 
             SIGINT   --  OS sends to a process when interrupt key is
                          hit (for example, control-C).
             SIGUSR1  --  User defined signal.
 
       - Every signal has a "default action".  For example, the kernel will
         send you a SIGSEGV if you access a bad memory location.  The default
         action for that is to dump core and exit.
 
       - You can change the default action.
 
       - For example:
 
            To send a signal:
 
            int kill(int pid, int signal_number)
 
            i.e.,  kill(1234, SIGUSR1);
 
            To handle a signal:
 
            void (*sigset (int sig, void (*disp)(int)))(int);
 
            i.e.,
 
               void doit(int);
 
               sigset(SIGUSR1, doit);
 
 
       - More on this later.........
 
 
     2.  Process can use file and record locking
 
         - advisory and mandatory
         - applications use lockf() and fcntl().
 
     3.  Process can use "semaphore" files
 
         -  process A does an action, then creates file_1 when done.
         -  process B checks if file_1 exists
 
     4. Process can use pipes.
 
        - Example:
 
                int filedes[2];
 
                if (pipe(filedes) < 0) {
                   printf("can't create pipe\n");
                   exit(1);
                }
 
         pipe() creates an I/O mechanism called a pipe and  returns
         two  file  descriptors,  fildes[0] and fildes[1].  The files
         associated with fildes[0] and fildes[1] are both  opened  for
         reading  and  writing.
 
         A read from fildes[0] accesses the data written to fildes[1]
         on  a  first-in-first-out  (FIFO)  basis  and  a  read  from
         fildes[1] accesses the data written to fildes[0] also  on  a
         FIFO basis.
 
         - General actions:
 
               - process creates a pipe;
               - fork;
               - parent closes filedes[0];
               - child closes filedes[1];
               - parent writes to filedes[1];
               - child reads from filedes[0];
 
     5. Process can use "Named Pipes"
 
        - A named pipes exists in the file system
 
                $ mknod /tmp/FIFO p
 
        - Process A can open and write;
        - Process B can open and read;
 
     6. Processes can use message queues, semaphores, and shared memory.
 
        - A message queue is memory in the kernel that lets
          process read and write to queues.
 
           - a process creates a message queue with the msgget() routine.
 
           - other processes can place data on the queue and extrace data from
             the queue by using msgsnd() and msgrcv().
 
        - A shared memory segment is common space in the kernel that
          several processes can read and write to.
 
           - use shmget() get create a shared memory segment, access
             it by mapping the memory to local variables with the
             shmat() routine.
 
           - semaphores allow synchronization.
 
    If the processes are on the different machines:
 
        USE THE NETWORK!
 
THE SOCKET INTERFACE - CONNECTION MODE SERVICE
        o Server routines:
 
            -- socket( )
                  o Creates a transport endpoint
                  o Specify datagram or virtual circuit
 
            -- bind( )
                  o Allows server to attach itself to an address
 
            -- listen( )
                  o Marks a transport endpoint as ``listen state''
 
            -- accept( )
                  o Returns an accepted connection
 
            -- read( )
                  o Reads data from transport endpoint
 
            -- write( )
                  o Writes data to transport endpoint
         
 
        o Client routines:
 
            -- socket( )
                  o Creates a transport endpoint
                  o Specify datagram or virtual circuit
 
            -- connect( )
                  o Binds to a return port
                  o Issues a connection request to server
 
            -- read( )
                  o Reads data from transport endpoint
 
            -- write( )
                  o Writes data to transport endpoint
GENERAL FLOW
 
                   Server
 
                  socket( )
                     |
                     |
                     |
                   bind( )
                     |                                 Client
                     |
                     |
                  listen( )                            socket( )
                     |                                     |
                     |                                     |
                     |                                     |
                  accept( )                            connect( )
                     |
                     |                                     |
                                                           |
                      <----------------------------------  |
                     |
                     |                                     |
                     |
 
                      <------------------------------  write( )
                   read( )                                 |
                     |                                     |
                     |                                     |
                     |                                     |
                     |                                     |
                                                           |
                                                           |
                   write( ) --------------------------->
                                                        read( )
 
         
SOCKET APPLICATION
        o We will implement the query protocol using the socket
          interface
        o The connection-oriented version uses TCP/IP
        o The connectionless version uses UDP/IP
        o Parts of the code (i.e., name lookup routines) will be
          different for other transport providers
 
SERVER CODE
          #include <stdio.h>
          #include <sys/types.h>
          #include <sys/socket.h>
          #include <netinet/in.h>
 
          #define SERV_PORT  5134
          #define MAXNAME    1024
 
          main()
          {
               int socket_fd;       /* file descriptor into transport */
               int recfd;           /* file descriptor to accept on   */
               int length;          /* length of address structure    */
               struct sockaddr_in myaddr; /* address of this service  */
               struct sockaddr_in client_addr; /* address of client   */
               signal(SIGCHLD, SIG_IGN);
 
               /* Get a socket into TCP/IP */
               if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                    perror("socket failed");
                    exit(1);
               }
 
               /*
                *  Set up our address
                */
 
               bzero((char *)&myaddr, sizeof(myaddr));
               myaddr.sin_family = AF_INET;
               myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
               myaddr.sin_port = htons(SERV_PORT);
NOTES
        o The sockaddr structure is defined as follows:
 
          struct sockaddr {
              u_short sa_family;
              char    sa_data[14];
          }
 
        o sa_family specifies the address family
        o sa_data holds the address
        o Applications cast transport specific addresses into this
          structure
 
        o The sockaddr_in structure holds internet addresses, and is
          defined as follows:
 
          struct sockaddr_in {
              short   sin_family;
              u_short sin_port;
              struct  in_addr sin_addr;
              char    sin_zero[8];
          };
 
        o sin_port is the port number
        o sin_addr is the host IP address (32 bits)
        o sin_zeros fills in the remaining 8 bytes of the address
          allocated in the sockaddr structure
SERVER CODE (cont.)
               /*
                *  Bind to the address the service will be offered
                *  over.
                */
 
               if (bind(socket_fd, (struct sockaddr *)&myaddr,
                                      sizeof(myaddr)) < 0) {
                    perror("bind failed");
                    exit(1);
               }
 
               /*
                *  Set the socket up for listening, with a queue
                *  length of 1
                */
 
               if (listen(socket_fd, 1) < 0) {
                    perror("listen failed");
                    exit(1);
               }