/** @file protocol.h * @date April 24, 2009 * * The shared protocol definition for the "reliable" UDP sender and receiver. * * Under normal circumstances, the sender initiates the transmission by sending * an INIT message to the receiver. The receive acknowledges by sending a * START message, which contains a sequence id used for the remaining messages. * The sender then sends all DATA packets, and after the last packet arrives, * the receiver sends a DONE message to the sender, and the file transfer * completes. * * * ~ Sender ~ ~ Receiver ~ * | | * [INIT] -----------------> | * | | * | <----------------- [START] * | | * [DATA 1] ----------------> | * [DATA 2] ----------------> | * [DATA 3] ----------------> | * : : * [DATA N] ----------------> | * | | * | <------------------ [DONE] * | | * * If the receiver is unable to receive files or the file already exists at the * receiver, the receiver may respond to the INIT message with an ABORT * message. This indicates the sender should not send any further packets, and * the transfer should be aborted. * * ~ Sender ~ ~ Receiver ~ * | | * [INIT] -----------------> | * | | * | <----------------- [ABORT] * | | * * If packets are dropped during the transmission, the receiver may send RETRY * messages, which includes a range of packets to resend. The sender should * resend any packet the receiver requests before receiving the DONE message. * * ~ Sender ~ ~ Receiver ~ * | | * [INIT] -----------------> | * | | * | <----------------- [START] * | | * [DATA 1] ----------------> | * [DATA 2] -------> X | * [DATA 3] -------> X | * [DATA 4] ----------------> | * | | * | <----------------- [RETRY] * | | * [DATA 2] ----------------> | * [DATA 3] ----------------> | * [DATA 5] ----------------> | * : : * [DATA N] ----------------> | * | | * | <------------------ [DONE] * | | * * A timeout can occur at any time. It is left to the sender and receiver to * determine these values according to the characteristics of their networks. * Regardless, the receiver will respond to a DATA message with an ABORT * message if it has aborted the transfer due to a timeout. The sender should * implement its own timeout if it never receives the START/ABORT or DONE * messages. * * Similarly, the data packet sizes are configured by the sender in the INIT * messages. This allows the sender to optimize the transmission according to * the characteristics of the network. * * All numeric values are sent with the most significant byte first. */ #ifndef PROTOCOL_H_ #define PROTOCOL_H_ /** The maximum length of a file name supported by the protocol. */ #define NAME_MAX_LENGTH 20 /** The size of a buffer that can hold the longest supported file name. */ #define NAME_SIZE (1 + NAME_MAX_LENGTH) /** * The maximum length of a description for a reason why a transfer was * aborted. */ #define REASON_MAX_LENGTH 255 /** * The size of a buffer that can hold the longest supported reason why a * transfer was aborted. */ #define REASON_SIZE (1 + REASON_MAX_LENGTH) /** The smallest supported data packet buffer size. */ #define DATA_MIN_SIZE 1 /** The largest supported data packet buffer size. */ #define DATA_MAX_SIZE 5000 /** The length of the DATA message header. */ #define DATA_HEADER_SIZE 9 /** The maximum length of a packet passed using this protocol. */ #define PACKET_MAX_SIZE (DATA_MAX_SIZE + DATA_HEADER_SIZE) /* -------------------------- SENDER MESSAGE TYPES -------------------------- */ /** Sent by the sender to indicate it wishes to transfer a file. */ #define MSG_TYPE_INIT 0x11 /** Sent by the sender to transfer one packet of data. */ #define MSG_TYPE_DATA 0x12 /* ------------------------- RECEIVER MESSAGE TYPES ------------------------- */ /** Sent by the receiver to indicate the sender may transfer a file. */ #define MSG_TYPE_START 0x21 /** Sent by the receiver to indicate the sender should abort transfer. */ #define MSG_TYPE_ABORT 0x22 /** Sent by the receiver to indicate the sender should resend packets. */ #define MSG_TYPE_RETRY 0x23 /** Sent by the receiver to indicate the file transfer completed. */ #define MSG_TYPE_DONE 0x24 /* ---------------------------- READ/WRITE BUFFER --------------------------- */ /** A structure that contains information about datagram data. */ typedef struct msg_buffer_t { /** The data of the datagram. */ u_char data[PACKET_MAX_SIZE]; /** The length of the data in the datagram. */ size_t size; } msg_buffer_t; /* ----------------------------- ABORT MESSAGE ------------------------------ */ /** * The abort message contents. * * [0x00] type (MSG_TYPE_ABORT) * [0x01] id (MSB) * [0x02] : * [0x03] : * [0x04] : (LSB) * [0x05] reason (N bytes, where 0 < N <= REASON_MAX_SIZE) * : : * [0x05 + N] : (0x00) */ typedef struct msg_abort_t { /** The type of the message. This is always MSG_TYPE_ABORT. */ u_char type; /** * The sequence id. This is a value returned by the receiver in the * start message, if available; otherwise zero. */ u_long id; /** * The reason the transfer was aborted. Only the valid data is sent, * and this includes the first NULL terminator. */ char reason[REASON_SIZE]; } msg_abort_t; /* ------------------------------ DATA MESSAGE ------------------------------ */ /** * The data message contents. * * [0x00] type (MSG_TYPE_DATA) * [0x01] id (MSB) * [0x02] : * [0x03] : * [0x04] : (LSB) * [0x05] packet (MSB) * [0x06] : * [0x07] : * [0x08] : (LSB) * [0x09] data (N bytes, where DATA_MIN_SIZE < N <= DATA_MAX_SIZE) * : : * [0x09 + N] : */ typedef struct msg_data_t { /** The type of the message. This is always MSG_TYPE_DATA. */ u_char type; /** * The sequence id. This is a value returned by the receiver in the * start message. */ u_long id; /** The packet number. */ u_long packet; /** * The packet data. Only the valid data is sent. The number of bytes * sent is usually equal to the data_size in the init message. The size * of the last packet is truncated. */ u_char data[DATA_MAX_SIZE]; } msg_data_t; /* ------------------------------ DONE MESSAGE ------------------------------ */ /** * The done message contents. * * [0x00] type (MSG_TYPE_DONE) * [0x01] id (MSB) * [0x02] : * [0x03] : * [0x04] : (LSB) */ typedef struct msg_done_t { /** The type of the message. This is always MSG_TYPE_DONE. */ u_char type; /** * The sequence id. This is a value returned by the receiver in the * start message. */ u_long id; } msg_done_t; /* ------------------------------ INIT MESSAGE ------------------------------ */ /** * The initialization message contents. * * [0x00] type (MSG_TYPE_INIT) * [0x01] checksum (MSB) * [0x02] : * [0x03] : * [0x04] : (LSB) * [0x05] filesize (MSB) * [0x06] : * [0x07] : * [0x08] : (LSB) * [0x09] datasize (MSB) * [0x0a] : (LSB) * [0x0b] name (N bytes, where 2 <= N <= NAME_MAX_SIZE) * : : * [0x0b + N] : (0x00) */ typedef struct msg_init_t { /** The type of the message. This is always MSG_TYPE_INIT. */ u_char type; /** * The checksum for the file. This is calculated using a 32-bit CRC * algorithm compatible with WinZip (polynomial = 0×04c11db7). */ u_long checksum; /** The size of the file, which must be greater than zero. */ u_long filesize; /** * The size of each packet, which must be between DATA_MIN_SIZE and * DATA_MAX_SIZE. */ u_short datasize; /** * The name of the file the sender will send. Only the valid data is * sent, and this includes the first NULL terminator. */ char name[NAME_SIZE]; } msg_init_t; /* ----------------------------- RETRY MESSAGE ------------------------------ */ /** * The retry message contents. * * [0x00] type (MSG_TYPE_RETRY) * [0x01] id (MSB) * [0x02] : * [0x03] : * [0x04] : (LSB) * [0x05] first (MSB) * [0x06] : * [0x07] : * [0x08] : (LSB) * [0x09] last (MSB) * [0x0a] : * [0x0b] : * [0x0c] : (LSB) */ typedef struct msg_retry_t { /** The type of the message. This is always MSG_TYPE_RETRY. */ u_char type; /** * The sequence id. This is a value returned by the receiver in the * start message. */ u_long id; /** The first packet in a range to resend (inclusive). */ u_long first; /** The last packet in a range to resend (inclusive). */ u_long last; } msg_retry_t; /* ----------------------------- START MESSAGE ------------------------------ */ /** * The start message contents. * * [0x00] type (MSG_TYPE_START) * [0x01] id (MSB) * [0x02] : * [0x03] : * [0x04] : (LSB) */ typedef struct msg_start_t { /** The type of the message. This is always MSG_TYPE_START. */ u_char type; /** The sequence id, which is incremented each transfer instance. */ u_long id; } msg_start_t; /* -------------------------- READ/WRITE FUNCTIONS -------------------------- */ /** Reads a ABORT message. * * @param msg The destination. * @param buffer The source. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ extern int msg_abort_read(msg_abort_t * msg, const msg_buffer_t * buffer); /** Writes an ABORT message to a buffer. * * @param buffer The destination. * @param msg The source. */ extern void msg_abort_write(msg_buffer_t * buffer, const msg_abort_t * msg); /** Reads a DATA message. * * @param msg The destination. * @param buffer The source. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ extern int msg_data_read(msg_data_t * msg, const msg_buffer_t * buffer); /** Writes an DATA message to a buffer. * * @param buffer The destination. * @param msg The source. */ extern void msg_data_write( msg_buffer_t * buffer, const msg_data_t * msg, u_short datasize); /** Reads a DONE message. * * @param msg The destination. * @param buffer The source. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ extern int msg_done_read(msg_done_t * msg, const msg_buffer_t * buffer); /** Writes a DONE message to a buffer. * * @param buffer The destination. * @param msg The source. */ extern void msg_done_write(msg_buffer_t * buffer, const msg_done_t * msg); /** Reads an INIT message. * * @param msg The destination. * @param buffer The source. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ extern int msg_init_read(msg_init_t * msg, const msg_buffer_t * buffer); /** Writes an INIT message to a buffer. * * @param buffer The destination. * @param msg The source. */ extern void msg_init_write(msg_buffer_t * buffer, const msg_init_t * msg); /** Reads a RETRY message. * * @param msg The destination. * @param buffer The source. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ extern int msg_retry_read(msg_retry_t * msg, const msg_buffer_t * buffer); /** Writes a RETRY message to a buffer. * * @param buffer The destination. * @param msg The source. */ extern void msg_retry_write(msg_buffer_t * buffer, const msg_retry_t * msg); /** Reads a START message. * * @param msg The destination. * @param buffer The source. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ extern int msg_start_read(msg_start_t * msg, const msg_buffer_t * buffer); /** Writes a START message to a buffer. * * @param buffer The destination. * @param msg The source. */ extern void msg_start_write(msg_buffer_t * buffer, const msg_start_t * msg); /** Returns the size of the data for a specified packet. * * @param msg The INIT message. * @param packet The packet number. * * @return The size of the data for a specified packet. */ extern u_short protocol_data_size(const msg_init_t * msg, u_long packet); /** Verifies a name is valid. * * @param name The name. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ extern int protocol_name_verify(const char * name); /** Returns the number of packets required to transfer the file. * * @param msg The INIT message. * * @return The number of packets required to transfer the file. */ extern u_long protocol_packet_count(const msg_init_t * msg); /** Returns the file offset for a specified packet. * * @param msg The INIT message. * @param packet The packet number. * * @return The offset in the file (useful for fseek). */ extern long protocol_packet_offset(const msg_init_t * msg, u_long packet); #endif /* PROTOCOL_H_ */