2 * inet (BSD) socket peer application
3 * starts a socket listener (server part) and connects to another
6 * 2010, Razvan Deaconescu
14 #include <sys/types.h>
15 #include <sys/socket.h>
19 #include "sock_util.h"
22 #define DEFAULT_LEADER_LISTEN_PORT 43210
23 #define DEFAULT_LEADER_HOSTNAME "localhost"
24 #define DEFAULT_FOLLOWER_LISTEN_PORT 54321
25 #define DEFAULT_FOLLOWER_HOSTNAME "localhost"
27 #define DEFAULT_SERVER_BACKLOG 5
29 #define PACKET_PAYLOAD_SIZE 120
30 #define PACKET_INDEX_SIZE sizeof(unsigned long long)
31 #define PACKET_TIMESPEC_SIZE sizeof(time_t)
32 #define PACKET_SIZE (PACKET_PAYLOAD_SIZE + PACKET_INDEX_SIZE + PACKET_TIMESPEC_SIZE)
34 #define TIMER_FREQUENCY_SECS 1
35 #define CLOCKID CLOCK_REALTIME
45 static char rcv_buf[PACKET_SIZE];
46 static char snd_buf[PACKET_SIZE];
48 /* connection socket */
51 static timer_t timerid;
53 static void init_buffer_random(char *buf, size_t len)
59 for (i = 0; i < len-2; i++)
60 buf[i] = (char) (rand() % 26) + 'a';
64 static void init_buffers(void)
66 init_buffer_random(rcv_buf, PACKET_PAYLOAD_SIZE);
67 init_buffer_random(snd_buf, PACKET_PAYLOAD_SIZE);
70 static void fill_send_buffer(void)
72 static unsigned long long index = 0;
74 time_t curr_time_secs;
76 curr_time_secs = time(NULL);
78 ptr = snd_buf + PACKET_PAYLOAD_SIZE;
79 * (unsigned long long *) ptr = index;
80 ptr += PACKET_INDEX_SIZE;
81 * (time_t *) ptr = curr_time_secs;
83 printf("[send] index: %llu curr_time_secs: %lu\n", index, curr_time_secs);
87 static ssize_t send_buffer(int sockfd)
89 return send(sockfd, snd_buf, PACKET_SIZE, 0);
92 static ssize_t receive_buffer(int sockfd)
94 return recv(sockfd, rcv_buf, PACKET_SIZE, 0);
97 static void timer_handler(int sig, siginfo_t *si, void *uc)
102 nbytes = send_buffer(connectfd);
103 DIE(nbytes < 0, "send_buffer");
106 static void remove_timer(void)
108 timer_delete(timerid);
111 static void schedule_timer(void)
116 struct itimerspec its;
119 memset(&sa, 0, sizeof(sa));
120 sa.sa_flags = SA_SIGINFO | SA_RESTART;
121 sa.sa_sigaction = timer_handler;
122 sigemptyset(&sa.sa_mask);
123 rc = sigaction(SIG, &sa, NULL);
124 DIE(rc < 0, "sigaction");
126 /* Block timer signal temporarily */
128 sigaddset(&mask, SIG);
129 rc = sigprocmask(SIG_SETMASK, &mask, NULL);
130 DIE(rc < 0, "sigprocmask");
132 /* Create the timer */
133 sev.sigev_notify = SIGEV_SIGNAL;
134 sev.sigev_signo = SIG;
135 sev.sigev_value.sival_ptr = &timerid;
136 rc = timer_create(CLOCKID, &sev, &timerid);
137 DIE(rc < 0, "timer_create");
139 /* Start the timer */
140 its.it_value.tv_sec = TIMER_FREQUENCY_SECS;
141 its.it_value.tv_nsec = 0;
142 its.it_interval.tv_sec = TIMER_FREQUENCY_SECS;
143 its.it_interval.tv_nsec = 0;
144 rc = timer_settime(timerid, 0, &its, NULL);
145 DIE(rc < 0, "timer_settime");
147 /* Unlock the timer signal, so that timer notification
149 rc = sigprocmask(SIG_UNBLOCK, &mask, NULL);
150 DIE(rc < 0, "sigprocmask");
153 static void print_buffer_meta(void)
155 unsigned long long index;
156 time_t curr_time_secs;
157 time_t sender_time_secs;
160 curr_time_secs = time(NULL);
162 ptr = rcv_buf + PACKET_PAYLOAD_SIZE;
163 index = * (unsigned long long *) ptr;
164 ptr += PACKET_INDEX_SIZE;
165 sender_time_secs = * (time_t *) ptr;
167 printf("[recv] index %llu, ", index);
168 if (sender_time_secs > curr_time_secs)
169 printf("negative latency (weird)\n");
171 printf("latency %lu seconds (curr_time = %lu, sender_time = %lu)\n",
172 curr_time_secs - sender_time_secs,
177 static void usage(const char *argv0)
179 fprintf(stderr, "Usage: %s [-l | --leader] [-p | --port <listen-port>] [-b | --buffer-size <buffer-size>] [-f | --frequency <frequency>] <peer-host> <peer-port>\n", argv0);
182 static void parse_args(int argc, char **argv)
185 int digit_optind = 0;
188 int this_option_optind = optind ? optind : 1;
189 int option_index = 0;
190 static struct option long_options[] = {
191 {"leader", 0, NULL, 0},
192 {"port", 1, NULL, 0},
193 {"buffer-size", 1, NULL, 0},
194 {"frequency", 1, NULL, 0},
198 c = getopt_long(argc, argv, "lp:b:f:",
199 long_options, &option_index);
205 printf("option %s", long_options[option_index].name);
207 printf(" with arg %s", optarg);
212 printf("option l\n");
216 printf("option l with value '%s'\n", optarg);
220 printf("option b with value '%s'\n", optarg);
224 printf("option f with value '%s'\n", optarg);
231 printf("?? getopt returned character code 0%o ??\n", c);
236 printf("non-option ARGV-elements: ");
237 while (optind < argc)
238 printf("%s ", argv[optind++]);
243 int main(int argc, char **argv)
247 struct sockaddr_in addr;
248 socklen_t addrlen = 0;
250 parse_args(argc, argv);
253 if (client_type == TYPE_LEADER) {
254 listenfd = tcp_listen_connections(DEFAULT_LEADER_LISTEN_PORT,
255 DEFAULT_SERVER_BACKLOG);
256 DIE(listenfd < 0, "tcp_listen_connections");
258 sockfd = accept(listenfd, (SSA *) &addr, &addrlen);
259 DIE(sockfd < 0, "accept");
261 connectfd = tcp_connect_to_server(DEFAULT_FOLLOWER_HOSTNAME,
262 DEFAULT_FOLLOWER_LISTEN_PORT);
263 DIE(connectfd < 0, "tcp_connect_to_server");
265 else if (client_type == TYPE_FOLLOWER) {
266 listenfd = tcp_listen_connections(DEFAULT_FOLLOWER_LISTEN_PORT,
267 DEFAULT_SERVER_BACKLOG);
268 DIE(listenfd < 0, "tcp_listen_connections");
270 connectfd = tcp_connect_to_server(DEFAULT_LEADER_HOSTNAME,
271 DEFAULT_LEADER_LISTEN_PORT);
272 DIE(connectfd < 0, "tcp_connect_to_server");
274 sockfd = accept(listenfd, (SSA *) &addr, &addrlen);
275 DIE(sockfd < 0, "accept");
277 else if (client_type == TYPE_OLD_LEADER) {
278 listenfd = tcp_listen_connections(DEFAULT_LEADER_LISTEN_PORT,
279 DEFAULT_SERVER_BACKLOG);
280 DIE(listenfd < 0, "tcp_listen_connections");
282 connectfd = tcp_connect_to_server(DEFAULT_FOLLOWER_HOSTNAME,
283 DEFAULT_FOLLOWER_LISTEN_PORT);
284 DIE(connectfd < 0, "tcp_connect_to_server");
286 sockfd = accept(listenfd, (SSA *) &addr, &addrlen);
287 DIE(sockfd < 0, "accept");
300 nbytes = receive_buffer(sockfd);
301 DIE(nbytes < 0, "receive_buffer");
306 sockfd = accept(listenfd, (SSA *) &addr, &addrlen);
307 DIE(sockfd < 0, "accept");
309 if (client_type == TYPE_FOLLOWER) {
310 connectfd = tcp_connect_to_server(DEFAULT_LEADER_HOSTNAME, DEFAULT_LEADER_LISTEN_PORT);
311 DIE(connectfd < 0, "tcp_connect_to_server");
313 if (client_type == TYPE_LEADER || client_type == TYPE_OLD_LEADER) {
314 connectfd = tcp_connect_to_server(DEFAULT_FOLLOWER_HOSTNAME, DEFAULT_FOLLOWER_LISTEN_PORT);
315 DIE(connectfd < 0, "tcp_connect_to_server");