fwd.c: Check return code from `chdir'.
[fwd] / blast.c
CommitLineData
a8ceabf6 1#include <assert.h>
2#include <ctype.h>
3#include <errno.h>
73ac0c02 4#include <math.h>
a8ceabf6 5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include <sys/types.h>
10#include <sys/time.h>
11#include <unistd.h>
12#include <sys/socket.h>
13#include <netinet/in.h>
14#include <arpa/inet.h>
15#include <netdb.h>
16
17#include <mLib/alloc.h>
18#include <mLib/conn.h>
19#include <mLib/mdwopt.h>
20#include <mLib/quis.h>
21#include <mLib/report.h>
22#include <mLib/sel.h>
23#include <mLib/tv.h>
24
25typedef struct blast {
26 conn c;
27 sel_timer t;
28} blast;
29
73ac0c02 30#define sin saddrin
a8ceabf6 31static struct sockaddr_in sin;
32static sel_state sel;
33static struct timeval ctv = { 0, 500000 };
34static sel_timer sec;
35static unsigned count = 0;
36
37static void timers(void);
38
39static void stats(struct timeval *tv, void *p)
40{
41 static char baton[5] = "/-\\|";
42 static char *bt = baton;
43 struct timeval ttv;
44 printf("\r%c %u connections/second", *bt++, count);
45 if (!*bt)
46 bt = baton;
47 fflush(stdout);
48 count = 0;
49 TV_ADDL(&ttv, tv, 1, 0);
50 sel_addtimer(&sel, &sec, &ttv, stats, p);
51}
52
53static void newconn(blast *b);
54
55static void retry(struct timeval *tv, void *p)
56{
57 blast *b = p;
58 newconn(b);
59}
60
61static void backoff(blast *b)
62{
63 struct timeval tv;
64 unsigned r = rand();
65 double q = RAND_MAX / 5;
66 gettimeofday(&tv, 0);
67 TV_ADDL(&tv, &tv, r / q, (r % (unsigned)q) * (MILLION / q));
68 sel_addtimer(&sel, &b->t, &tv, retry, b);
69}
70
71static void connected(int fd, void *p)
72{
73 blast *b = p;
74 sel_rmtimer(&b->t);
75 if (fd == -1)
76 backoff(b);
77 else {
78 count++;
79 close(fd);
a8ceabf6 80 }
0d3d364b 81 newconn(b);
a8ceabf6 82}
83
84static void timeout(struct timeval *tv, void *p)
85{
86 blast *b = p;
87 conn_kill(&b->c);
88 newconn(b);
89}
90
91static void timers(void)
92{
93 struct tab { void (*func)(struct timeval *tv, void *p); const char *name; }
94 tab[] = { { retry, "retry" }, {timeout, "timeout"}, { stats, "stats" }, { 0,
95 0 }};
96 sel_timer *t = sel.timers;
97 while (t) {
98 struct tab *q; for (q = tab; q->func != t->func; q++) ;
73ac0c02 99/* assert(t->prev->next == t); */
100 printf("%lu.%06lu %p %s\n", t->tv.tv_sec, t->tv.tv_usec, t->p, q->name);
a8ceabf6 101 assert(t != t->next);
102 t = t->next;
103 }
104 puts("");
105}
206212ca 106
a8ceabf6 107static void newconn(blast *b)
108{
109 int fd = socket(PF_INET, SOCK_STREAM, 0);
110 struct timeval tv;
111 if (fd < 0)
112 goto fail;
113 gettimeofday(&tv, 0);
114 TV_ADD(&tv, &tv, &ctv);
e35ff2b8 115 sel_addtimer(&sel, &b->t, &tv, timeout, b);
0d3d364b 116 if (conn_init(&b->c, &sel, fd, (struct sockaddr *)&sin, sizeof(sin),
117 connected, b))
118 goto fail;
a8ceabf6 119 return;
120
121fail:
e35ff2b8 122 sel_rmtimer(&b->t);
a8ceabf6 123 backoff(b);
124}
125
126int main(int argc, char *argv[])
127{
128 blast *b;
129 size_t n = 256;
130
131 ego(argv[0]);
132
133 for (;;) {
134 int i = getopt(argc, argv, "t:n:");
135 if (i < 0)
136 break;
137 switch (i) {
138 case 't': {
139 double t = strtod(optarg, 0);
140 double s = modf(t, &t);
141 ctv.tv_sec = t;
142 ctv.tv_usec = s * MILLION;
143 } break;
144 case 'n':
145 n = atoi(optarg);
146 break;
147 default:
148 exit(1);
149 }
150 }
151
152 argv += optind;
153 argc -= optind;
154 if (argc != 2) {
9515272f 155 pquis(stderr, "Usage: $ [-t TIME] [-n COUNT] HOST PORT\n");
a8ceabf6 156 exit(1);
157 }
158
159 sel_init(&sel);
160 sin.sin_family = AF_INET;
161
162 {
163 struct hostent *h = gethostbyname(argv[0]);
164 if (!h)
165 die(1, "bad hostname `%s'", argv[0]);
166 memcpy(&sin.sin_addr, h->h_addr, sizeof(struct in_addr));
167 }
168
169 if (isdigit((unsigned char)argv[1][0]))
170 sin.sin_port = htons(atoi(argv[1]));
171 else {
172 struct servent *s = getservbyname(argv[1], "tcp");
173 if (!s)
174 die(1, "bad service name `%s'", argv[1]);
175 sin.sin_port = s->s_port;
176 }
177
178 b = xmalloc(n * sizeof(blast));
179
180 {
181 int i;
182 for (i = 0; i < n; i++)
183 newconn(&b[i]);
184 }
185
186 {
187 struct timeval tv;
188 gettimeofday(&tv, 0);
189 tv.tv_sec++;
190 sel_addtimer(&sel, &sec, &tv, stats, 0);
191 }
192
193 for (;;) {
194 sel_select(&sel);
195 }
196}