Introducing the Client Program
A modified version of an earlier client program is presented here. This client program requires two command-line arguments: the server address and the client address to use. The specification of the additional client IP address permits you to perform more experimentation with your TCP wrapper program. Listing 16.5 shows the modified datagram client program.
Example 16.5. dgramcln2.c—The Modified Datagram Client Program
<$nopage>
001 1: /* dgramcln2.c:
002 2: *
003 3: * Modified datagram client:
004 4: */
005 5: #include <stdio.h>
006 6: #include <unistd.h>
007 7: #include <stdlib.h>
008 8: #include <errno.h>
009 9: #include <string.h>
010 10: #include <time.h>
011 11: #include <sys/types.h>
012 12: #include <sys/socket.h>
013 13: #include <netinet/in.h>
014 14: #include <arpa/inet.h>
015 15:
016 16: /*
017 17: * This function reports the error and
018 18: * exits back to the shell:
019 19: */
020 20: static void
021 21: bail(const char *on_what) {
022 22:
023 23: if ( errno ) {
024 24: fputs(strerror(errno),stderr);
025 25: fputs(": ",stderr);
026 26: }
027 27: fputs(on_what,stderr);
028 28: fputc('\n',stderr);
029 29: exit(1);
030 30: }
031 31:
032 32: int
033 33: main(int argc,char **argv) {
034 34: int z;
035 35: char *srvr_addr = NULL; /* Srvr addr */
036 36: char *clnt_addr = NULL; /* Clnt addr */
037 37: struct sockaddr_in adr_srvr; /* Server */
038 38: struct sockaddr_in adr_clnt; /* Client */
039 39: struct sockaddr_in adr; /* AF_INET */
040 40: int alen; /* Socket addr length */
041 41: int s; /* Socket */
042 42: char dgram[512]; /* Recv buffer */
043 43:
044 44: /*
045 45: * Insist on two command-line arguments
046 46: * (without port numbers):
047 47: *
048 48: * dgramcln2 <server_addr> <client_addr>
049 49: */
050 50: if ( argc != 3 ) {
051 51: fputs("Usage: dgramclnt <server_ipaddr> "
052 52: "<client_ipaddr>\n",stderr);
053 53: return 1;
054 54: }
055 55:
056 56: srvr_addr = argv[1]; /* 1st arg is srv */
057 57: clnt_addr = argv[2]; /* 2nd arg is cln */
058 58:
059 59: /*
060 60: * Create a server socket address: <$nopage>
061 61: */
062 62: memset(&adr_srvr,0,sizeof adr_srvr);
063 63: adr_srvr.sin_family = AF_INET;
064 64: adr_srvr.sin_port = htons(9090);
065 65: adr_srvr.sin_addr.s_addr =
066 66: inet_addr(srvr_addr);
067 67:
068 68: if ( adr_srvr.sin_addr.s_addr == INADDR_NONE )
069 69: bail("bad server address.");
070 70:
071 71: /*
072 72: * Create a UDP socket:
073 73: */
074 74: s = socket(AF_INET,SOCK_DGRAM,0);
075 75: if ( s == -1 )
076 76: bail("socket()");
077 77:
078 78: /*
079 79: * Create the specific client address:
080 80: */
081 81: memset(&adr_clnt,0,sizeof adr_clnt);
082 82: adr_clnt.sin_family = AF_INET;
083 83: adr_clnt.sin_port = 0; /* Any port */
084 84: adr_clnt.sin_addr.s_addr =
085 85: inet_addr(clnt_addr);
086 86:
087 87: if ( adr_clnt.sin_addr.s_addr == INADDR_NONE )
088 88: bail("bad client address.");
089 89:
090 90: /*
091 91: * Bind the specific client address:
092 92: */
093 93: z = bind(s, (struct sockaddr *)&adr_clnt,
094 94: sizeof adr_clnt);
095 95:
096 96: if ( z == -1 )
097 97: bail("bind(2) of client address");
098 98:
099 99: /*
100 100: * Enter input client loop:
101 101: */
102 102: for (;;) {
103 103: /*
104 104: * Prompt user for a date format string:
105 105: */
106 106: fputs("\nEnter format string: ",stdout);
107 107: if ( !fgets(dgram,sizeof dgram,stdin) )
108 108: break; /* EOF */
109 109:
110 110: z = strlen(dgram);
111 111: if ( z > 0 && dgram[--z] == '\n' )
112 112: dgram[z] = 0; /* Stomp out newline */
113 113:
114 114: /*
115 115: * Send format string to server:
116 116: */
117 117: z = sendto(s, /* Socket */
118 118: dgram, /* datagram to snd */
119 119: strlen(dgram), /* dgram length */
120 120: 0, /* Flags: no options */
121 121: (struct sockaddr *)&adr_srvr,
122 122: sizeof adr_srvr);
123 123:
124 124: if ( z < 0 )
125 125: bail("sendto(2)");
126 126:
127 127: /*
128 128: * Wait for a response: <$nopage>
129 129: *
130 130: * NOTE: Control will hang here if the
131 131: * wrapper decides we lack access (no
132 132: * response will arrive).
133 133: */
134 134: alen = sizeof adr;
135 135:
136 136: z = recvfrom(s, /* Socket */
137 137: dgram, /* Receiving buffer */
138 138: sizeof dgram, /* Max recv size */
139 139: 0, /* Flags: no options */
140 140: (struct sockaddr *)&adr,
141 141: &alen); /* Addr len, in & out */
142 142:
143 143: if ( z < 0 )
144 144: bail("recvfrom(2)");
145 145:
146 146: dgram[z] = 0; /* NULL terminate */
147 147:
148 148: /*
149 149: * Report Result:
150 150: */
151 151: printf("Result from %s port %u :"
152 152: "\n\t'%s'\n",
153 153: inet_ntoa(adr.sin_addr),
154 154: (unsigned)ntohs(adr.sin_port),
155 155: dgram);
156 156: }
157 157:
158 158: /*
159 159: * Close the socket and exit:
160 160: */
161 161: close(s);
162 162: putchar('\n');
163 163:
164 164: return 0;
165 165: } <$nopage>
166 <$nopage>
The client program will not be covered in much detail, because it is very similar to the program dgramclnt.c presented in Listing 6.2 in Chapter 6, "Connectionless-Oriented Protocols." Aside from some cosmetic differences, the primary modifications added were
Lines 50 to 54 now insist that two command-line arguments be supplied.
The local socket is bound to the IP address specified in argv[2] with bind(2) (lines 81 to 97). This will be instrumental in your testing later.
Note that the program dgramcln2 will hang if the wrapper program decides that it should not gain access to the server. This occurs because the recvfrom(2) function never receives a reply from the server (lines 136 to 144). When this happens, you will need to interrupt out of the program (usually Ctrl+C is the interrupt character, but yours might be different).