192 lines
3.8 KiB
C
Executable File
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;
|
|
}
|
|
|
|
|
|
|