int main(int argc,char **argv) { int z; int s; /* Socket */ int alen; /* Length of address */ struct sockaddr_in adr_clnt; /* Client */ char dgram[512]; /* Receive buffer */ char dtfmt[512]; /* Date/Time Result */ time_t td; /* Current Time and Date */ struct tm dtv; /* Date time values */ fd_set rx_set; /* Incoming req. set */ struct timeval tmout; /* Timeout value */
/* * Open a log file for append: */ if(log_open(LOGPATH) == -1) exit(1); /* No log file ! */
log("dgramisrvr started. \n");
/* * Other initialization: */ s = 0; /* Our socket is on std input */ FD_ZERO(&rx_set); /* Initialize */ FD_SET(s,&rx_set); /* Notice fd=0 */
/* * Now wait for incoming datagrams: */ for(;;) { /* * Blog until a datagram arrives: */ alen = sizeof adr_clnt;
/* * Log the request: */ log("Got request '%s' from %s port %d\n", dgram, inet_ntoa(adr_clnt.sin_addr), ntohs(adr_clnt.sin_port));
/* * Get the current date and time: */ time(&td); /* Current time & date */ dtv = *localtime(&td);
/* * Formate a new date and time string, * based upon the input format string: */ strftime(dtfmt, /* Formatted result */ sizeof dtfmt, /* Max size */ dgram, /* date/time format */ &dtv); /* Input values */
/* * Send the formatted result back to the * client program: */ z = sendto(s, /* Socket */ dtfmt, /* datagram result */ strlen(dtfmt), /* length */ 0, /* Flags:no options */ (struct sockaddr *)&adr_clnt, alen);
if(z<0) bail("sendto(2)");
/* * Wait for next packet or timeout: * * This is easily accomplished with the * use of select(2). */ do { /* Establish Timeout = 8.0 secs */ tmout.tv_sec = 8; /* 8 seconds */ tmout.tv_usec = 0; /* + 0 usec */
/* Wait for read event or timeout */ z = select(s+1,&rx_set,NULL,NULL,&tmout); }while(z==-1 && errno == ENITR);
/* * Exit if select(2) return an error * or if it idictes a timeout: */ if(z<=0) break; }
/* * Close the socket and exit: */ if(z == -1) log("%s:select(2) \n",strerror(errno)); else log("Time out:server exiting.\n");
int main(int argc,char **argv,char **envp) { int z; struct sockaddr_in adr_clnt; /* Client */ int alen; /* Address length */ char dgram[512]; /* Receive buffer */ char *str_addr; /* String form of addr */
/* * We must log denied attempts: */ if(log_open(LOGPATH) == -1) exit(1); /* Can't open log file! */
log("wrapper started.\n");
/* * Peek at datagram using MSG_PEEK: */ alen = sizeof adr_clnt; /* length */
z = recvfrom(0, /* Socket on std input */ dgram, /* Receiving buffer */ sizeof dgram, /* Max recv size */ MSG_PEEK, /* Flags:Peek */ (struct sockaddr *)&adr_clnt, &alen); /* Addr len, in & out */
if(z<0) bail("recvfrom(2),peeking at client" "address.");
/* * Covert IP address to string form: */ str_addr = inet_ntoa(adr_clnt.sin_addr);
if(strcmp(str_addr,"127.7.7.7") != 0) { /* * Not our special 127.7.7.7 address: */ log("Address %s port %d rejected.\n", str_addr,ntohs(adr_clnt.sin_port));
/* * We must read this packet now without * the MSG_PEEK option to discard dgram: */ z = recvfrom(0, /* Socket */ dgram, /* Receiving buffer */ sizeof dgram, /* Max rcv size */ 0, /* No flags */ (struct sockaddr *)&adr_clnt, &alen);
/* * Accpet this dgram request,and * launch the server: */ log("Address %s port %d accepted.\n", str_addr,ntohs(adr_clnt.sin_port));
/* * inetd has provied argv[0] from the * config file /etc/inetd.conf:we have * used this to indicate the server's * full pathname for this exampel.we * simply pass any other arguments and * environment as is. */ log("Starting '%s'\n",argv[0]); log_close(); /* No longer need this */
z = execve(argv[0],argv,envp);
/* * If control returns,the execve(2) * failed for some reason: */ log_open(LOGPATH); /* Re log */
/* * This function reports the error and * exits back to the shell: */ static void bail(char *on_what) { if(errno) { fputs(strerror(errno),stderr); fputs(": ",stderr); } fputs(on_what,stderr); fputc('\n',stderr); exit(1); }
/* * Bind the specific client address: */ z = bind(s,(struct sockaddr *)&adr_clnt,sizeof adr_clnt);
if(z==-1) bail("bind(2) of client address");
/* * Enter input client loop: */ for(;;) { /* * Prompt user for a date formate string: */ fputs("\nEnter format string: ",stdout); if(!fgets(dgram,sizeof dgram,stdin)) break; /* EOF */
z = strlen(dgram); if(z>0 && dgram[--z] == '\n') dgram[z] = 0; /* Stomp out newline */
/* * Send format string to server: */ z = sendto(s, /* Socket */ dgram, /* datagram to send */ strlen(dgram), /* dgram length */ 0, /* Flags:no options */ (struct sockaddr *)&adr_srvr, sizeof adr_srvr);
if(z<0) bail("sendto(2)");
/* * Wait for a response: * * NOTE: Control will hang here if the * wrapper decides we lack access (no * response will arrive). */ alen = sizeof adr;
z = recvfrom(s, /* Socket */ dgram, /* Receiving buffer */ sizeof dgram, /* Max recv size */ 0, /* Flags no options */ (struct sockaddr *)&adr, &alen); /* Addr len, in & out */
if(z<0) bail("recfrom(2)");
dgram[z]=0; /* NULL terminate */
/* * Report Result: */ printf("Result from %s port %u :" "\n\t'%s'\n", inet_ntoa(adr.sin_addr), (unsigned)ntohs(adr.sin_port), dgram); }
/* * Close the socket and exit: */ close(s); putchar('\n');
$ ./dgramcln2 127.0.0.1 127.7.7.7 Enter format string: %x Result from 127.7.7.7 port 9090 : '11/09/99' Enter format string: %x %X Result from 127.7.7.7 port 9090 : '11/09/99 19:11:32' Enter format string: CTRL+D $
$ tail -f /tmp/dgramisrvr.log [PID 1279] dgramisrvr started. [PID 1279] Got request '%A %B %D' from 127.7.7.7 port 1027 [PID 1279] Timed out: server exiting. [PID 1294] dgramisrvr started. [PID 1294] Got request '%x' from 127.7.7.7 port 1027 [PID 1294] Got request '%x %X' from 127.7.7.7 port 1027 [PID 1294] Timed out: server exiting.
最后四行日志记录表明服务器进程ID 1294 可以在超时之前处理两个数据请求。
御载演示程序
要御载演示程序,可以执行下面的命令:
$ make clobber rm -f *.o core a.out rm -f /tmp/wrapper.log /tmp/dgramisrvr.log rm -f /tmp/inetd.conf /tmp/wrapper /tmp/dgramisrvr rm -f dgramisrvr wrapper dgramcln2 studnt1 12763 1 0 23:04 ? 00:00:00 /usr/sbin/inetd /tmp/inetd.conf If you see your inetd process running above, you may want to kill it now. $