1 /*
2 * Simple Jitter program (client side)
3 * Alcatel Alenia Space - 2006
4 * GPL Licence
5 * Author: Nicolas Hennion
6 */
7
8 #include "jitter.h"
9
10 /* Global variables */
11 int socketfd;
12 struct sockaddr_in serveraddr;
13 #ifdef IPV6_SUPPORT
14 struct sockaddr_in6 serveraddr6;
15 #endif
16
main(int argc,char ** argv)17 int main(int argc, char **argv) {
18 short int tag6 = 0;
19
20 socklen_t slen=sizeof(serveraddr);
21 #ifdef IPV6_SUPPORT
22 socklen_t slen6=sizeof(serveraddr6);
23 #endif
24
25 struct hostent *hptr;
26 char *buf, server_name[BUFFER_CHAR], server_ip[BUFFER_CHAR];
27 extern char *optarg;
28 int i, errflag=1, n_flag=0, t_flag=0;
29 int packet_number=DEFAULT_PACKET_NUMBER, time_number=DEFAULT_TIME_NUMBER;
30 int port_number=DEFAULT_PORT_NUMBER, buffer_size=DEFAULT_BUFFER_SIZE, bitrate=DEFAULT_BITRATE, tos = DEFAULT_TOS;
31 double begin=0, end=0, sendbegin=0, sendend=0, lastprogressbar=0;
32 unsigned long packet_delay, packet_size;
33
34 /* Manage arguments */
35 #ifdef IPV6_SUPPORT
36 while ((i = getopt(argc, argv, "6c:n:t:p:w:b:s:v")) != EOF) {
37 #else
38 while ((i = getopt(argc, argv, "c:n:t:p:w:b:s:v")) != EOF) {
39 #endif
40 switch (i) {
41 #ifdef IPV6_SUPPORT
42 case '6':
43 tag6 = 1;
44 break;
45 #endif
46 case 'c':
47 strncpy(server_name, optarg, BUFFER_CHAR);
48 if (!tag6) {
49 /* IPv4 */
50 hptr = gethostbyname(server_name);
51 #ifdef IPV6_SUPPORT
52 } else {
53 /* IPv6 */
54 hptr = gethostbyname2(server_name,AF_INET6);
55 #endif
56 }
57 if (hptr == NULL) {
58 fprintf(stderr, "Invalid server IP address or name...\n");
59 errflag = 1;
60 } else {
61 inet_ntop(hptr->h_addrtype, *(hptr->h_addr_list), server_ip, sizeof(server_ip));
62 errflag = 0;
63 }
64 break;
65 case 's':
66 /* TOS option specified */
67 sscanf(optarg, "%x", &tos);
68 if ((tos < 0x00) || (tos > 0xFF))
69 errflag = 1;
70 break;
71 case 'n':
72 sscanf(optarg, "%d", &packet_number);
73 n_flag = 1;
74 if ((packet_number < 2) || (packet_number > MAX_PACKET_NUMBER) || t_flag)
75 errflag = 1;
76 break;
77 case 't':
78 sscanf(optarg, "%d", &time_number);
79 t_flag = 1;
80 if ((time_number < 2) || n_flag)
81 errflag = 1;
82 break;
83 case 'p':
84 sscanf(optarg, "%d", &port_number);
85 if ((port_number < 1024) || (port_number > MAX_PORT_NUMBER))
86 errflag = 1;
87 break;
88 case 'w':
89 sscanf(optarg, "%d", &buffer_size);
90 if ((buffer_size < MIN_BUFFER_SIZE) || (buffer_size > MAX_BUFFER_SIZE))
91 errflag = 1;
92 break;
93 case 'b':
94 sscanf(optarg, "%d", &bitrate);
95 if (bitrate < 11 )
96 errflag = 1;
97 break;
98 case 'v':
99 fprintf(stderr, "version: sjitter client version %s\n", SJITTERC_VERSION);
100 errflag = 1;
101 break;
102 }
103 }
104 if (errflag) {
105 #ifdef IPV6_SUPPORT
106 fprintf(stderr, "usage: sjitterc [-6] -c SERVER [[-n NBPCKT] | [-t SECOND]] [-p PORTNB] [-w SIZE] [-b BITRAT] [-s TOS]\n");
107 fprintf(stderr, "\t-6 : Use the IPv6 protocol\n");
108 #else
109 fprintf(stderr, "usage: sjitterc -c SERVER [[-n NBPCKT] | [-t SECOND]] [-p PORTNB] [-w SIZE] [-b BITRAT] [-s TOS]\n");
110 #endif
111 fprintf(stderr, "\t-c SERVER: where SERVER is the server IP address or name\n");
112 fprintf(stderr, "\t-n NBPCKT: where NCPCKT is the number of datagram (>1 , <%d) [default:%d]\n", MAX_PACKET_NUMBER, DEFAULT_PACKET_NUMBER);
113 fprintf(stderr, "\t-t SECOND: where SECOND is the number of second (>1) [default:%d]\n", DEFAULT_TIME_NUMBER);
114 fprintf(stderr, "\t-p PORTNB: where PORTNB is the port number (>1024, <%d) [default:%d]\n", MAX_PORT_NUMBER, DEFAULT_PORT_NUMBER);
115 fprintf(stderr, "\t-w SIZE: where SIZE is the application buffer size (bytes) (>%d, <%d) [default:%d]\n", MIN_BUFFER_SIZE, MAX_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
116 fprintf(stderr, "\t-b BITRATE: where BITRATE is the bitrate (IP level) in Kbps (>10) [default:%d]\n", DEFAULT_BITRATE);
117 fprintf(stderr, "\t-s TOS: where TOS is the hexadecimal value for IP header TOS field (>=0x00, <=0xFF) [default:%x]\n", DEFAULT_TOS);
118 if (n_flag && t_flag) {
119 fprintf(stderr, "It is not possible to use -n and -t in the same command line\n");
120 }
121 exit(2);
122 }
123
124 /* Buffer allocation */
125 buf = (char *) malloc(buffer_size);
126
127 /* Signals management */
128 signal(SIGINT, onsignal);
129 signal(SIGTERM, onsignal);
130 signal(SIGQUIT, onsignal);
131
132 /* Build the socket */
133 if (!tag6) {
134 /* IPv4 */
135 if ((socketfd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
136 errorexit("IPv4 socket error");
137 /* Set TOS field */
138 if (setsockopt(socketfd, IPPROTO_IP, IP_TOS, (char*) &tos, sizeof(tos)) == -1)
139 errorexit("IPv4 setsockopt error");
140 memset((char *) &serveraddr, sizeof(serveraddr), 0);
141 serveraddr.sin_family = AF_INET;
142 serveraddr.sin_port = htons(port_number);
143 if (inet_aton(server_ip, &serveraddr.sin_addr)==0)
144 perror("IPv4 inet_aton error");
145 #ifdef IPV6_SUPPORT
146 } else {
147 /* IPV6 */
148 if ((socketfd=socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP))==-1)
149 errorexit("IPv6 socket error");
150 memset((char *) &serveraddr6, sizeof(serveraddr6), 0);
151 serveraddr6.sin6_family = AF_INET6;
152 serveraddr6.sin6_port = htons(port_number);
153 if (inet_pton(AF_INET6, server_ip, &serveraddr6.sin6_addr)==0)
154 perror("IPV6 inet_aton error");
155 #endif
156 }
157
158 if (t_flag) {
159 /* -t option set, compute the packet number */
160 packet_number = (time_number*(bitrate*1000.0))/((buffer_size+28)*8);
161 } else {
162 /* Compute the estimate time */
163 time_number = (packet_number*((buffer_size+28)*8))/(bitrate*1000.0);
164 }
165 if (!tag6) {
166 /* IPv4 */
167 printf("Send data (%d datagrams of %d bytes / %d Kbps) to the server:port %s:%d\n",
168 packet_number, buffer_size, bitrate, inet_ntoa(serveraddr.sin_addr), port_number);
169 #ifdef IPV6_SUPPORT
170 } else {
171 /* IPv6 */
172 char buf6[INET6_ADDRSTRLEN];
173 printf("Send data (%d datagrams of %d bytes / %d Kbps) to the [server]:port [%s]:%d\n",
174 packet_number, buffer_size, bitrate, inet_ntop(AF_INET6, &serveraddr6.sin6_addr, buf6, sizeof(buf6)), port_number);
175 #endif
176 }
177
178 /* Send configuration datagram to the server */
179 snprintf(buf, buffer_size, "SJITTER-START %d %d ", packet_number, buffer_size);
180 if (!tag6) {
181 /* IPv4 */
182 if (sendto(socketfd, buf, buffer_size, 0, (const struct sockaddr *) &serveraddr, slen)==-1)
183 errorexit("IPv4 sendto error");
184 #ifdef IPV6_SUPPORT
185 } else {
186 /* IPv6 */
187 if (sendto(socketfd, buf, buffer_size, 0, (const struct sockaddr *) &serveraddr6, slen6)==-1)
188 errorexit("IPv6 sendto error");
189 #endif
190 }
191
192 /* Compute delay for bitrate (goal on the IP level) */
193 packet_size = (unsigned long) ((buffer_size+28)*8);
194 packet_delay = (unsigned long) ((packet_size/(bitrate*1000.0))*1000000);
195
196 /* Send data to the server */
197 /* Init the packet number tag */
198 i=0;
199 /* Star the main loop */
200 printf("Sending data (estimate time: %d seconds)...\n", time_number);
201 begin = lastprogressbar = getcurrenttimems();
202 while (i<packet_number) {
203
204 /* Manage bitrate */
205 usleep(packet_delay-((sendend-sendbegin)*1000000));
206
207 /* Send datagram on the network interface */
208 sendbegin = getcurrenttimems(); /* Send begin... */
209 snprintf(buf, buffer_size, "SJITTER-DATA %d %lf ", i, sendbegin);
210 if (!tag6) {
211 /* IPv4 */
212 if (sendto(socketfd, buf, buffer_size, 0, (const struct sockaddr *) &serveraddr, slen)==-1)
213 errorexit("IPv4 sendto error");
214 #ifdef IPV6_SUPPORT
215 } else {
216 /* IPv6 */
217 if (sendto(socketfd, buf, buffer_size, 0, (const struct sockaddr *) &serveraddr6, slen6)==-1)
218 errorexit("IPv6 sendto error");
219 #endif
220 }
221 sendend = getcurrenttimems(); /* ... send end */
222
223 /* Display progress bar (every 1 second)*/
224 if ((sendend-lastprogressbar) > 1) {
225 progressbar(i, packet_number);
226 lastprogressbar = sendend;
227 }
228
229 /* Next packet */
230 i++;
231 }
232 end = getcurrenttimems();
233
234 /* Send "SJITTER-END" datagram to the server */
235 snprintf(buf, buffer_size, "SJITTER-END ");
236 if (!tag6) {
237 /* IPv4 */
238 if (sendto(socketfd, buf, buffer_size, 0, (const struct sockaddr *) &serveraddr, slen)==-1)
239 errorexit("IPv4 sendto error");
240 #ifdef IPV6_SUPPORT
241 } else {
242 /* IPv6 */
243 if (sendto(socketfd, buf, buffer_size, 0, (const struct sockaddr *) &serveraddr6, slen6)==-1)
244 errorexit("IPv6 sendto error");
245 #endif
246 }
247
248 /* Summary */
249 printf("\r \r");
250 printf("Summary: %d datagrams sent in %.2lf seconds (%.0lf Kbps)\n",
251 packet_number, end-begin, (packet_number*buffer_size*8)/(end-begin)/1000);
252
253 close(socketfd);
254 free(buf);
255
256 return 0;
257 }
258