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