A Programme répéteur UDP
/** Small utility to listen for UDP packets on an UDP port **/
/** and repeat them on another UDP port **/
/** Include files **/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
/** Constants definitions **/
#define ACTIVITY_DELAY 60
#define MAX_BUFFER 2048
#define PORT_LISTEN 520
#define PORT_REPEAT 5200
/** General types definitions **/
/** Functions **/
/* Create a socket on a given UDP port */
int create_socket(short int port,unsigned char use_bdcst){
struct sockaddr_in address;
int status,broadcast=1;
int sd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(sd<0){
perror("create_socket.socket");
exit(-1);
}
address.sin_family=AF_INET;
address.sin_port=htons(port);
address.sin_addr.s_addr=INADDR_ANY;
if(use_bdcst){
status=setsockopt(sd,SOL_SOCKET,SO_BROADCAST,&broadcast,sizeof broadcast);
if(status<0) return -1;
}
status=bind(sd,(struct sockaddr *)&address,sizeof address);
if(status<0){perror("create_socket.bind"); exit(-1);}
return sd;
}
/* Wait for activity on a given sockets */
int wait_activity(int *sds,int *ready,int nb){
fd_set read;
struct timeval tv;
int status,i,max=0;
int activity=-1;
FD_ZERO(&read);
for(i=0;i<nb;i++){
FD_SET(sds[i],&read);
if(sds[i]>max) max=sds[i];
}
tv.tv_sec=ACTIVITY_DELAY; tv.tv_usec=0;
status=select(max+1,&read,NULL,NULL,&tv);
if(status<0){
perror("wait_activity.select");
exit(-1);
}
for(i=0;i<nb;i++)
if(!FD_ISSET(sds[i],&read)) ready[i]=0;
else { activity=1; ready[i]=1; }
return activity;
}
/* Read a packet on one socket and send it on the other */
void repeat_packet(int sd_recv,int sd_send,int port_send){
struct sockaddr_in address_sender;
struct sockaddr_in address_local;
unsigned char buffer[MAX_BUFFER];
int status,packet_size,sent_size;
unsigned int size;
size=sizeof address_local;
status=getsockname(sd_recv,(struct sockaddr *)&address_local,&size);
if(status<0){ perror("repeat_packet.getsockname"); exit(-1); }
packet_size=recvfrom(sd_recv,buffer,MAX_BUFFER,0,
(struct sockaddr *)&address_sender,&size);
if(address_local.sin_port!=address_sender.sin_port) return;
size=sizeof address_local;
status=getsockname(sd_send,(struct sockaddr *)&address_local,&size);
if(status<0){ perror("repeat_packet.getsockname"); exit(-1); }
address_local.sin_port=htons(port_send);
address_local.sin_addr.s_addr=INADDR_BROADCAST;
size=sizeof address_local;
sent_size=sendto(sd_send,buffer,packet_size,0,
(struct sockaddr *)&address_local,size);
if(sent_size!=packet_size){
fprintf(stderr,"Cannot repeat UDP packet.\n");
exit(-1);
}
}
/* Main function */
int main(int argc,char *argv[]){
int listen_port,repeat_port;
int sds[2],ready[2];
/* Analyze arguments */
if(argc==3){
listen_port=atoi(argv[1]);
repeat_port=atoi(argv[2]);
}
else{
listen_port=PORT_LISTEN;
repeat_port=PORT_REPEAT;
}
fprintf(stderr,"Listening on UDP port %d, repeating on UDP port %d.\n",listen_port,repeat_port);
/* Wait for activity on repeating port */
fprintf(stderr,"Listening on UDP port %d for activity.\n",listen_port);
sds[0]=create_socket(repeat_port,1);
if(sds[0]<0){
fprintf(stderr,"Cannot bind to port %d.\n",repeat_port);
exit(-1);
}
if(wait_activity(sds,ready,1)==1){
fprintf(stderr,"Found activity on port %d, exiting.\n",repeat_port);
exit(-1);
}
/* Wait for packet on a port and repeat on the other */
fprintf(stderr,"Entering repeating mode.\n");
sds[1]=create_socket(listen_port,1);
if(sds[1]<0){
fprintf(stderr,"Cannot bind to port %d.\n",listen_port);
exit(-1);
}
while(1){
if(wait_activity(sds,ready,2)<0){
fprintf(stderr,"No more activity on port %d, exiting.\n",listen_port);
exit(0);
}
if(ready[0]==1) repeat_packet(sds[0],sds[1],listen_port);
if(ready[1]==1) repeat_packet(sds[1],sds[1],repeat_port);
}
}