/* * File Name: udp.c * Author: Jade Cheng * Date: March 29, 2009 * Course: ICS 451 * Assignment: Project 2 */ #include "common.h" #include "udp.h" #include "log.h" /** The value of the socket when it is closed. */ #define UDP_CLOSED_SOCKET -1 /** To allow sockaddr without struct. */ typedef struct sockaddr sockaddr; /** To allow sockaddr_in without struct. */ typedef struct sockaddr_in sockaddr_in; /** A union of sockaddr and sockaddr_in. */ typedef union address_u { sockaddr sa; sockaddr_in sin; } address_u; static void log_buffer( const char * message, const peer_t * peer, const void * data, size_t size); /** The listening UDP socket. */ static int g_socket = UDP_CLOSED_SOCKET; /* ------------------------------------------------------------------------ */ extern int udp_fd(void) { assert(g_socket != UDP_CLOSED_SOCKET); return g_socket; } /* ------------------------------------------------------------------------ */ extern int udp_recv(void * buffer, size_t max, size_t * actual, peer_t * from) { address_u u; ssize_t r; socklen_t len; assert(buffer != NULL); assert(actual != NULL); assert(from != NULL); assert(max > 0); /* Make sure the socket is open before receiving data. */ RETURN_IF_FALSE(g_socket != UDP_CLOSED_SOCKET); /* Receive the buffer of data from the peer. */ memset(&u, 0, sizeof(u)); len = sizeof(sockaddr_in); r = recvfrom(g_socket, buffer, max, 0, &u.sa, &len); /* Check everything was successful. */ RETURN_IF_FALSE(r > 0); RETURN_IF_FALSE(u.sin.sin_family == AF_INET); RETURN_IF_FALSE(len == sizeof(sockaddr_in)); /* Store the number of bytes received. */ *actual = (size_t)r; /* Store the port and address (from network to host endian). */ from->port = ntohs(u.sin.sin_port); from->addr = u.sin.sin_addr.s_addr; log_buffer("Receiving from", from, buffer, *actual); return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ extern int udp_send(const peer_t * to, const void * buffer, size_t size) { address_u u; ssize_t r; assert(to != NULL); assert(buffer != NULL); assert(size > 0); /* Make sure the socket is open before sending. */ RETURN_IF_FALSE(g_socket != UDP_CLOSED_SOCKET); log_buffer("Sending to", to, buffer, size); /* Specify the peer's port and address (from host to network endian). */ u.sin.sin_family = AF_INET; u.sin.sin_port = htons(to->port); u.sin.sin_addr.s_addr = to->addr; /* Send the data to the peer. */ r = sendto(g_socket, buffer, size, 0, &u.sa, sizeof(sockaddr_in)); RETURN_IF_FALSE(r == (ssize_t)size); return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ extern int udp_start(u_short port) { address_u u; /* Make sure the socket is closed. */ RETURN_IF_FALSE(g_socket == UDP_CLOSED_SOCKET); /* Listen on the specified port from any IP address. */ u.sin.sin_family = AF_INET; u.sin.sin_port = htons(port); u.sin.sin_addr.s_addr = INADDR_ANY; /* Create the socket for listening. */ g_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Check for errors creating the socket. */ if (g_socket < 0) { g_socket = UDP_CLOSED_SOCKET; RETURN_FAILURE(); } /* Bind to the port and check for errors. */ if (bind(g_socket, &u.sa, sizeof(sockaddr_in)) < 0) { close(g_socket); g_socket = UDP_CLOSED_SOCKET; RETURN_FAILURE(); } return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ extern int udp_stop(void) { /* Verify the socket is open before closing. */ RETURN_IF_FALSE(g_socket != UDP_CLOSED_SOCKET); close(g_socket); g_socket = UDP_CLOSED_SOCKET; return EXIT_SUCCESS; } /* ------------------------------------------------------------------------ */ static void log_buffer( const char * message, const peer_t * peer, const void * data, size_t size) { FILE * f; if ((f = log_open()) != NULL) { fprintf(f, "%s ", message); fprint_peer(f, peer); fprintf(f, "\n"); fprint_buffer(f, data, size); fprintf(f, "\n"); log_close(f); } }