Table of Contents
- Table of Contents
- Overview
- Language Choices: C++, Python, Ruby
- JSON
- Project Success criteria
- Getting the Code
- Strategy
- Suggested schedule
- Studying the sample code
- More details on the frameworks and sample code
- You must write grading logs
- Hints and Warnings
- Hints and Warnings For Python and Ruby Users
- Teams
- Preparing your report
- Submitting your work for grading
- Commenting and code quality
Overview
One of the most important achievements of distributed system research is the ability to provide transparency: the network "disappears", so things that are remote appear to be local. In this assignment, you will implement your own remote procedure call system which will provide transparency for the invocation of simple C++ functions including those that accept as arguments and that return structured values.
You will do this in phases: first,
after studying extensive sample code that is provided for you,
you will learn to build the necessary proxies and stubs by hand,
and you will use those to demonstrate some simple programs transparently invoking functions remotely.
Later, you will implement your own rpcgenerate
program, which will take as input an Interface Definition Language file (IDL) in the form of a very simple C++ compatible header (.h),
and which will output the C++ source code for the proxy and the stub automatically.
This assignment should be interesting for several reasons. First of all, there is something almost magical about invoking an ordinary function and finding that it's actually executed on another computer at the other side of the network. Second, RPC illustrates the power of providing simple abstractions to wrap complex capabilities, and you will find out that what goes on under the covers to achieve even a simple remote procedure call is both complex and subtle. This is true of many distributed systems, including the Web. Finally, this will be an opportunity to do meta-programming, which involves having one program (your RPC generator) create or manipulate the code for other programs. Going back to the time of Alan Turing, computers have blurred in fascinating ways the line between programs and data, and it's when we do meta-programming that the power of this integration becomes clear.
A note on terminology
Many references use the terms like client stub and server stub for what we're calling proxy (client stub) and stub (server stub).
Language Choices: C++, Python, Ruby
The functions you call remotely and the code that invokes them are written C++, but we give you a choice of programming languages to use when building your rpcgenerate
proxy and stub generator.
- You write your
rpcgenerate
program in C++ and generate proxies and stubs in C++. You use the provided C++ framework to parse the .idl files into a parse tree that your generator can use.
- or - - You write your
rpcgenerate
program in your choice of Python or Ruby and it generates proxies and stubs in C++. You use the providedidl_to_json
program to convert the .idl files into the JSON format, which is easily read using standard libraries in both Python and Ruby.
Makefile
to automatically generate proxies and stubs using your rpcgenerate
program. If everything works right, you'll be able to write simple C++ programs that completely transparently
and automatically invoke functions on remote computers!
Note: in your generated C++ proxies you may use C/C++ features like sscanf
, stringstreams
and <<
if they are helpful for your formatting and parsing, and you can use STL constructs like vector
and map
. You must must not use things like Boost regexp libraries, libraries that generate or serialize structured data types for you, etc. So, you must not use libraries that generate or parse JSON in your C++ proxies or stubs (you will want to use the built in JSON parsing facilities in Python or Ruby if you use those languages to build your rpcgenerate
program; your proxies and stustubs must do their own message formatting and parsing). If you are not sure whether a particular library or feature may be used, please ask.
JSON
You will want to spend just a little
time learning about JSON, which
is a widely used data format for the Web and elsewhere.
For the C++ option, the idl_to_json.cpp
program we give you will be your model for learning to use the C++ interfaces
to our IDL parser; if you are using Python or Ruby, then you will be using the JSON
output of that program.
Many of you who have done Web programming will already know JSON;
for those who haven't seen it, learning will take you about 10 min. and JSON
is one of those file format technologies
that every 21st century programmer should know.
Project Success criteria
To succeed in this project you must:- For full credit: write a program named
rpcgenerate
that will generate proxies and stubs for any function that can be declared using the IDL format described in this assignment. - Partial credit: you will get significant credit for an
rpcgenerate
program that handles at least some non-trivial cases, e.g. that handles functions with multiple arguments of varying types and return values, but perhaps not the most complex cases like arrays of structs or structs containing arrays of structs, etc. (though, if you structure your code right, those cases shouldn't be too hard — that's a big hint!) - For (minimal) partial credit: if you cannot succeed
at creating the
rpcgenerate
program, you will get some credit for manually writing proxies and stubs to handle one or more of the sample interfaces and functions provided with this assignment. For a passing grade, you must successfully invoke a function that takes at least one struct as an argument, and that returns a non-void value. (I.e. just invoking the simple arithmetic functions is not sufficient.)
You must adapt the supplied Makefile to successfully build all the samples you want us to test.
Your generator program must be called rpcgenerate
and it must
open filenames passed on the command line; we may try it with our own test IDL when grading! The proxies and stubs you generate must follow the naming convention:
<idlname>.proxy.cpp
and <idlname>.stub.cpp
,
as we did for simplefunction.idl
, and these must compile to create the corresponding .o files using your Makefile
, regardless of the idl file name.
You may find it helpful to uncomment the lines invoking $(RPCGEN) in the Makefile
we provide you; this will cause make to call your rpcgenerator on IDL files when you ask to build things like xxxx.proxy.o
. Be careful, you might also wind up
calling your generator on simplefunction.idl
, and thereby writing
over the sample proxies and stubs we give you. You might want to make spare copies
just in case (or you can always retrieve from git.)
If we test with our own IDL, we will link your proxies and stubs with our own test application framework.
Note: although we provide a few IDL files and functions to start you on your testing, your goal is to support any legal IDL interface! Therefore, you should test your code not just with the provided samples, but with others that you create as unit tests for your code. To do that, you will have to write some IDL, and some test functions and clients to play with. (You can create yours by adapting the ones provided.)
Getting the Code
The code for this project is in three distribution directories, but most likely you'll only need to copy one of them; the others are referenced automatically from the make files.
/comp/117/files/RPC.samples
: this directory contains sample programs you can build, experiment with, and adapt to build your project. To get this code, do:git clone /comp/117/files/RPC.samples
After making yourself a local copy of theRPC.samples
directory, you can domake all
andmake clean
as usual. As noted above, we suggest you do agit clone
to get our code. Note that we may occasionally ask you to do agit pull
to update some of the sample programs if we improve them./comp/117/files/RPC.framework
contains the code for the IDL parser. As with other shared CS 117 frameworks, this should be accessed automatically by the makefile for the samples, presuming your environment variable is set in the usual way. Especially if you are writing your generator in C++, you will probably want to look at the header and .cpp files in this directory, though, to learn how the parser works./comp/117/files/c150Utils
: this is the network framework we've been using since the original UDP ping project. The only change is that the new c150streamsocket class has been added to support the TCP networking we will be doing in this RPC project.
Note that the directory that you ultimately submit with your implementaiton
must be named RPC
, but you will likely create it by adapting
what's in RPC.samples
.
Strategy
This project will be much easier if you approach it in an orderly way, making progress every week. We suggest you do the following steps in roughly the following order. This section provides a quick overview of the steps you will take; many are explored in much more detail later in this writeup.
Experiment with our code
Start by looking over and understanding our sample code. A detailed guide is provided below, and you should also look again at the slides from our in-class introduction.
In practice, you will almost surely want to learn to handle each case manually first.
So, you will probably want to start by manually implementing some proxies and stubs, first for the very simple cases like arithmetic
, and then for an example using structs or arrays.
To help you learn how things work, we provide a fully worked example of an idl file called simplefunction.idl
and just for that one we give you simplefunction.proxy.cpp
and
simplefunction.stub.cpp
, as well as simplefunctionclient.cpp
.
We also give you a Makefile
that builds runnable executables
simplefunctionclient
and simplefunctionserver
.
In short, we give you a completely worked example of runnable code that creates a network connection, and remotely invokes a trivial function.
If you understand how the code works you will figure out
that we build a simplefunctionserver
executable but there is in fact
no simplefunctionserver.cpp
source file, indeed, that will teach you why
why all servers are built from the same source file for the main
function.
You will also see how our code uses the c150streamsocket class, which is the TCP equivalent of the UDP support you used for filecopy.
Manually build some proxies and stubs
The next step is for you to manually build some proxies and stubs.
To get you started on that we've provided arithmetic.idl
, arithmetic.cpp
(which implements the functions), and arithmeticclient.cpp
.
Floating-point equivalents with names like floatarithmetic.idl
are also included.
We have not provided proxies and stubs for these, that's your job!
Doing that much should be simple, since it's a very small change beyond what we show you how to do for simplefunction.idl
.
Then go on to generate some proxies and stubs to handle structures and arrays.
You can either adapt some of the sample IDL that we provide, or create your own test cases.
You will have to provide your own unit tests similar to the ones we have created for arithmetic
and floatarithmetic
(I.e. we aren't implementing
the functions or the client for you at this point).
Learn about types, our IDL parser and the JSON generator.
This is a good time to learn about the type system and the IDL parser that we provide for you (you will want to carefully study https://www.cs.tufts.edu/comp/117/assts/rpc_typesystem). The parser is a C++ framework that we have written to process IDL files. Remember that for this project, IDL files are just a very restricted subset of C++ .h files, so the parser is basically parsing .h files.
Whether you are planning to use Ruby, Python or C++, you should become familiar
with the program we supply called named idl_to_json
.
That program
calls the parser on IDL file(s) you supply,
parses them, and prints the
results of the parse as a JSON file.
This program is valuable for at least three reasons:
- Because the test program prints the parsed information from any IDL file (.h file) you give it, you can use the test program to understand the types you will have to handle in your RPC system
- If you write your
rpcgenerate
program in C++, you are encourged to "steal" code fromidl_to_json.cpp
for use in yourrpcgenerate
program. This will make it easier for you to get at the type information. - If you are writing
rpcgenerate
in Python or Ruby, then you will actually call theidl_to_json
executable from your Python or Ruby code to translate the IDL into JSON. You will then run that through the Python or Ruby JSON parsers (the writeup on type information includes sample Python and Ruby code for doing this.)
Start planning your proxy and stub generator
As you better understand the type system, start thinking about how you
will structure an rpcgenerate
implementation to
automatically generate the proxies and stubs you will need. Don't try
to implement everything at once, but try from the start to build a
structure that will extend to handle the more complex cases.
Think hard about invariants, pre-conditions and post-conditions:
- As you're serializing a function argument into your message buffer, how will you represent different types?
- Think ahead: how will you handle more complex cases, like a structure that contains an array of integers? Can you share any code with the case where an argument is an array (I.e. not in a struct?)
- Consider your deserializer at the same time as your serializer: what information will it need to read in messages, e.g. when will it find out how long a message is (remember that TCP does not preserve message boundaries — it's just a stream of bytes. You must NOT close connections in between calls.)
Once you've got a strategy, and verified on paper that it's likely to work, start implementing the simple cases in rpcgenerate
, demonstrating that it can automatically generate the same sorts of proxies and stubs you did manually.
As noted above, you'll get partial credit for that.
The key to this project is thinking clearly: if you just start coding
rpcgenerate
you're likely to make a mess that won't scale; if you
have a clear design in mind for how the pieces will work together, and how the
message format is related to the function interfaces
and your generated code structures, this assignment can be done
quite cleanly and without terrible complexity!
Update your Makefiles
Assuming you've built an rpcgenerate
you must update
your Makefile
so that it will correctly build xxx.proxy.cpp
and xxx.stub.cpp
given xxx.idl
.
Some of the commented code already in the Makefile
may be helpful if uncommented (and if necessary adapted).
There's already a rule that builds a .o
from any .cpp
, so those rules together automatically give you .o
from .idl
.
With all that in place you can have client applications depend on xxx.proxy.o
and servers depend in the Makefile
on xxx.stub.o
.
Any source files that
include xxx.idl
should also have dependencies on that too, of course. Whenever your xxx.idl
changes and you redo your make, all of the following should happen automatically:
- Your
rpcgenerate
gets called to recreate the proxy and stub C++ source - The corresponding
.o
files get compiled usingg++
- If your program source includes the
.idl
, that source automatically recompiles - Your client and server executable(s) are relinked
This is very typical of how the tooling in a "real" RPC system works. Almost completely automatically, the remoting code needed for your functions is generated, compiled and linked. The client and server source code has almost nothing in it to suggest that remoting is happening, except for the one call we add in the client to make a connection to the server!
Suggested schedule
Intermediate work will not be collected and graded, but this assignment is way too big to tackle in one big push at the end. We strongly suggest that you stick to the following schedule:
- By Monday November 04, be familiar in detail with all the sample code provided. If possible, make minor modifications to
simplefunction.idl
and its associated proxies and stubs. Make sure that you can run the server and the client successfully, and that you understand what is in the logs that they produce. Also make sure you understand how the makefiles build the client, and especially the server: there may be a few details that surprise you, but they are important. - By Monday November 11, hand build proxies
for
arithmetic.idl
andfloatarithmetic.idl
and then go on to do structs and arrays. Your goal should be to have enough done for partial credit as described above, and to give you the background you need to design yourrpcgenerate
program. - After building proxies by hand, design and code the RPC generator to generate proxies and stubs automatically. The expected due date for final submissions is Wednesday November 27.
If there is anything you don't understand when reviewing the samples, please ask! It will be very difficult for you to complete your work successfully if you don't understand them. You do not have to understand the internals of the IDL parser framework, but for the RPC generator phase, you do have to know how to use it,
either by calling the parser from C++, or by using idl_to_json
to generate
json that will be used by your Python or Ruby program..
Studying the sample code
As noted above, we give you some completely worked samples and of course the parsing code and JSON generator.
So, what's missing in the samples? Several things. Keep in mind the two main goals you will be trying to achieve: first to learn how to write proxies and stubs by hand, and second to write a program that will generate them automatically. Anyway, among the crucial things missing in the samples that you will eventually have to provide are:
- The samples remotely invoke trivial functions that take no arguments and return no return value. You will have to figure out how to write proxies and stubs that resolve both of those shortcomings, and that will be capable of dealing with structured as well a simple types (details below).
- As noted above, an IDL parser has been written for you, but there is no sample RPC generator. So, as you read the provided proxies and stubs, and as you think about how to enhance them to deal with arguments and return values, you should also be thinking about how you would write a program to generate such proxies and stubs automatically given the parsed IDL as input.
Suggested order of study for sample code:
It's suggested that you work in the following order to learn what's been provided to you and plan your project:
- Read and experiment with the pingstreamclient/pingstreamserver to learn to use dgmstreamsocket, which is a wrapper for TCP streams (very similar to, and based on c150dgmsocket, so studying this should be easy).
- Look at the
simplefunction.idl
and compare it to the formal grammar for IDL - Study very carefully
simplefunctionclient
,simplefunctionserver
, and thesimplefunction.proxy/simplefunction.stub
that they use.- Make sure you understand how the makefile builds the pieces.
- Check especially the way that
rpcserver.cpp
is used as the main() forsimplefunctionserver
, and how it could be used again for many other such servers - Note that the
rpcproxyhelper
andrpcstubhelper
set a global variable with thec150streamsocket
so the proxies and stubs can get them without extra arguments (which would change their signatures)
- Now look at some of the more complex IDL examples provided for you. Make sure you understand how function arguments, types and especially structured types like structs and arrays work. Note that some examples use arrays of structs, and others have structs with arrays; fully general nesting is possible.
- Play with
idl_to_json
. Give it your own idl files and see what it does. If you are doing a C++ generator, now is the time to carefully readidl_to_json.cpp
to see how it builds and walks through the parse tree. This is exactly what yourrpcgenerate
program will have to do. Feel free to steal the code, as long as you fix the comments.
Studying the sample remote application
Before reading this section, you might want to review the slides presented in class that explain what's discussed below.
It's inherent in the nature of RPC that multiple separately compiled files have to be brought together in ways that are sometimes subtle. This is because the client and the server need to agree on the interface to each function that is to be available remotely, yet they need different implementations. Specifically, for each IDL file to be prepared for remote use:
- The actual implementations of the functions need to be available in a source file, compiled, and linked with the server which will call them. Indeed, this is likely to be the same source file that would be used if the entire program ran locally.
- Similarly, there will be a client application program (actually, you could write as many as you like) that makes calls to what it believes to be local functions.
- For use at the client side, we need to build manually or using the RPC generator a C++ proxy code that implements the same function signatures, but which packages the arguments for each, sends them using a protocol (of your design) to the server, where a dispatch routine in the stub chooses which function to call. Having done that, control passes to a function-specific stub which reconstructs the arguments, calls the function, gathers the return value if any, and sends a response back to the client.
- Similarly, the server needs a manually or automatically generated stub, which reads messages from the socket and calls the requested function.
For our project, the IDL files are a very restricted subset of C++ .h file syntax, so the IDL files can be #include
'd directly into the applications, proxies, and stubs to ensure that all have the correct interface.
More information on the IDL files is provided below.
More details on the frameworks and sample code
The following sections briefly discuss the frameworks and samples that are new for this assignment:
c150streamsocket
For the file copy assignment you used a class named c150dgmsocket
to provide convenient UDP services.
For this assignment, a similar class named c150streamsocket
is available and is used by the samples.
It implements a simple TCP stream-based client/server.
To help you learn it, slightly modified versions of the ping samples are provided:
these are called pingstreamclient
and pingstreamserver
.
If you study these, it should be trivial to figure out how to use c150streamsocket
in the intended manner.
Please make sure right away that the samples work for you, so we can debug problems early.
A couple of details may not be quite obvious about the stream classes:
first of all, as is the case with all TCP streams, message boundaries are not preserved. If you do two writes of 50 bytes each it's quite possible that a read of 75 bytes
will succeed, leaving 25 bytes to be read the next time.
Also: UNIX and Linux sockets provide very flexible facilities for writing servers that deal with multiple clients at a time. The framework provided to you does not try:
it implements a model in which you accept a connection, work with it until there is no more incoming data (read eof), then close the connection and accept another.
Those of you who are familiar in detail with socket programming will know that doing all this usually requires an extra socket for accepting connections, plus one for each actual client connection.
That is hidden from you by the c150streamsocket
class: you do the accepts and the reads/writes on the same instance, and there can be at most one connected client at a time.
Most of the other details should be familiar from the UDP framework, or else should be obvious from the provided samples.
Note that the sample proxies and stubs provided for you (discussed below) also
show how c150streamsocket
is used.
Sample remote application: proxies, stubs and IDL
As noted above, a complete pair of client and server, with proxies and stubs is provided to illustrate the remoting of three trivial functions.
The applications are simplefunctionclient
and
simplefunctionserver
.
The client takes a server name as argument; the server takes no arguments.
The remoted functions are declared in the file named simplefunction.idl
.
Note that this is syntactically a C++ header file and is included several places in the sample.
Provided for you are handwritten proxies and stubs corresponding to this IDL:
simplefunction.proxy.cpp
and simplefunction.stub.cpp
.
Study these! Look at the way they are linked into the client and server applications. Look at how they are handled in the Makefile. Understand how the proxy appears to the client application so that it can make func1
, func2
and
func3
appear to be local.
Look in simplefunction.stub.cpp
and be sure you understand why it has routines with names like __func1
. Why can't we just name those func1
?
By the way, the simple protocol illustrated in these proxies and stubs isn't very robust. You will be modifying or replacing it anyway when you design your own promoting protocol to support arguments and return values. (The provided one just sends the function name as a null-terminated string. The server responds with null-terminated strings "DONE" or "BAD" depending on whether the function name was recognized. I suspect that, for reasons discussed in class, you may want to send explicit lengths rather than using nulls to delimit strings in your protocol.)
If you do a make all
you will find two applications built using the proxy and the stub: simplefunctionclient
and simplefunctionserver
.
Try these on our virtual servers, being sure to start the server end first.
Note that the usual debug framework is available and the log files should show you quite a bit about what the proxies and stubs are doing.
You must write grading logs
To make it easier for us to grade your project, we are asking that you put useful information into grading log files just as you did with the file copy assignment. The general instructions are exactly the same.
- Make sure you
#include "c150grading.h"
in any file that writes to the grading log - In your main programs ( that is in your client programs, and also in the server),
be sure to do the following:
// // DO THIS FIRST OR YOUR ASSIGNMENT WON'T BE GRADED! // GRADEME(argc, argv);
You can assume that we will do this for you in any clients we use to invoke your functions. You should do it in your clients so you can test that theGRADING
output you write from your proxies is as you intend. *GRADING
is a C++ output stream, so you can do grading output like this:*GRADING << "The sum of 100 + 20 + 3 is: " << 100+20+3 << endl;
Please record all significant events with data. Specifically, record at the server and the client when you are handling a request to invoke a function or return value, and provide useful information about the messages that you send using TCP.
Hints and Warnings
Here are a few additional hints and warnings regarding this project:
- In C++, the
string
type declaration needs to be included, and it lives in the std namespace (the full type name isstd::string
). Any source file that includes any of our IDL files that usesstring
should first do:#include <string> using namespace std;
If you don't, thestring
type will come up as undefined. - Be sure to test your implementation with functions that return no value.
First of all, such functions are useful to users, but more importantly,
we may use them in testing other features such as your ability to handle
various types of arguments. Specifically, it's reasonable if in your proxy for a function with this signature:
int add(int x, int y);
...you generate code that looks like this:int result = add(x_arg, y_arg); // argument and result names your up to you
...but for a function like this that returns no value:void somefunc(int x, int y);
...it's of course not OK to generate this:void result = somefunc(x_arg, y_arg);
We see this mistake from time, to time, and if we are using such "void" functions to test other features, you could lose credit for those! - You will want to avoid spending a lot of time writing code to format the C++ source that your
rpcgenerate
program needs to create for proxies and stubs. The best ways to do this depend on which language you're using:- C++: One trick for doing that is to make a template of a proxy and a template of the stub in a file, using unique placeholder strings such as XXXFUNCTIONSTUBSHEREXXX
where you expect to insert code dynamically.
Use whatever technique you like to build up the actual dynamically created code such as the stub for a function in a C++ string.
Read the template file into another C++ string, and use functions like
find()
to locate your placeholders, andreplace()
to replace the placeholder with your dynamically generated code. You can use this trick for the whole file, as well as to template pieces that you may need to generate repeatedly. - Ruby: Ruby has syntax for very long strings that honor newlines. They have the strange name HEREDOC, but don't worry about that. You can do something like this (be careful to use double quotes on "END_MARKER" so you get escapes ane #{} interpolation:
code = << "END_MARKER" class #{getName() { int #{varname1}; int #{varname2}; } END_MARKER
That will produce acode
string with roughly the following after callinggetname()
and assumingvarname1
is X andvarname2
is Y.class className { int X; int Y; } END_MARKER
- Python: Python string interpolation is now quite
similar since Python 3 has introduced the formatted string literals.
Furthermore, this works with triple quoted multiline lstrings like this:
code = f"""class {classname} {{ int {varname1}; int {varname2}; }} """
Important: Note the letterf
ahead of the triple quote; that's what enables variable and expression substitution in the string.code
will be set to the string (making the same assumptions about the variable values as we did in the Ruby example):class someClass { int x; int y; };
- C++: One trick for doing that is to make a template of a proxy and a template of the stub in a file, using unique placeholder strings such as XXXFUNCTIONSTUBSHEREXXX
where you expect to insert code dynamically.
Use whatever technique you like to build up the actual dynamically created code such as the stub for a function in a C++ string.
Read the template file into another C++ string, and use functions like
Hints and Warnings For Python and Ruby Users
We will be adding hints and warnings here as we get more experience using Python and Ruby. For now:
- Remember that your program must be named
rpcgenerate
, notrpcgenerate.py
orrpcgenerate.rb
- You can make your program executable by making sure the very first line says:
#!/bin/env python3
or#!/bin/env ruby
Of course, you also need to make sure that you set execute permissions:chmod u+rwx rpcgenerate
If you do all this correctly, you will be able to run your program just as you would a C++ executable. - A sample Python program for getting type information and sample Ruby program for getting type information are discussed in the type system introduction.
Teams
The rules regarding programming teams will be the same as for the file copy assignment. You may work with the same partner as last time if you prefer, but where practical you are encouraged to switch as you will probably learn more by working with different partners on different assignments. Remember: you and your partner must not split the work. You must do all design, coding, and debugging in person, together.
WARNING: this is a very substantial assignment and you will likely find it much easier to complete if you have a partner. As always, we expect that both partners will be substantially involved in all significant design work, but this RPC project can involve a fair amount of detail work, such as preparing the boilerplate text for proxies and stubs once your basic design has been established. It is acceptable to divide up such tasks as long as both students are fully aware of what is being done, and as long as the core architectural decisions, code generation architecture, and protocol design are done jointly. Where students work alone for good reason, e.g. if they are based off-campus, expectations will be adjusted accordingly. Students who choose to work alone in spite of partners being available will not benefit from such accommodation.
Preparing your report
As with the file copy assignment, the report you submit with your project will be a significant part of the grading process, but unless you've done something unusual, the necessary report will probably be much briefer. The template includes a few standard questions, and has a section where you can add any additional details we might need.
Template for report - Download template for report
Submitting your work for grading
Before you submit, we urge you to reread the section on Hints and Warnings. There might be a reminder there of something you need to fix before submitting.
The following are the steps you should take to prepare and submit your work. If you are on a team, one student should follow these steps, and the other should follow the instructions under team submission below. (same as for the file copy assignment)
Preparing your work for submission
Please consider the following checklist before submitting your work:
- Ensure that all your progams build correctly with
make all
. It's essential that you not be using any private versions of the shared libraries in /comp/117/files/c150Utils. You should submit a single directory and makefile containing everything we need to test. If there is any standard code you've retained from RPC.samples, include that as well. - Do a "make clean" to remove all object and executable files
- Delete any GRADELOGs, debug logs, or other additional files that may have wound up in your directory.
- Make sure you have followed the instructions in Preparing your report. As with your code, the report must be joint work, with all team members contributing equally (obviously it's OK to do a bit of copy editing and formatting separately, but the content should be joint work)
Submitting your work
One team member from each team should submit the code and report described above:
cd <parent-directory> provide comp117 rpc RPC rpcreport.html <explain.txt>
RPC
must be the name of the directory in which your code is built. rpcreport.html
is your report. In most cases explain.txt
need not be provided, but this is the place for the submitting team member to give explanations of any personal issues that might need attention (explanations for lateness, illness, etc.) Information related to actually running and grading the submission should be in the report itself.
Instructions for team members
If you are a member of a team, then one of you should submit your complete project as described above. Immediately after that's done, the other should:
provide comp117 rpc teamreport.txt <explain.txt>
teamreport.txt should be a short text file indicating your name, and your team member's name. It should indicate: "I hereby certify that the submission by <partner's name> on <date> and <time> is our joint submission. Both the code and the report included with that submission are our joint work, and should be the basis for my grade for the rpc assignment."
If you there is any additional information, e.g. relating to personal issues (illness etc.) then either partner can provide that in an explain.txt file, as usual. As noted above, information related to actually running and grading the submission should be in the report itself.
Commenting and code quality
Please be sure to follow the CS 117 coding standards. In programs of this complexity it's particularly important that you organize and comment your code so that a grader can figure out how it works. If your code is not pleasant to read, well organized, and reasonably well commented, you will lose credit. Even code that works may not be judged well if we can't easily figure out why it works.
This assignment is a little unusual, because there is C++ code you will write by hand in the obvious way, and C++ that will be written by your RPC generator. The former must conform to the course coding standards. We understand that things like indenting for generated code can be tricky, and we don't expect you to burn lots of time on that. We do suggest, for your benefit and ours, that you make the generated code as easy to read and debug as you conveniently can.
WARNING: in past years, we were disappointed by the code quality of many of the file copy submissions (we are still working on this year's Filecopy grading). Deductions for that assignment were modest, on the assumption that expectations might not have been clear.