Try   HackMD

UDP Client/Server (select)

Author: WhoAmI
Date: 20220726
Copyright: CC BY-NC-SA

/*
20190225
udps.c

Author:WhoAmI

UDP client/server

maximum transmission unit (MTU):
Please see https://en.wikipedia.org/wiki/Maximum_transmission_unit

TTL problems:

void setttl(int sock, uint8_t ttl)
{
int ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(uint8_t));
if (ret != 0)
printf("Failed to setsockopt(): %s\n", strerror(errno));
}

IP fragmentation (特別經過 VPN):

Please see https://en.wikipedia.org/wiki/IP_fragmentation

Route problems

*/

udps.c

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> /*******************************/ /* FIXME */ /* MTU */ /*******************************/ #define MAXMTU 2500 /*******************************/ #define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); } #define STDIN 0 #define TIMEOUT 10 #define READSIZE 512 #define DEFAULT_PORT 9999 #define DEFAULT_CPORT 9990 static void hander(int sig) { printf("sig=%d\n",sig); } static ssize_t dump_frame(int fd, const void *buf,size_t len,int flags,const struct sockaddr *dest_addr, socklen_t addrlen) { ssize_t n; int mode=0; n=0; if(mode==0) { n=sendto(fd,buf,len,flags,dest_addr,addrlen); // n=write(fd,buf,count); } return n; } static ssize_t forward_frame(int fd, const void *buf,size_t len,int flags,const struct sockaddr *dest_addr, socklen_t addrlen) { /* ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); */ ssize_t n; int mode=0; n=0; if(mode==0) { n=sendto(fd,buf,len,flags,dest_addr,addrlen); } return n; } #define DEFAULTIP "127.0.0.1" int udp_client(int _port,int _rport, char *ip, int secs) { int server_fd; int remote_port; ssize_t recvbytes; char rbuf[MAXMTU]; struct sockaddr_in server_addr; struct sockaddr_in remote_addr,client_addr; char *remote_ip=DEFAULTIP; fd_set master_fds; fd_set read_fds; int fdmax; struct timeval tv; int port; int len; int i, j; char buf[READSIZE],ch; int nbytes; int yes=1; int retval; int connections=0; port=DEFAULT_CPORT; if(_port>0)port=_port; remote_port=9999; if(_rport>0)remote_port=_rport; if(ip!=NULL)remote_ip=ip; signal(SIGPIPE,hander); FD_ZERO(&master_fds); FD_ZERO(&read_fds); /* UDP SOCK_DGRAM */ if ((server_fd = socket(AF_INET, SOCK_DGRAM , 0)) == -1) PANIC("socket"); if (setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) PANIC("setsockopt"); memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(port); if (bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr))==-1) PANIC("bind"); FD_SET(server_fd,&master_fds); FD_SET(STDIN,&master_fds); //read from STDIN fdmax = server_fd; connections=0; /* in_addr_t inet_addr(const char *cp);*/ //clean remote_addr and set values memset(&remote_addr,0,sizeof(remote_addr)); remote_addr.sin_family = AF_INET; remote_addr.sin_addr.s_addr = inet_addr(remote_ip);; remote_addr.sin_port = htons(remote_port); // Server Loop for(;;) { tv.tv_sec = secs; tv.tv_usec = 0; read_fds=master_fds; retval = select(fdmax+1,&read_fds,NULL,NULL,&tv); switch(retval) { case -1: perror("select"); break; case 0: printf("C:Time Out...\n"); default: if (FD_ISSET(server_fd,&read_fds)) { /* ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); Please see man page */ printf("C:Recv from %d\n",server_fd); memset((struct sockaddr_in *)&client_addr,0,sizeof(client_addr)); len=sizeof(client_addr); if ((recvbytes=recvfrom(server_fd,rbuf, MAXMTU,0,(struct sockaddr *)&client_addr,&len)) == -1) { perror("recvfrom"); continue; } else { printf("C:New frame from %s on socket %d, connection=%d\n",inet_ntoa(client_addr.sin_addr),server_fd,connections); write(1,rbuf,recvbytes);//FIXME write to stdout } } ; break; }//switch printf("\nInput bytes:>\n"); if ((nbytes=read(0, buf, sizeof(buf))) > 0) //FIXME: we can read from stdin { for(j=server_fd; j<=fdmax; j++) { if (FD_ISSET(j, &master_fds)) { printf("C:Forward %d bytes to %d\n",nbytes,j); if (forward_frame(j, buf, nbytes, 0,(const struct sockaddr *)&remote_addr,sizeof(remote_addr)) == -1) { printf("socket fd=%d",j); perror("send"); } } }//for } }//for server loop return 0; } static ssize_t readln(int sockfd, char *buf,size_t len, int time_out) { int n; fd_set readfds; struct timeval tval; ssize_t total; int ret; char *pc; total=0; FD_ZERO(&readfds); do { FD_SET(sockfd, &readfds); tval.tv_sec = time_out; tval.tv_usec = 0; if(time_out<=0) { if(( n = select(sockfd+1, &readfds, NULL, NULL, NULL))<0)return -1; } else { if ( (n = select(sockfd+1, &readfds, NULL, NULL, time_out ? &tval : NULL)) == 0) { errno = ETIMEDOUT; printf("Read timeout!\n"); return(-1); } } ret=read(sockfd,buf+total,1); //Notice that '\n' pc= buf+total; if(ret>0) { total+=ret; if(*pc=='\n')break; } else if(ret==0) { //eof break; } else { return -1; } } while(total<len); if(total<len)buf[total]=0; else buf[len-1]=0; return total; } int main_server(int _port, int secs,int echo) { int server_fd; int client_fd; ssize_t recvbytes; char rbuf[MAXMTU]; struct sockaddr_in server_addr; struct sockaddr_in client_addr; fd_set master_fds; fd_set read_fds; int fdmax; struct timeval tv; int port; int len; int i, j; char buf[READSIZE],ch; int nbytes; int yes=1; int retval; int connections=0; int READIN=0; port=DEFAULT_PORT; if(_port>0)port=_port; signal(SIGPIPE,hander); FD_ZERO(&master_fds); FD_ZERO(&read_fds); /* UDP SOCK_DGRAM */ if ((server_fd = socket(AF_INET, SOCK_DGRAM , 0)) == -1) PANIC("socket"); if (setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) PANIC("setsockopt"); memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(port); if (bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr))==-1) PANIC("bind"); #ifdef TCPSERVER if (listen(server_fd,10) == -1) PANIC("listen"); #endif FD_SET(server_fd,&master_fds); // FD_SET(STDIN,&master_fds); //read from STDIN fdmax = server_fd; connections=0; // Server Loop for(;;) { tv.tv_sec =secs; tv.tv_usec = 0; read_fds=master_fds; fprintf(stderr,"S:Wait...%d secs\n",secs); retval = select(fdmax+1,&read_fds,NULL,NULL,&tv); switch(retval) { case -1: perror("select"); break; case 0: fprintf(stderr,"S:Time Out...\n"); default: //20190224 BUG FIXED! for(i=server_fd; i<= fdmax; i++) { if (FD_ISSET(i,&read_fds)) { /* ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); */ memset((struct sockaddr_in *)&client_addr,0,sizeof(client_addr)); len=sizeof(client_addr); if ((recvbytes=recvfrom(server_fd,rbuf, MAXMTU,0,(struct sockaddr *)&client_addr,&len)) == -1) { perror("recvfrom"); continue; } else { fprintf(stderr,"S:New frame from %s:%d on socket %d, connection=%d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),server_fd,connections); //echo len=sizeof(client_addr); if( echo){ dump_frame(server_fd,rbuf,recvbytes,0,(struct sockaddr *)&client_addr,len);//FIXME } write(1,rbuf,recvbytes); } } } // exit(0); break; }//switch if(READIN==1) { printf("S:Read from stdin...10 secs>\n"); if ((nbytes=readln(0, buf, sizeof(buf),10)) > 0) //FIXME: we can read from stdin { for(j=server_fd; j<=fdmax; j++) { if (FD_ISSET(j, &master_fds)) { printf("S:Send %d bytes to others...",nbytes); if (forward_frame(j, buf, nbytes, 0,(const struct sockaddr *)&client_addr,sizeof(client_addr)) == -1) { perror("send"); } } }//for } }//read from stdin }//for server loop return 0; } int main(int argc, char *argv[]) { int port=DEFAULT_PORT; int mode=0; //default: server int i; char *ip="127.0.0.1"; int rport=DEFAULT_PORT; //remort port int lport=DEFAULT_PORT-10; //remort port int timeout=TIMEOUT; int ret; int echo=0; if(argc>1) { for(i=1;i<argc;i++) { if(strcmp(argv[i],"-t")==0) { i++; timeout=atoi(argv[i]); } if(strcmp(argv[i],"-c")==0) { mode=1; //client } if(strcmp(argv[i],"-s")==0) { mode=atoi(argv[++i]); //server printf("mode=%d\n",mode); } if(strcmp(argv[i],"-ip")==0) { ip=argv[++i]; } if(strcmp(argv[i],"-rport")==0) { rport=atoi(argv[++i]); } if(strcmp(argv[i],"-port")==0) { port=atoi(argv[++i]); lport=port; } if(strcmp(argv[i],"-echo")==0) { echo=1; printf("Echo on!\n"); } } } else { printf("Usage:\n%s [-c] [-s 1] [-ip 127.0.0.1] [-rport 9999] [-port 9999] [-t 60]\n\n",argv[0]); printf("default: %s -s %d -ip %s -rport %d -port %d -t %d\n",argv[0],mode,ip,rport,port,timeout); } if(mode==0) { printf("Server start on UDP port %d...\n",port); ret=main_server(port, timeout,echo); } if(mode==1) { printf("Client start on port %d...remort ip=%s port=%d\n",lport, ip,rport); //int udp_client(int _port,int _rport, char *ip, int secs) ret=udp_client(lport,rport,ip, timeout); } }