/* * 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 /* The 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_PACKET 1 #define FISH_PROTOCOL_ECHO 2 #define FISH_PROTOCOL_NEIGHBOR 3 #define FISH_PROTOCOL_NAMING 4 #define FISH_PROTOCOL_ROUTING_LS 5 #define FISH_PROTOCOL_TRANSPORT 6 #define FISH_PROTOCOL_ROUTING_DV 7 #define FISH_PROTOCOL_MAX 8 // upper bound, not a real protocol /* a mapping from protocol number to name */ static const char* protocolstr[] __attribute__((unused)) = { "error", "packet", "echo", "neighbor", "naming", "routing_ls", "transport", "routing_dv" }; /* 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. The two arguments are: *from* which * tells the address of the immediate neighbor that sent the frame, and *frame* * which contains the packet data. Note that 'struct packet *' will need to be * cast to a 'struct transport_packet *' to interpret the contents. Your receive * handler doesn't return any value. */ struct packet; typedef void (*receive_handler)(int from, struct packet *frame); /* 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 address 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 ttl; // A hop limit (compare to the IP TTL; Peterson 4.1) that is // set to at most MAX_TTL when a packet is created and decremented // every time that a packet is forward by a node. The packet is // discarded if the ttl reaches zero. int cksum; // A checksum that is used to detect data that has been corrupted // in the network, or zero if there is no checksum present. The // checksum covers the entire packet with the TTL and checksum // fields set to zero. This field is calculated when the packet // is first sent using the TCP/UDP checksum algorithm (see // Peterson 2.4.2), and checked when the packet reaches its // final destination. int pktid; // A value that is incremented for every new packet that is // created by a node. It is used to implement functions such // as flooding and fragmentation. (Compare to the IP IPID; // Peterson 4.1) int src; // The address of source node which originally created this packet. int dst; // The destination address of this packet. This is either a // particular node or a special constant, such as the broadcast // address which means "all neighbors." int protocol; // The protocol type, one of the constants defined above, which // determines the format of the data carried in the payload of // the packet. int length; // The length, in bytes, of this frame, including this header. // This value shall never be less than PACKET_HEADER_SIZE, and // never more than MTU. }; #define PACKET_HEADER_SIZE (sizeof(struct header)) #define PACKET_DATA_SIZE (MTU - PACKET_HEADER_SIZE) /* * All packets consist of a packet header (as specified above) and a data * section. More advanced protocols can be developed by structuring the * data section. Packets containg more refined protocols can always be * cast to this basic packet struct. */ struct packet { struct header pkt_hdr; // The packet header as described above. char data[PACKET_DATA_SIZE]; // The payload of the packet. This can // be structured to implement more advanced // protocols. }; /*-------------------------------------------------------------------------- * fishnet API calls *--------------------------------------------------------------------------*/ /* * NOTE: * Any fishnet API call may abort and dump core on failure (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. If the * fishhead_location is not "", then a fishhead node is contacted for * obtaining the network topology. If the fishhead_location is "", * then the network topology is dictated by the physical environment * (this is typically used for wireless). * * You supply your requested node address to this call. * * 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" 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_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 calling 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 input 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(int dest, // immediate neighbor to send to void* frame); // pointer to the frame /* 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 cancel 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); /* 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 called 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); /*-------------------------------------------------------------------------- * Echo packet structures and constants (assignment 1) *--------------------------------------------------------------------------*/ /* The echo protocol is used to bounce a data string off a node to * determine if the node is "up." The protocol works by first * transmitting a data string from node A to node B, and then node B * returns the string to node A. * * This protocol is essentially the ping Internet utility (see 'man ping'). */ /* There are two different types of packets defined in the echo * protocol: request and reply. * * A packet from node A "requests" that node B return the packet's * data string to node A. Node B "responds" by creating a new packet * containing the data string and returning it to node A. */ #define ECHO_PROTOCOL_REQUEST 0 #define ECHO_PROTOCOL_RESPONSE 1 /* Echo packet header. */ struct echo_header { int code; // The echo protocol type, indicating whether this is a // request or a response packet. }; /* The maximum number of characters of data that can be sent in an echo packet. */ #define MAX_ECHO_DATA \ ( (PACKET_DATA_SIZE) - sizeof(struct echo_header) ) /* The structure of an echo packet. * * Note that a (struct echo_packet) may be cast to a (struct packet). * Similarly, if the protocol is FISH_PROTOCOL_ECHO, a (struct packet) * may be cast to a (struct echo_packet). */ struct echo_packet { struct header pkt_hdr; // The packet header, same as for all packets struct echo_header echo_hdr; // The echo packet header, indicating type of // echo packet. char data[MAX_ECHO_DATA]; // The data that is "bounced" between two nodes. // Upon processing a request packet, a node must // copy this payload into the response packet. }; /*-------------------------------------------------------------------------- * Routing structures and constants (assignment 2) *--------------------------------------------------------------------------*/ #define MAX_NAME_ENTRIES \ ( (MTU - PACKET_HEADER_SIZE - sizeof(struct name_packet_header)) \ /sizeof(struct name_entry) ) #define MAX_LSA_ENTRIES \ ( (MTU - PACKET_HEADER_SIZE - sizeof(struct link_state_packet_header)) \ /sizeof(struct link_state_announcement) ) #define LS_INFINITY 9999 #define NEIGHBOR_DISCOVERY_REQUEST 0 #define NEIGHBOR_DISCOVERY_RESPONSE 1 /* A nodes advertises its name with this struct.*/ struct name_entry { int address; // fishnet node address char name[12]; // hostname as string, null terminated int seq_no; // per address sequence number for announcement int valid_ms; // interval information should be kept for (in milliseconds) }; /* This header stores the number of name_entry's in a name_packet */ struct name_packet_header { int num_entries; }; /* This packet is used to disseminate the names of nodes */ struct name_packet { struct header pkt_hdr; // Same header as for all packets struct name_packet_header name_pkt_hdr; // Stores the number of name_entries struct name_entry name_entries[MAX_NAME_ENTRIES]; // Name entries in this packet }; /* This header is used for neighbor discovery. To ask a neighbor whether it is alive, * set type to NEIGHBOR_DISCOVERY_REQUEST; to respond to a request, set it to * NEIGHBOR_DISCOVERY_RESPONSE */ struct neighbor_packet_header { int type; // NEIGHBOR_DISCOVERY_REQUEST or NEIGHBOR_DISCOVERY_RESPONSE }; /* This packet is used for neighbor discovery */ struct neighbor_packet { struct header pkt_hdr; // Same header as for all packets struct neighbor_packet_header neigh_pkt_hdr; // A neighbor discovery req or response }; /* A nodes uses this struct to convey link information. */ struct link_state_announcement { int from_address; // head of link; a fishnet node address int to_address; // tail end of link int cost; // 1 if link is up, LS_INFINITY if link is down int seq_no; // per link sequence number for announcement int valid_ms; // interval information should be kept for (in milliseconds) }; /* This header stores the number of link_state_announcements in a link_state_packet */ struct link_state_packet_header { int num_entries; }; /* This packet is used to disseminate link-state information */ struct link_state_packet { struct header pkt_hdr; // Same header as for all packets struct link_state_packet_header lk_state_pkt_hdr; // Stores the num of announcements struct link_state_announcement lk_state_announcements[MAX_LSA_ENTRIES]; }; /*-------------------------------------------------------------------------- * Distance Vector Routing structures and constants (you will not need # both link state and distance vector routing) *--------------------------------------------------------------------------*/ /* A routing protocol is used to construct a forwarding table that can be * used to send packets between source and destination addresses. * * Nodes annouce the destinations that they can reach, as well as the * cost of it transmitting a packet to those destinations. */ /* * The number of hops distance vector algorithm considers to be infinity * in order to discover a loop. */ #define DV_INFINITY MAX_TTL /* Route advertisement header. */ struct routing_header { int num_routes; // The number of routes that are advertised in this packet. }; /* * Route advertisement structure. For each destination that can be reached * from the generating node, a route_advertisement is included in the * routing packet. */ struct route_advertisement { int destination_address; // Indicates a destination that can be reached from // the advertising node. This must be a particular // node; it cannot be a special constant, such as // all neighbors. int metric; // The cost of a packet traversing this route to // the destination. }; /* The maximum number of advertisements in a routing packet. */ #define MAX_ADVERTISEMENTS \ ( ((PACKET_DATA_SIZE) - sizeof(struct routing_header)) / \ sizeof(struct 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 { struct header pkt_hdr; // The packet header, same as for all packets. struct routing_header route_hdr; // The routing packet header, indicating // the number of advertisements contained // within this packet. // The content of the packet is an array of route advertisements. // This array indicates the destinations reachable from // this node, and the cost of using these routes. struct route_advertisement adv[MAX_ADVERTISEMENTS]; }; /*-------------------------------------------------------------------------- * Transport structures and constants *--------------------------------------------------------------------------*/ /* The transport protocol provides reliable data transmission across the * network (similar to TCP). The transport protocol is connection oriented, * using sequence numbers, acknowledgements, and retransmissions to ensure * that data is reliably delivered. */ /* 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 milliseconds) after which a packet should be * retransmitted if no acknowledgement has been recieved */ #define RETRANSMIT_TIMEOUT_MS 1000 /* The maximum number of retransmissions attempted by a sender. The * connection is aborted by the sender if all retransmissions fail. */ #define MAX_RETRANSMIT 5 /* Time (in milliseconds) after which a connection is deleted by the recieve * side, if no packets are received during that time. */ #define IDLE_TIMEOUT_MS 10000 /* * The transport header structure. This structure contains all of the information * necessary to establish a connection, demultiplex packets to the correct * connection, and provide reliable data transmission. */ struct transport_header { /* The port of the source node which originally created this packet. Ports are used to specify which process sent or should receive the packet. */ int src_port; /* The port at the destination node, represents the application at the other end. */ int dst_port; /* The sequence number is attached to any packet containing data, SYN, or FIN. If the packet is a pure acknowledgement, meaning no data is contained in the packet, it may be set to zero. The initial sequence number associated with a connection is random; all subsequent sequence numbers are incremented. (See Peterson 2.5.2). Sequence numbers apply to bytes. */ unsigned int seq_no; /* The ack number indicates the sequence number of the next byte expected. Should always be set, even in data packets. */ unsigned int ack_no; /* The SYN flag is used to indicate the start of this half(-duplex) connection */ unsigned int syn; /* The FIN flag is used to indicate the end for this half of the connection */ unsigned int fin; /* The RST flag is set to abort a connection; it is sent in response to a syn to a port with no listening application, and sent in response to a packet in the wrong state. (eg a data packet received in the closed state) */ unsigned int rst; /* The advertised window represents the amount of buffer space left for receiving additional data. A stop-and-wait receiver MUST set this to no more than TRANSPORT_PAYLOAD_SIZE. A sliding window receiver SHOULD set this to the amount of space that can be used for buffering out-of-order data. A sender MUST NOT send more data */ unsigned int advertised_window; }; #define TRANSPORT_HEADER_SIZE (sizeof(struct transport_header)) #define TRANSPORT_PAYLOAD_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 pkt_hdr; struct transport_header transport_hdr; char payload[TRANSPORT_PAYLOAD_SIZE]; }; #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (!FALSE) #endif #endif /* __FISH_H__ */