#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "udp.h" typedef void *(*thread_t)(void*); typedef void *thread_param_t; typedef struct tag_listen_info { int port; void (*receiving_function)(udp_packet_t); } listen_info_t; int udp_get_broadcast_address(const char *network_interface, char *broadcast_address, int address_buffer_length) { int sockfd = -1; struct ifreq ifr; // Start referanse-socket if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("get_broadcast_addr (socket)"); return ERR_CANT_CREATE_SOCKET; } strncpy (ifr.ifr_name, network_interface, sizeof(ifr.ifr_name)); // Hent broadcast adresse fra ioctl() if (ioctl(sockfd, SIOCGIFBRDADDR, &ifr) != 0) { perror("get_broadcast_addr (ioctl)"); return ERR_CANT_GET_BROADCAST_ADDR; } if ( ifr.ifr_broadaddr.sa_family != AF_INET ) { fputs("Not IPV4 network interface", stderr); return ERR_INVALID_DEVICE; } strncpy( broadcast_address, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr), address_buffer_length); broadcast_address[address_buffer_length-1] = '\0'; close(sockfd); return 0; } void udp_abort_listen(int thread) { pthread_cancel( thread ); } static void *udp_listen_thread(listen_info_t *listen_info_ptr) { int sockfd, n; struct sockaddr_in serv_addr; udp_packet_t packet; listen_info_t li = *listen_info_ptr; if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("listen (socket)"); pthread_exit(NULL); } { int dummy=1; setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &dummy, sizeof(dummy)); setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy)); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(li.port); if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("listen (bind)"); close(sockfd); pthread_exit(NULL); } while (1) { n = recvfrom(sockfd, &packet, sizeof(packet), 0, 0, 0); if (n < 0) fprintf(stderr, "ERROR reading from socket\n"); li.receiving_function(packet); } pthread_exit(NULL); } int udp_listen(int port, void (*receiving_function)(udp_packet_t)) { static listen_info_t li; pthread_t new_thread; li.port = port; li.receiving_function = receiving_function; if (pthread_create(&new_thread, NULL, (thread_t)&udp_listen_thread, (thread_param_t)&li) != 0) { perror ("listen (pthread_create)"); return ERR_CANT_CREATE_THREAD; } else { return new_thread; } } int udp_send_packet(const char addr[256], int port, udp_packet_t packet) { int sockfd; struct sockaddr_in serv_addr; struct hostent *server; server = gethostbyname(addr); if (server == NULL) { perror("send (gethostbyname)"); return ERR_INVALID_HOST; } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length); serv_addr.sin_port = htons(port); if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("send (socket)"); return ERR_CANT_CREATE_SOCKET; } { int dummy=1; setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &dummy, sizeof(dummy)); setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy)); } if (connect(sockfd, (void*)(&serv_addr), sizeof(serv_addr)) < 0) { perror("send (connect)"); close(sockfd); return ERR_CANT_CONNECT; } if (write(sockfd, &packet, sizeof(packet)) != sizeof(packet)) { perror("send (write)"); close(sockfd); return ERR_CANT_WRITE; } close(sockfd); return 0; }