/* * File Name: messages.c * Author: Jade Cheng * Date: March 29, 2009 * Course: ICS 451 * Assignment: Project 2 */ #include "common.h" #include "messages.h" /** The control message header. */ #define CTRL_MSG_HEADER 0xcc /** The data message header code. */ #define DATA_MSG_HEADER 0xdd /** The listing message selector byte. */ #define LISTING_SELECTOR 0x4c /** The request message selector byte. */ #define REQUEST_SELECTOR 0x52 /** The try message selector byte. */ #define TRY_SELECTOR 0x54 static int read_array(msg_buf_t * src, u_char * dst, u_short len); static int read_name(msg_buf_t * src, char * dst); static int read_uchar(msg_buf_t * src, u_char * dst); static int read_ulong(msg_buf_t * src, u_long * dst); static int read_ushort(msg_buf_t * src, u_short * dst); static void write_array(msg_buf_t * dst, const u_char * towrite, size_t len); static void write_name(msg_buf_t * dst, const char * towrite); static void write_uchar(msg_buf_t * dst, u_char towrite); static void write_ulong(msg_buf_t * dst, u_long towrite); static void write_ushort(msg_buf_t * dst, u_short towrite); /* ------------------------------------------------------------------------ */ extern int data_msg_read(msg_buf_t * src, data_msg_t * dst) { u_char header; u_short count; assert(src != NULL); assert(dst != NULL); /* Start to read from index 0 and increment as the function reads. */ src->index = 0; /* Read the header of the message, which should be 0xdd. */ RETURN_IF_FAILED(read_uchar(src, &header)); RETURN_IF_FALSE(header == (u_char)DATA_MSG_HEADER); /* Read the name of the file. */ RETURN_IF_FAILED(read_name(src, dst->name)); /* Read the size of the data contents. */ RETURN_IF_FAILED(read_ushort(src, &count)); RETURN_IF_FALSE(count <= MAX_CONTENT_LENGTH); dst->size = count; /* Read the data contents. */ RETURN_IF_FAILED(read_array(src, dst->data, dst->size)); return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ extern void data_msg_write(msg_buf_t * dst, const data_msg_t * src) { int name_len; assert(dst != NULL); assert(src != NULL); assert(src->size <= MAX_CONTENT_LENGTH); /* Reset the destination message buffer. */ memset(dst, 0, sizeof(*dst)); name_len = strlen(src->name); /* Write the header. */ write_uchar(dst, (u_char)DATA_MSG_HEADER); /* Write the name of the file. */ write_name(dst, src->name); /* Write the length of the data contents in bytes. */ write_ushort(dst, src->size); /* Write the data contents. */ write_array(dst, src->data, src->size); } /* ------------------------------------------------------------------------ */ extern int listing_msg_read(msg_buf_t * src, listing_msg_t * dst) { u_char header1, header2; u_short count; int i; assert(src != NULL); assert(dst != NULL); /* Start to read from index 0 and increment as the function reads. */ src->index = 0; /* Read the first header of the message, which should be 0xcc. */ RETURN_IF_FAILED(read_uchar(src, &header1)); RETURN_IF_FALSE(header1 == (u_char)CTRL_MSG_HEADER); /* Read the second header of the message, which should be 0x4c. */ RETURN_IF_FAILED(read_uchar(src, &header2)); RETURN_IF_FALSE(header2 == (u_char)LISTING_SELECTOR); /* Read the number of items in the message. */ RETURN_IF_FAILED(read_ushort(src, &count)); RETURN_IF_FALSE(count <= MAX_LISTING_COUNT); dst->count = count; /* Read the each name contained in each item. */ for (i = 0; i < dst->count; i++) RETURN_IF_FAILED(read_name(src, dst->entries[i])); return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ extern void listing_msg_write(msg_buf_t * dst, listing_msg_t * src) { int i; assert(dst != NULL); assert(src != NULL); assert(src->count <= MAX_LISTING_COUNT); /* Reset the destination message buffer. */ memset(dst, 0, sizeof(*dst)); /* Write the first header. */ write_uchar(dst, (u_char)CTRL_MSG_HEADER); /* Write the second header. */ write_uchar(dst, (u_char)LISTING_SELECTOR); /* Write the number of items contained in this listing message. */ write_ushort(dst, src->count); /* Write all items, which are file names. */ for (i = 0; i < src->count; i++) write_name(dst, src->entries[i]); } /* ------------------------------------------------------------------------ */ extern int request_msg_read(msg_buf_t * src, request_msg_t * dst) { u_char header1, header2; assert(src != NULL); assert(dst != NULL); /* Start to read from index 0 and increment as the function reads. */ src->index = 0; RETURN_IF_FAILED(read_uchar(src, &header1)); RETURN_IF_FALSE(header1 == (u_char)CTRL_MSG_HEADER); /* Read the header of the message, which should be 0x52. */ RETURN_IF_FAILED(read_uchar(src, &header2)); RETURN_IF_FALSE(header2 == (u_char)REQUEST_SELECTOR); /* Read the name of the file contained in the message. */ RETURN_IF_FAILED(read_name(src, dst->name)); return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ extern void request_msg_write(msg_buf_t * dst, request_msg_t * src) { assert(dst != NULL); assert(src != NULL); /* Reset the destination message buffer. */ memset(dst, 0, sizeof(*dst)); /* Write the first header. */ write_uchar(dst, (u_char)CTRL_MSG_HEADER); /* Write the second header. */ write_uchar(dst, (u_char)REQUEST_SELECTOR); /* Write the name of file contained in the request message. */ write_name(dst, src->name); } /* ------------------------------------------------------------------------ */ extern int try_msg_read(msg_buf_t * src, try_msg_t * dst) { u_char header1, header2; int i; assert(src != NULL); assert(dst != NULL); /* Start to read from index 0 and increment as the function reads. */ src->index = 0; /* Read the first header of the message, which should be 0xcc. */ RETURN_IF_FAILED(read_uchar(src, &header1)); RETURN_IF_FALSE(header1 == (u_char)CTRL_MSG_HEADER); /* Read the second header of the message, which should be 0x54. */ RETURN_IF_FAILED(read_uchar(src, &header2)); RETURN_IF_FALSE(header2 == (u_char)TRY_SELECTOR); /* Read the name of the file contained in the message. */ RETURN_IF_FAILED(read_name(src, dst->name)); /* Read the number of peer item contained in the message. */ RETURN_IF_FAILED(read_ushort(src, &dst->count)); RETURN_IF_FALSE(dst->count <= MAX_TRY_COUNT); /* Read each peer contained in each item. */ for (i = 0; i < dst->count; i++) { RETURN_IF_FAILED(read_ulong(src, &dst->peers[i].addr)); RETURN_IF_FAILED(read_ushort(src, &dst->peers[i].port)); } return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ extern void try_msg_write(msg_buf_t * dst, try_msg_t * src) { int i; assert(dst != NULL); assert(src != NULL); assert(src->count <= MAX_TRY_COUNT); /* Reset the destination message buffer. */ memset(dst, 0, sizeof(*dst)); /* Write the first header. */ write_uchar(dst, (u_char)CTRL_MSG_HEADER); /* Write the second header. */ write_uchar(dst, (u_char)TRY_SELECTOR); /* Write the name of the file contained in the try message. */ write_name(dst, src->name); /* Write the number of peers contained in the try message. */ write_ushort(dst, src->count); /* Write each peer. */ for (i = 0; i < src->count; i++) { write_ulong(dst, src->peers[i].addr); write_ushort(dst, src->peers[i].port); } } /* ------------------------------------------------------------------------ */ extern msg_type get_msg_type(msg_buf_t * src) { assert (src != NULL); if (src->size < 2) return msg_type_unknown; /* Check for data messages. */ if (src->buffer[0] == (u_char)DATA_MSG_HEADER) return msg_type_data; /* Check for control messages. */ if (src->buffer[0] == (u_char)CTRL_MSG_HEADER) { if (src->buffer[1] == (u_char)LISTING_SELECTOR) return msg_type_listing; if (src->buffer[1] == (u_char)REQUEST_SELECTOR) return msg_type_request; if (src->buffer[1] == (u_char)TRY_SELECTOR) return msg_type_try; } return msg_type_unknown; } /* ------------------------------------------------------------------------ */ /** * Reads an array of u_char from a message buffer. * * @param src The message buffer. * @param dst An array of uchar memory. * @param len The length in bytes to read. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ static int read_array(msg_buf_t * src, u_char * dst, u_short len) { u_char a; size_t i; int j; assert(src != NULL); assert(dst != NULL); i = 0; for (j = 0; j < len; j++) { RETURN_IF_FAILED(read_uchar(src, &a)); dst[i++] = a; } return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ /** * Reads a file name from a message buffer. * * @param src The message buffer. * @param dst The file name. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ static int read_name(msg_buf_t * src, char * dst) { u_char a; size_t i; assert(src != NULL); assert(dst != NULL); /* File names are treated as strings, so use '\0' to indicate the end. */ i = 0; do { RETURN_IF_FALSE(i != MAX_NAME_LENGTH); RETURN_IF_FAILED(read_uchar(src, &a)); dst[i++] = a; } while(a != '\0'); RETURN_IF_FAILED(verify_name(dst)); return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ /** * Reads a u_char from a message buffer. * * @param src The message buffer. * @param dst The u_char. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ static int read_uchar(msg_buf_t * src, u_char * dst) { assert(src != NULL); assert(dst != NULL); /* Make sure the reading is not beyond the buffer size. */ RETURN_IF_FALSE(src->index < src->size); /* Read a byte at the next index, and increment the index. */ *dst = src->buffer[(src->index)++]; return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ /** * Reads peer infomation from a message buffer. * * @param src The message buffer. * @param dst The peer infomation. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ static int read_ulong(msg_buf_t * src, u_long * dst) { u_char a, b, c, d; assert(src != NULL); assert(dst != NULL); /* Read four bytes out of the message buffer. */ RETURN_IF_FAILED(read_uchar(src, &a)); RETURN_IF_FAILED(read_uchar(src, &b)); RETURN_IF_FAILED(read_uchar(src, &c)); RETURN_IF_FAILED(read_uchar(src, &d)); /* Read the unsigned long in MSB and store it in host order. */ *dst = 0; *dst |= a << 24; *dst |= b << 16; *dst |= c << 8; *dst |= d; return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ /** * Reads u_shor number from a message buffer in the form of msg_buf_t. * * @param src The message buffer in the form of msg_buf_t. * @param dst A u_shor number memory space to read to. * * @return EXIT_SUCCESS or EXIT_FAILURE. */ static int read_ushort(msg_buf_t * src, u_short * dst) { u_char a, b; assert(src != NULL); assert(dst != NULL); /* Read two bytes out of the message buffer. */ RETURN_IF_FAILED(read_uchar(src, &a)); RETURN_IF_FAILED(read_uchar(src, &b)); /* Read teh unsigned short in MSB and store it in host order. */ *dst = 0; *dst |= a << 8; *dst |= b; return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ /** * Write an array of u_char into a message buffer. * * @param dst The message buffer. * @param src The array of uchar. * @param len The length in bytes to write. */ static void write_array(msg_buf_t * dst, const u_char * src, size_t len) { int i; assert(dst != NULL); assert(src != NULL); for (i = 0; i < len; i++) write_uchar(dst, src[i]); } /* ------------------------------------------------------------------------ */ /** * Write a name into a message buffer. * * @param dst The message buffer. * @param src The name. */ static void write_name(msg_buf_t * dst, const char * src) { int i; int len; assert(dst != NULL); assert(src != NULL); assert(verify_name(src) == EXIT_SUCCESS); len = strlen(src); for (i = 0; i <= len; i++) write_uchar(dst, src[i]); } /* ------------------------------------------------------------------------ */ /** * Write a u_char into a message buffer. * * @param dst The message buffer. * @param src The u_char. */ static void write_uchar(msg_buf_t * dst, u_char src) { assert(dst != NULL); assert(dst->size < MESSAGE_BUFFER_SIZE); dst->buffer[dst->size++] = src; } /* ------------------------------------------------------------------------ */ /** * Write peer infomation into a message buffer. * * @param dst The message buffer. * @param src The peer information. */ static void write_ulong(msg_buf_t * dst, u_long src) { assert(dst != NULL); /* Convert the host order to MSB. */ write_uchar(dst, (u_char)(src >> 24)); write_uchar(dst, (u_char)((src >> 16) & 0xff)); write_uchar(dst, (u_char)((src >> 8) & 0xff)); write_uchar(dst, (u_char)(src & 0xff)); } /* ------------------------------------------------------------------------ */ /** * Write a u_short number into a message buffer. * * @param dst The message buffer. * @param src The u_short number. */ static void write_ushort(msg_buf_t * dst, u_short src) { assert(dst != NULL); /* Convert the host order to MSB. */ write_uchar(dst, (u_char)(src >> 8)); write_uchar(dst, (u_char)(src & 0xff)); } /* ------------------------------------------------------------------------ */ #ifdef TESTS static int tests() { msg_buf buf; data_msg msg1; data_msg msg2; listing_msg msg3; listing_msg msg4; request_msg msg5; request_msg msg6; try_msg msg7; try_msg msg8; msg_type type; u_char data[5] = {'a', 'b', 'c', 'd', 'e'}; int i; strncpy(msg1.name, "jade", 5); for (i = 0; i < 5; i++) msg1.data[i] = data[i]; msg1.data_len = 5; data_msg_write(&buf, &msg1); print_buffer(buf.msg_buf, buf.buf_count); type = get_msg_type(&buf); if (type == data_type_msg) { data_msg_read(&buf, &msg2); print_buffer((u_char *)msg2.name, strlen(msg2.name)); print_buffer(msg2.data, msg2.data_len); } strncpy(msg3.entries[0], "abcde", 6); strncpy(msg3.entries[1], "fghijk", 7); strncpy(msg3.entries[2], "lmno", 5); strncpy(msg3.entries[3], "pqr", 4); msg3.count = 4; listing_msg_write(&buf, &msg3); print_buffer(buf.msg_buf, buf.buf_count); type = get_msg_type(&buf); if (type == listing_type_msg) { listing_msg_read(&buf, &msg4); for(i = 0; i < msg4.count; i++) print_buffer((u_char *)msg4.entries[i], strlen(msg4.entries[i])); } strncpy(msg5.name, "monkey", 7); request_msg_write(&buf, &msg5); print_buffer(buf.msg_buf, buf.buf_count); type = get_msg_type(&buf); if(type == request_type_msg) { request_msg_read(&buf, &msg6); print_buffer((u_char *)msg6.name, strlen(msg6.name)); } strncpy(msg7.name, "egg", 4); msg7.peers[0].addr = 0x01020304; msg7.peers[1].addr = 286331153; msg7.peers[2].addr = 286331154; msg7.peers[3].addr = 286331155; msg7.peers[0].port = 0x0102; msg7.peers[1].port = 11; msg7.peers[2].port = 12; msg7.peers[3].port = 13; msg7.count = 4; try_msg_write(&buf, &msg7); print_buffer(buf.msg_buf, buf.buf_count); type = get_msg_type(&buf); if(type == try_type_msg) { try_msg_read(&buf, &msg8); print_buffer((u_char *)msg8.name, strlen(msg8.name)); } return EXIT_SUCCESS; } #endif /* TESTS */