/* * Include this header file to gain access to the fishnet API. * Start by looking at the API section. */ #ifndef __FISH_H__ #define __FISH_H__ /* Some standard includes here so you don't need to do them */ #include #ifndef WIN32 #include #endif #include /*-------------------------------------------------------------------------- * fishnet constants *--------------------------------------------------------------------------*/ /* Don't pick a fishnet address larger than this: it won't work! */ #define MAX_NODE_ADDRESS 9999 /* * This Fishnet address allows you use fish_send() to send a frame to all * immediate neighbors. */ #define ALL_NEIGHBORS 0 /* * This Fishnet address allows you use fish_send() to send a frame to a * randomly selected immediate neighbor. */ #define ANY_NEIGHBOR -1 /* Packet size limits. The total packet length must be less than the * maximum transmission unit (MTU). */ #define MTU 1024 /* Th time-to-live or TTL limits the number of hops a packet can * take, in order to prevent loops. */ #define MAX_TTL 16 /* These are the different kinds of packets that can be sent over the * fishnet, where each kind corresponds to a protocol. */ #define FISH_PROTOCOL_ERROR 0 #define FISH_PROTOCOL_ECHO_REQUEST 1 #define FISH_PROTOCOL_ECHO_RESPONSE 2 #define FISH_PROTOCOL_ROUTING 3 #define FISH_PROTOCOL_TRANSPORT 4 #define FISH_PROTOCOL_MAX 5 // upper bound, not a real protocol /* Levels for use with fish_debug(). During fish api calls, debugging * information is sent to stderr. These levels control what debugging * information is displayed; if the current debug level is at least the * level of the message, the message will be displayed. * * See also fish_setdebuglevel(). */ #define FISH_DEBUG_NONE 0 // No debugging messages #define FISH_DEBUG_APPLICATION 1 // Print debug messages for the app // You may use 2 as an extra level #define FISH_DEBUG_TRANSPORT 3 // Print debug messages for transport // You may use 4 as an extra level #define FISH_DEBUG_ROUTING 5 // Print debug messages for routing #define FISH_DEBUG_TOPOLOGY 6 // Print messages for topology changes #define FISH_DEBUG_ALL 7 // Print message when a frame is sent // or received #define FISH_DEBUG_INTERNAL 8 // Print libfish internal debug messages /*-------------------------------------------------------------------------- * fishnet structures and datatypes *--------------------------------------------------------------------------*/ /* receive_handler is the type of the upcall registered with fish_recvhook() * to receive packets from the networks. This tells you the arguments that * a receive handler must accept. It doesn't return anything. */ typedef void (*receiv_handler)(int from, // the address of the neighbor who // sent the frame void* frame, // the frame received int frame_length); // the length of the frame in bytes /* keyboard_handler is the type of the * upcall registered with fish_keybhook(). Your keyboard input * handler will take one parameter: *line_of_text*, which does not * include the newline character ('\n'), but is null-terminated so* * that functions like sprintf will work. */ typedef void (*keyboard_handler) (char* line_of_text); /* A generic packet has the common header given below, plus data. * * Depending on the type of packet, there will be further structure to * the data. For example, if the packet is a transport packet then there * will be a transport header too. * * Note that the source and destination addresses are for the entire life * of the packet. The src addres should be the address of the node that * creates the packet, and the dst address should be the address of the * node the packet will eventually end up at. You shouldn't change the * src or dst fields as you forward a packet through the network. */ struct header { int src; // source address int dst; // destination address int ttl; // time-to-live counter int protocol; // the protocol type }; #define PACKET_HEADER_SIZE (sizeof(struct header)) #define PACKET_DATA_SIZE (MTU - PACKET_HEADER_SIZE) struct packet { struct header hdr; // the packet header char data[PACKET_DATA_SIZE]; // the rest of the packet }; /*-------------------------------------------------------------------------- * fishnet API calls *--------------------------------------------------------------------------*/ /* * NOTE: * Any fishnet API call may abort and dump core on failre (e.g., if it is * given bad arguments). An error message will be printed, and you can use * gdb to help you figure out what happened. */ /* fish_joinnetwork adds your node to the Fishnet network and is * generally the first function you will call. * * The host and port arguments describe the fishhead to contact, which * is synonymous with the network that you are joining. You supply your * requested node address to this call. You may also supply a domain * name, which will influence the topology of a hierarchical Fishnet. * The call will either succeed, in which case you have joined a Fishnet, * or will fail, printing an error message and exiting. There are a * variety of possible errors, such as not being able to contact the * fishhead or the address you wanted already being in use. * * Note that this function will exit the program on failure. */ extern void fish_joinnetwork(const char* fishhead_location, // In the format "host:port" const char* domain, // The domain to run your node in int addr); // Your address, between 1 and // MAX_ADDRESS /* fish_getheadhost can be used to get the name of the fishhead host after * fish_joinnetwork has been called. */ extern const char* fish_getheadhost(void); /* fish_getheadport can be used to get the fishhead port after * fish_joinnetwork has been called. */ extern int fish_getheadport(void); /* fish_getaddress can be used to get the fishnet node address after * fish_joinnetwork has been called. */ extern int fish_getaddress(void); /* fish_getdomain can be used to get the fishnet domain name after * fish_joinnetwork has been called. */ extern const char* fish_getdomain(void); /* fish_recvhook registers a function that you write to be called at a * later time when a frame is received from the network. * * This is considered an "upcall": You tell libfish what function to call * when a packet is received, rather than you caling a function directly * to receive a packet. Your function will be called from the fish_main * function when a packet is received. The function you register using * fish_recvhook will get the packet, and can do anything it likes with * it, but must return after it is finished since no further packets can * be received until this happens. * * Note that the memory in which the frame is stored belongs to libfish; * you MUST NOT free it. * * To register your receive handler as an upcall, define a function with * the same signature as receive_handler, and pass the name of the function * into fish_recvhook(). */ extern void fish_recvhook(receive_handler recvhandler); /* fish_keybhook registers a function that you write to be called at a * later time when a line of keyboard input is available. * * Like recvhook, it is an upcall that gets called from inside * fish_main. It can do anything it likes with the input, but must * return before further inut can be received. * * Note that the memory in which the input is stored belongs to libfish; * you MUST NOT free it. */ extern void fish_keybhook(keyboard_handler keybhandler); /* fish_send sends a frame to an immediate neigbhor, given the neighbor's * address and the packet itself as a byte array. * * It can be called any time after a node has joined a network. * * There are three special addresses you can send to besides those of your * immediate neighbors. You can send a frame to yourself (your own address). * You can also send a frame to the ALL_NEIGHBORS address or the * ANY_NEIGHBOR address defined above. * * The frame is data of any type, e.g. a (struct packet *). * * The frame_length should be exactly the number of bytes that are used in * the frame, e.g., for a packet, the length of the packet header plus the * length of the data it contains. * * The function returns 0 on success and -1 on failure. */ extern int fish_send(intdest, // address to send to void* frame, // pointer to the frame int frame_length); // length of the frame in bytes /* fish_main is the main fishnet loop. Calling fish_main() is the last * thing you should do in your main() function. * * Your program will typically join a Fishnet, set up receive and keyboard * handlers, plus any timers, and then sit in fish_main() for the rest of * the program. Frame reception, keyboard input and timer expiry are called * from within fish_main() and return control to fish_main(). * * fish_main will automatically exit the program when the user types * "exit". */ extern void fish_main(void); /* fish_scheduleevent sets up a timer function to be called at some time in * the future. * * You write the timer function, and supply an argument value that it will * be invoked with. fish_scheduleevent returns a handle to the timer event, * which can be used to cancl it before it expires. The return value is * an integer representing the event, which will always be greater than 0. * * Note that attempting to schedule two events with the same event_handler * and argument will result in an error. * */ typedef void (*event_handler_t)(void *); typedef int event; extern event // returns a handle for the event fish_scheduleevent( int msec_delay, // how far in the future to call // the event handler (in milliseconds) void (*event_handler)(void *), // the timer function that you wrote void *event_handler_argument); // any one piece of data that you // want passed to the timer // function /* fish_cancelevent cancels a timer before it expires. Its argument is * the handle returned by fish_scheduleevent. */ extern void *fish_cancelevent(event event_handle) /* fish_setdebuglevel sets the fishnet debugging level, using the constants * defined above. The debug level can be changed anywhere in the program. */ extern void fish_setdebuglevel(const int level); /* fish_getdebuglevel gets the current fishnet debugging level. */ extern int fish_getdebuglevel(void); /* fish_debug lets you print debugging output, with a timestamp. * * The level is one of the constants defined above (or one you define), * and the format string works like the one in printf. The message will be * printed only if (level >= fish_getdebuglevel()). * * The attribute tag allows gcc to check the arguments to fish_debug. */ extern void fish_debug(int level, const char* format, ...) __attribute__ ((format (printf, 2, 3))); /* fish_debugchar lets you print a single character as debugging output. * * The level is one of the constants defined above (or one you define). * The message will be printed and the output stream flushed if * (level >= fish_getdebuglevel()). */ extern void fish_debugchar(int level, char ch); /* fish_debugframe lets you print the contents of a frame as debugging * output. The supplied message is printed before the contents of the * frame. */ extern void fish_debugframe(int level, const char* msg, const void *frame, int frame_length); /* fish_setdebugfile will cause the debugging output to be sent to a file * instead of the screen. * * Be careful when running two programs that try to write to the same * file. */ extern void fish_setdebugfile(FILE *f); /* fish_readhook and fish_remove_readhook are advanced functions for * integrating ordinary TCP sockets in a fishnet application. * * read_ready_handler is called when socket is ready to be read. Usually, * this means there is data to be read, but sometimes the socket may have * been closed by the other end, meaning that read() will return zero bytes. * * remove_readhook should be calld when the socket is closed, * otherwise you may see "bad file descriptor" errors. */ void fish_readhook(int sd, // the socket descriptor void (*read_ready_handler)(int socket)); // the callback void fish_remove_readhook(int sd); /*-------------------------------------------------------------------------- * Routing structures and constants (assignment 2) *--------------------------------------------------------------------------*/ /* The number of hops distance vector algorithm considers to be infinity * in order to discover a loop. */ #define INFINITY MAX_TTL /* Route advertisement structure. */ struct route_advertisement { int destination_address; // The address of the destination node int metric; // The cost of the path to the destination }; /* The maximum number of advertisements in a routing packet. */ #define MAX_ADVERTISEMENTS ( PACKET_DATA_SIZE / \ sizeof(strut route_advertisement)) /* The structure of a routing packet. * * Note that a (struct routing_packet) may be cast to a (struct packet). * Similarly, if the protocol is FISH_PROTOCOL_ROUTING, a (struct packet) * may be cast to a (struct routing_packet). */ struct routing_packet { // The packet header, same as for all packets struct header hdr; // The content of the packet is an array of route advertisements (not // just random bytes). struct route_advertisement adv[MAX_ADVERTISEMENTS]; }; /*-------------------------------------------------------------------------- * Transport structures and constants (assignment 3) *--------------------------------------------------------------------------*/ /* Maximum value of the port number that can be used by the transport layer */ #define MAX_PORT_NUMBER 10000 /* The number of concurrent connections that should be supported. */ #define MAX_CONNECTIONS 20 /* Time (in seconds) after which a packet should e retransmitted if no * acknowledgement has been recieved */ #define RETRANSMIT_TIMEOUT 1 /* The maximum number of retransmissions attempted by a sender. The * connection is aborted by the sender if all retransmissions fail. */ #define MAX_RETRANSMIT 3 /* Time (in seconds) after which a connection is deleted by the recieve * side, if no packets are received during that time. */ #define IDLE_TIMEOUT 10 /* The transport header structure. */ struct transport_header { int src_port; // source port int dst_port; // destination port unsigned int seq_no; // sequence number for packets containing data, // SYN, or FIN // (set to 0 if this is a pure acknowledgment) unsigned int ack_no; // acknowledgment number // (sequence number of the last in-order packet // received) unsigned int syn; // SYN flag; indicates start of connection unsigned int fin; // FIN flag;indicates end of connection }; #define TRANSPORT_HEADER_SIZE (sizeof(struct transport_header)) #define TRANSPORT_DATA_SIZE (PACKET_DATA_SIZE - TRANSPORT_HEADER_SIZE) /* The transport packet structure. * * Note that a (struct transport_packet) may be cast to a (struct packet). * Similarly, if the protocol is FISH_PROTOCOL_TRANSPORT, a (struct packet) * may be cast to a (struct transport_packet). */ struct transport_packet { struct header hdr; // The packet header struct transport_header transport_hdr; // The transport header char data[TRANSPORT_DATA_SIZE]; // The data }; #endif /* __FISH_H__ */