/** @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_ */