Previous Contents

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);
  }
}

Previous Contents