]> rtime.felk.cvut.cz Git - frescor/fwp.git/blob - wme_test/wclient.c
Kosmeticke upravy wclient.c, pridani DEBUG volby
[frescor/fwp.git] / wme_test / wclient.c
1 #include <errno.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <netinet/in.h>
5 #include <arpa/inet.h>
6 #include <netdb.h>
7 #include <signal.h>
8 #include <sys/wait.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <time.h>
13 #include <string.h>
14 #include <pthread.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <stdbool.h>
18
19 /*#define AC_VO 0
20 #define AC_VI 1
21 #define AC_BE 2
22 #define AC_BK 3
23 */
24
25 #define PARAM_SERVERADDR 1
26 #define BASE_PORT        5100
27 #define AC_QUEUES        4
28 #define MAX_SENDENDPOINTS  10
29 #define MTU              800 
30
31 // Turn on/off debugging
32 #define DEBUG 0
33
34 enum {  AC_VO = 0,
35         AC_VI = 1,
36         AC_BE = 2,
37         AC_BK = 3
38 };
39
40 const int prio_to_ac[8] = {2,3,3,2,1,1,0,0};
41 const unsigned int ac_to_tos[4] = {224,160,96,64};
42
43 int ac_sockfd[AC_QUEUES];
44 FILE* logfd;
45 char* server_addr; 
46
47 const char logfname[] = "delay_stats.dat";
48
49 struct msg_t {
50         unsigned int tos;
51         struct timespec send_timestamp;
52         unsigned long int seqn;
53         unsigned char padding[MTU];
54 };
55
56 /* maximal traffic delay in ms - 10 s*/
57 #define MAX_DELAY_US 10000000
58 #define GRANULARITY 100
59
60 unsigned delay_stats[AC_QUEUES][MAX_DELAY_US/GRANULARITY];
61
62 /*struct ac_stats[AC_QUEUES] {
63    unsigned long int min_trans_time;
64    unsigned long int sum_trans_time;
65    struct timespec   recv_timestamp;
66    struct timespec   send_timestamp; 
67 };*/
68
69 struct send_endpoint {
70         int ac;
71         long period_nsec;
72         int bandwidth_bps;      /* bits per second */
73 };
74
75 #define MSEC (1000*1000)
76 #define Mbit (1024*1024)
77 #define Kbit 1024
78
79
80 /*
81 struct send_endpoint sepoint[] = {
82         { .ac = AC_VO, .period_nsec=200*MSEC, .bandwidth_bps = 34*Kbit },
83         { .ac = AC_VI, .period_nsec=25*MSEC, .bandwidth_bps =  480*Kbit },
84         { .ac = AC_BE, .period_nsec=40*MSEC, .bandwidth_bps =  300*Kbit },
85         { .ac = AC_BK, .period_nsec=40*MSEC, .bandwidth_bps =  300*Kbit },
86 //      { .ac = AC_VI, .period_nsec=17*MSEC, .bandwidth_bps =  675*Kbit },
87 };
88 */
89
90 struct send_endpoint sepoint[] = {
91         { .ac = AC_VO, .period_nsec=40*MSEC, .bandwidth_bps = 300*Kbit },
92         { .ac = AC_VI, .period_nsec=40*MSEC, .bandwidth_bps =  300*Kbit },
93         { .ac = AC_BE, .period_nsec=60*MSEC, .bandwidth_bps =  200*Kbit },
94         { .ac = AC_BK, .period_nsec=60*MSEC, .bandwidth_bps =  200*Kbit },
95 };
96
97 unsigned int nr_sepoints = sizeof(sepoint)/sizeof(*sepoint);
98
99 void stopper()
100 {
101         int ac, i, maxi;
102         bool allzeros;
103         unsigned sum[AC_QUEUES];
104
105         printf("\n Writing data to log file...\n");
106
107         allzeros = true;
108         for (maxi = MAX_DELAY_US/GRANULARITY - 1; maxi >= 0; maxi--) {
109                 for (ac = 0; ac < AC_QUEUES; ac++) {
110                         if (delay_stats[ac][maxi] != 0) allzeros = false;
111                 }
112                 if (!allzeros) break;
113         }
114         if (maxi < 10000/GRANULARITY) maxi = 10000/GRANULARITY;
115
116         for (ac = 0; ac < AC_QUEUES; ac++) { 
117                 sum[ac] = 0;
118                 for ( i = 0 ; i < maxi; i++) 
119                         sum[ac]+=delay_stats[ac][i];
120                 if (sum[ac] == 0)
121                         fprintf(stderr, "No response in AC %d\n", ac);
122         }
123
124         for (ac = 0; ac < AC_QUEUES; ac++) { 
125                 for ( i = 0 ; i < maxi; i++) {
126                         double val;
127                         val = (double)delay_stats[ac][i]*100.0 / sum[ac];
128                         fprintf(logfd,"%f %lf\n", i*GRANULARITY/1000.0, val);
129                 }
130                 
131                 fprintf(logfd, "\n\n");
132         }
133         
134         printf("Finished.\n");
135         fclose(logfd);
136
137         exit(0);
138 }
139
140 static inline 
141 void timespec_add (struct timespec *sum, const struct timespec *left,
142               const struct timespec *right)
143 {
144         sum->tv_sec = left->tv_sec + right->tv_sec;
145         sum->tv_nsec = left->tv_nsec + right->tv_nsec;
146
147         if (sum->tv_nsec >= 1000000000){
148                 ++sum->tv_sec;
149                 sum->tv_nsec -= 1000000000;
150         }
151 }
152
153 static inline 
154 void timespec_sub (struct timespec *diff, const struct timespec *left,
155               const struct timespec *right)
156 {
157         diff->tv_sec = left->tv_sec - right->tv_sec;
158         diff->tv_nsec = left->tv_nsec - right->tv_nsec;
159
160         if (diff->tv_nsec < 0){
161                   --diff->tv_sec;
162                   diff->tv_nsec += 1000000000;
163         }
164 }
165
166 int create_ac_socket(unsigned int ac) 
167 {
168         int sockfd;
169         unsigned int yes=1, tos;
170
171
172         if ((sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
173         {
174                 perror("Unable to open socket");
175                 return -1;
176         }
177         
178         if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
179                 perror("Unable to set socket");
180                 return -1;
181         }
182
183         
184         //tos = ((AC_QUEUES - ac) *2 - 1)*32;
185         tos = ac_to_tos[ac];
186         if (setsockopt(sockfd, SOL_IP, IP_TOS, &tos, sizeof(tos))) {
187                 perror("Unable to set TOS");
188                 close(sockfd);
189                 return -1;
190         }
191
192         return sockfd;
193 }
194
195
196 void* receiver(void* queue)
197 {
198         struct msg_t    msg;
199         struct  sockaddr_in rem_addr;
200         int     mlen;
201         unsigned int ac, rem_addr_length; 
202         unsigned long int trans_time_usec;
203         unsigned long int min_trans_time;
204         struct timespec   send_timestamp,recv_timestamp, trans_time; 
205         
206         min_trans_time = ~0;
207         
208         ac = (int)queue;
209         rem_addr_length = sizeof(rem_addr);
210         while (1) {
211                 while ((mlen = recvfrom(ac_sockfd[ac], &msg, sizeof(msg), 0,\
212                         (struct sockaddr*)&rem_addr, &rem_addr_length)) < 0) {
213                             if (errno == EINTR) continue;
214                             perror("Chyba pri prijimani pozadavku");
215                             return NULL;
216                 }       
217                 clock_gettime(CLOCK_MONOTONIC,&recv_timestamp);
218                 send_timestamp = msg.send_timestamp;
219                 
220                 timespec_sub(&trans_time,&recv_timestamp ,&send_timestamp);
221                 trans_time_usec = (trans_time.tv_sec * 1000000 + \
222                                          trans_time.tv_nsec / 1000) /2;
223           
224                 if (trans_time_usec < MAX_DELAY_US)
225                         delay_stats[ac][trans_time_usec/GRANULARITY]++;
226         
227                 /*if (trans_time_nsec < min_trans_time) 
228                         min_trans_time = trans_time_nsec;*/
229                 /*printf("seqn= %lu tos= %d start= %lu(s).%lu(ns)"\
230                          "stop= %lu(s).%lu(ns)\n trans_time = %lums\n",\
231                          msg.seqn, msg.tos, send_timestamp.tv_sec,\
232                          send_timestamp.tv_nsec,recv_timestamp.tv_sec,\
233                          recv_timestamp.tv_nsec, trans_time_msec); */
234         }
235 }
236
237 void* sender(void* endpoint)
238 {
239         struct sockaddr_in rem_addr;
240         struct msg_t msg;
241         unsigned long int seqn;
242         struct timespec time_to_wait, current_time, period, interval;
243         struct hostent* ph;
244         struct send_endpoint* spoint = (struct send_endpoint*) endpoint;
245         int ac = spoint->ac;
246         
247         memset(&rem_addr,0, sizeof(rem_addr));
248         //-------------------------------------------------------------------
249         // TODO: not functioning - check it
250                 
251         if ((rem_addr.sin_addr.s_addr = inet_addr(server_addr)) == INADDR_NONE){
252            ph = gethostbyname(server_addr);
253            if (ph) 
254                    rem_addr.sin_addr = *((struct in_addr *)ph->h_addr);
255            else {
256                    perror("Unknown server"); 
257            }
258         }
259         
260         //------------------------------------------------------------------
261  
262         rem_addr.sin_family = AF_INET;
263         rem_addr.sin_addr.s_addr =  inet_addr(server_addr);
264         rem_addr.sin_port = htons(BASE_PORT + ac);
265         seqn = 0;
266         
267         period.tv_nsec = spoint->period_nsec;
268         period.tv_sec = 0;
269
270         while (1) {
271
272                 msg.seqn = seqn;
273                 msg.tos = ac_to_tos[ac];
274                 
275                 clock_gettime(CLOCK_MONOTONIC,&msg.send_timestamp);
276                 
277                 while (sendto(ac_sockfd[ac], &msg, sizeof(msg), 0,\
278                                 (struct sockaddr*)&rem_addr, sizeof(rem_addr)) < 0) {
279                                 if (errno == EINTR) continue;
280                                 perror("Error while sending.");
281                                 return NULL;
282                 }
283
284 #if DEBUG
285                 printf("%d", ac);
286                 fflush(stdout);
287 #endif
288                 seqn++;
289                 
290                 timespec_add(&time_to_wait,&msg.send_timestamp,&period);
291                 clock_gettime(CLOCK_MONOTONIC,&current_time);
292                 timespec_sub(&interval,&time_to_wait,&current_time);
293                 nanosleep(&interval,NULL);
294         }       
295 }
296
297 int main(int argc, char *argv[])
298 {
299         int ac, i, rc;
300         pthread_attr_t attr;
301         pthread_t thread;
302         int use_stdin = 0;
303         char opt;
304
305
306         while ((opt = getopt(argc, argv, "hs")) != -1) {
307                 switch (opt) {
308                         case 's':
309                                 use_stdin = 1;
310                                 break;
311                         default:
312                                 fprintf(stderr, "Usage: %s [ options ] server_addr\n", argv[0]);
313                                 fprintf(stderr, "options:  -s  read streams from stdin\n");
314                                 exit(1);
315                 }
316         }
317         if (optind < argc) {
318                 server_addr = argv[optind];
319         } else {
320                 fprintf(stderr, "Expected server address argument\n");
321                 exit(1);
322         }
323
324
325                 
326         memset(delay_stats,0, sizeof(delay_stats));     
327         pthread_attr_init(&attr);
328
329         if ((logfd = fopen(logfname,"w+")) == NULL) {
330                 fprintf(stderr,"Can not open %s\n", logfname);
331                 exit(1);
332         }
333                 
334
335         if (signal(SIGTERM, stopper) == SIG_ERR) {
336                 perror("Error in signal registration");
337                 exit(1);
338         }
339                 
340         if (signal(SIGINT, stopper) == SIG_ERR) {
341                 perror("Signal handler registration error");
342                 exit(1);
343         }
344         
345         /* create four receivers each per AC */
346         for (ac = AC_QUEUES - 1; ac >= 0; ac--) {
347                 ac_sockfd[ac] = create_ac_socket(ac);
348                 rc = pthread_create(&thread, &attr, receiver, (void*) ac);
349                 if (rc) {
350                         printf("Error while creating receiver %d\n",rc);
351                         return 1;
352                 }
353         }               
354                         
355         /* create sendpoints */
356         for (i = 0; i < nr_sepoints; i++) {
357                 rc = pthread_create(&thread, &attr, sender, (void*) &sepoint[i]);
358                 if (rc) {
359                         printf("Error while creating sender %d\n",rc);
360                         return 1;
361                 }
362         }
363         
364         while (1) {
365                 sleep(100000);
366         }
367         
368         return 0;
369 }