heis/UDP/udp.c

192 lines
3.8 KiB
C
Executable File

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#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;
}