protocol.h

/** @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_ */
Valid HTML 4.01 Valid CSS