CS 3113: Project 2

Objectives

The objectives of this project are for you to:

Overview

For project 1, you implemented a program composed of two pieces:

In particular, the API provided a specific set of functions for manipulating the storage file.

For project 2, we will keep these two pieces the same, except that they will become their own processes and the interaction between them will be through a pair of named pipes. Specifically, we will implement a client-server model of interaction, with the user interface acting as the client and the storage component acting as a server.

Proper Academic Conduct

The code solution to this project must be done individually. Do not copy solutions to this problem from the network and do not look at or copy solutions from others. However, you may use the net for inspiration and you may discuss your general approach with others. These sources must be documented in your README file.


Specification

Named Pipes

Add a rule in your Makefile to create two named pipes in the local directory. In Linux, a named pipe can be created at the command line through this command:
mkfifo PIPE_NAME
where PIPE_NAME is the name of the pipe as it will appear in the file system.

Your two pipes are:

In C, you can open named pipes just as you would any file, including specifying whether you will open the pipe for reading or writing (note that a process should only choose one of these).

A word of caution: the open() system call on a pipe will block until the other end is also opened. For example, if your process opens a named pipe for writing, the open() system call will not return until after another process has opened the same pipe for reading. One implication is that if two processes are trying to open a pair of pipes (one to read and the other to write), make sure that you open them in the same order. For this project, you must open pipe_in first and then pipe_out.


Storage API

The storage API does not change from the prior project.


Storage_Remote API

The Storage_Remote API provides exactly the same functions (names, parameters and return values) as the Storage API. Once implemented, you will be able to link it with your project2.c code with no real changes to your code.

The key difference with the Storage API is that this new API interacts with the server process through the pipes in order to implement its four key functions. The protocol for interacting with the server is defined below.


project2

project2.c (along with the Storage_Remote API) implements the client process. This file is a copy of project1.c with the following changes:

Note that the STORAGE structure in storage_remote.h has changed slightly:

typedef struct 
{
  int fd_to_storage;
  int fd_from_storage;
} STORAGE;

It now stores file descriptors for information going to the storage server and coming from the storage server.


server

server.c implements (along with storage.c) the server program. The server is an infinite loop that:

Note that once you start the server, it will continue to execute, even after the client sends a SHUTDOWN message.


Messages

The key components of the communication protocol are defined in comm.h:
// Possible types of messages
typedef enum  {WRITE_REQUEST = 0, READ_REQUEST, ACKNOWLEDGE,
	       DATA, SHUTDOWN, INIT_CONNECTION} MessageType;

// Message header
typedef struct
{
  MessageType type;   // Type of the message
  int len_message;    // Length of data sent in message after header
  int location;       // Location to read/write in file
  int len_buffer;     // Length of bytes to read/write in file
}HEADER;

Any message that is sent from one process to the other will be contain an instance of the HEADER type. The header contains the type of the message. If additional data needs to be sent in addition to the header, then the length of the data will be stored in HEADER.len_message. The HEADER will then be followed by exactly this number of bytes.

The header also contains HEADER.location and HEADER.len_buffer. These values are used for specifying in the remote file the offset and the length of the data to be copied into or out of the file.

You can create and initialize an instance of the header on the stack with the following code:

HEADER h;
h.type = SHUTDOWN;
h.len_message = 0;
h.location = -1;       // These value is not used for SHUTDOWN messages,
h.len_buffer = -1;     // but it is good practice to set them to known values


Communication Protocol

There are four different types of interactions that can occur between the client and the server, corresponding to the four API function implemented in storage_remote.c. All interactions are initiated by the client and always have a response from the server.

init_storage()

STORAGE * init_storage(char * name);

close_storage()

int close_storage(STORAGE *storage);

get_bytes()

int get_bytes(STORAGE *storage, unsigned char *buf, int location, int len);

put_bytes()

int put_bytes(STORAGE *storage, unsigned char *buf, int location, int len);


Notes


Testing

Your testing procedue will be as follows:

Notes:


Examples

The user interaction is identical to that in project 1, so the project 1 test cases still stand.


Submitting Your Program


Grading Criteria


Downloads

The following file contains several header and skeleton C files: project2_skel.tar. These skeleton files are good starting points for the source files that you must implement.

We will make our project1 implementation available as a starting point, but only after the project 1 late deadline.


Hints


Addenda


andrewhfagg at gmail.com

Last modified: Tue Oct 1 09:42:10 2019