libuv-svace-build

Форк
0
/
test-ping-pong.c 
439 строк · 11.1 Кб
1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
 *
3
 * Permission is hereby granted, free of charge, to any person obtaining a copy
4
 * of this software and associated documentation files (the "Software"), to
5
 * deal in the Software without restriction, including without limitation the
6
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
 * sell copies of the Software, and to permit persons to whom the Software is
8
 * furnished to do so, subject to the following conditions:
9
 *
10
 * The above copyright notice and this permission notice shall be included in
11
 * all copies or substantial portions of the Software.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
 * IN THE SOFTWARE.
20
 */
21

22
#include "uv.h"
23
#include "task.h"
24

25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h> /* strlen */
28

29
static int completed_pingers = 0;
30

31
#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__MVS__)
32
#define NUM_PINGS 100 /* fewer pings to avoid timeout */
33
#else
34
#define NUM_PINGS 1000
35
#endif
36

37
static char PING[] = "PING\n";
38
static char PONG[] = "PONG\n";
39
static int pinger_on_connect_count;
40

41

42
typedef struct {
43
  int vectored_writes;
44
  unsigned pongs;
45
  unsigned state;
46
  union {
47
    uv_tcp_t tcp;
48
    uv_pipe_t pipe;
49
  } stream;
50
  uv_connect_t connect_req;
51
  char* pong;
52
} pinger_t;
53

54

55
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
56
  buf->base = malloc(size);
57
  buf->len = size;
58
}
59

60

61
static void ponger_on_close(uv_handle_t* handle) {
62
  if (handle->data)
63
    free(handle->data);
64
  else
65
    free(handle);
66
}
67

68

69
static void pinger_on_close(uv_handle_t* handle) {
70
  pinger_t* pinger = (pinger_t*) handle->data;
71

72
  ASSERT_EQ(NUM_PINGS, pinger->pongs);
73

74
  if (handle == (uv_handle_t*) &pinger->stream.tcp) {
75
    free(pinger); /* also frees handle */
76
  } else {
77
    uv_close((uv_handle_t*) &pinger->stream.tcp, ponger_on_close);
78
    free(handle);
79
  }
80

81
  completed_pingers++;
82
}
83

84

85
static void pinger_after_write(uv_write_t* req, int status) {
86
  ASSERT_OK(status);
87
  free(req->data);
88
  free(req);
89
}
90

91

92
static void pinger_write_ping(pinger_t* pinger) {
93
  uv_stream_t* stream;
94
  uv_write_t* req;
95
  uv_buf_t bufs[sizeof PING - 1];
96
  int i, nbufs;
97

98
  stream = (uv_stream_t*) &pinger->stream.tcp;
99

100
  if (!pinger->vectored_writes) {
101
    /* Write a single buffer. */
102
    nbufs = 1;
103
    bufs[0] = uv_buf_init(PING, sizeof PING - 1);
104
  } else {
105
    /* Write multiple buffers, each with one byte in them. */
106
    nbufs = sizeof PING - 1;
107
    for (i = 0; i < nbufs; i++) {
108
      bufs[i] = uv_buf_init(&PING[i], 1);
109
    }
110
  }
111

112
  req = malloc(sizeof(*req));
113
  ASSERT_NOT_NULL(req);
114
  req->data = NULL;
115
  ASSERT_OK(uv_write(req, stream, bufs, nbufs, pinger_after_write));
116

117
  puts("PING");
118
}
119

120

121
static void pinger_read_cb(uv_stream_t* stream,
122
                           ssize_t nread,
123
                           const uv_buf_t* buf) {
124
  ssize_t i;
125
  pinger_t* pinger;
126

127
  pinger = (pinger_t*) stream->data;
128

129
  if (nread < 0) {
130
    ASSERT_EQ(nread, UV_EOF);
131

132
    puts("got EOF");
133
    free(buf->base);
134

135
    uv_close((uv_handle_t*) stream, pinger_on_close);
136

137
    return;
138
  }
139

140
  /* Now we count the pongs */
141
  for (i = 0; i < nread; i++) {
142
    ASSERT_EQ(buf->base[i], pinger->pong[pinger->state]);
143
    pinger->state = (pinger->state + 1) % strlen(pinger->pong);
144

145
    if (pinger->state != 0)
146
      continue;
147

148
    printf("PONG %d\n", pinger->pongs);
149
    pinger->pongs++;
150

151
    if (pinger->pongs < NUM_PINGS) {
152
      pinger_write_ping(pinger);
153
    } else {
154
      uv_close((uv_handle_t*) stream, pinger_on_close);
155
      break;
156
    }
157
  }
158

159
  free(buf->base);
160
}
161

162

163
static void ponger_read_cb(uv_stream_t* stream,
164
                           ssize_t nread,
165
                           const uv_buf_t* buf) {
166
  uv_buf_t writebuf;
167
  uv_write_t* req;
168
  int i;
169

170
  if (nread < 0) {
171
    ASSERT_EQ(nread, UV_EOF);
172

173
    puts("got EOF");
174
    free(buf->base);
175

176
    uv_close((uv_handle_t*) stream, ponger_on_close);
177

178
    return;
179
  }
180

181
  /* Echo back */
182
  for (i = 0; i < nread; i++) {
183
    if (buf->base[i] == 'I')
184
      buf->base[i] = 'O';
185
  }
186

187
  writebuf = uv_buf_init(buf->base, nread);
188
  req = malloc(sizeof(*req));
189
  ASSERT_NOT_NULL(req);
190
  req->data = buf->base;
191
  ASSERT_OK(uv_write(req, stream, &writebuf, 1, pinger_after_write));
192
}
193

194

195
static void pinger_on_connect(uv_connect_t* req, int status) {
196
  pinger_t* pinger = (pinger_t*) req->handle->data;
197

198
  pinger_on_connect_count++;
199

200
  ASSERT_OK(status);
201

202
  ASSERT_EQ(1, uv_is_readable(req->handle));
203
  ASSERT_EQ(1, uv_is_writable(req->handle));
204
  ASSERT_OK(uv_is_closing((uv_handle_t *) req->handle));
205

206
  pinger_write_ping(pinger);
207

208
  ASSERT_OK(uv_read_start((uv_stream_t*) req->handle,
209
                          alloc_cb,
210
                          pinger_read_cb));
211
}
212

213

214
/* same ping-pong test, but using IPv6 connection */
215
static void tcp_pinger_v6_new(int vectored_writes) {
216
  int r;
217
  struct sockaddr_in6 server_addr;
218
  pinger_t* pinger;
219

220

221
  ASSERT_OK(uv_ip6_addr("::1", TEST_PORT, &server_addr));
222
  pinger = malloc(sizeof(*pinger));
223
  ASSERT_NOT_NULL(pinger);
224
  pinger->vectored_writes = vectored_writes;
225
  pinger->state = 0;
226
  pinger->pongs = 0;
227
  pinger->pong = PING;
228

229
  /* Try to connect to the server and do NUM_PINGS ping-pongs. */
230
  r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
231
  pinger->stream.tcp.data = pinger;
232
  ASSERT_OK(r);
233

234
  /* We are never doing multiple reads/connects at a time anyway, so these
235
   * handles can be pre-initialized. */
236
  r = uv_tcp_connect(&pinger->connect_req,
237
                     &pinger->stream.tcp,
238
                     (const struct sockaddr*) &server_addr,
239
                     pinger_on_connect);
240
  ASSERT_OK(r);
241

242
  /* Synchronous connect callbacks are not allowed. */
243
  ASSERT_OK(pinger_on_connect_count);
244
}
245

246

247
static void tcp_pinger_new(int vectored_writes) {
248
  int r;
249
  struct sockaddr_in server_addr;
250
  pinger_t* pinger;
251

252
  ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
253
  pinger = malloc(sizeof(*pinger));
254
  ASSERT_NOT_NULL(pinger);
255
  pinger->vectored_writes = vectored_writes;
256
  pinger->state = 0;
257
  pinger->pongs = 0;
258
  pinger->pong = PING;
259

260
  /* Try to connect to the server and do NUM_PINGS ping-pongs. */
261
  r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
262
  pinger->stream.tcp.data = pinger;
263
  ASSERT_OK(r);
264

265
  /* We are never doing multiple reads/connects at a time anyway, so these
266
   * handles can be pre-initialized. */
267
  r = uv_tcp_connect(&pinger->connect_req,
268
                     &pinger->stream.tcp,
269
                     (const struct sockaddr*) &server_addr,
270
                     pinger_on_connect);
271
  ASSERT_OK(r);
272

273
  /* Synchronous connect callbacks are not allowed. */
274
  ASSERT_OK(pinger_on_connect_count);
275
}
276

277

278
static void pipe_pinger_new(int vectored_writes) {
279
  int r;
280
  pinger_t* pinger;
281

282
  pinger = malloc(sizeof(*pinger));
283
  ASSERT_NOT_NULL(pinger);
284
  pinger->vectored_writes = vectored_writes;
285
  pinger->state = 0;
286
  pinger->pongs = 0;
287
  pinger->pong = PING;
288

289
  /* Try to connect to the server and do NUM_PINGS ping-pongs. */
290
  r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);
291
  pinger->stream.pipe.data = pinger;
292
  ASSERT_OK(r);
293

294
  /* We are never doing multiple reads/connects at a time anyway, so these
295
   * handles can be pre-initialized. */
296
  uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME,
297
      pinger_on_connect);
298

299
  /* Synchronous connect callbacks are not allowed. */
300
  ASSERT_OK(pinger_on_connect_count);
301
}
302

303

304
static void socketpair_pinger_new(int vectored_writes) {
305
  pinger_t* pinger;
306
  uv_os_sock_t fds[2];
307
  uv_tcp_t* ponger;
308

309
  pinger = malloc(sizeof(*pinger));
310
  ASSERT_NOT_NULL(pinger);
311
  pinger->vectored_writes = vectored_writes;
312
  pinger->state = 0;
313
  pinger->pongs = 0;
314
  pinger->pong = PONG;
315

316
  /* Try to make a socketpair and do NUM_PINGS ping-pongs. */
317
  (void)uv_default_loop(); /* ensure WSAStartup has been performed */
318
  ASSERT_OK(uv_socketpair(SOCK_STREAM, 0, fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE));
319
#ifndef _WIN32
320
  /* On Windows, this is actually a UV_TCP, but libuv doesn't detect that. */
321
  ASSERT_EQ(uv_guess_handle((uv_file) fds[0]), UV_NAMED_PIPE);
322
  ASSERT_EQ(uv_guess_handle((uv_file) fds[1]), UV_NAMED_PIPE);
323
#endif
324

325
  ASSERT_OK(uv_tcp_init(uv_default_loop(), &pinger->stream.tcp));
326
  pinger->stream.pipe.data = pinger;
327
  ASSERT_OK(uv_tcp_open(&pinger->stream.tcp, fds[1]));
328

329
  ponger = malloc(sizeof(*ponger));
330
  ASSERT_NOT_NULL(ponger);
331
  ponger->data = NULL;
332
  ASSERT_OK(uv_tcp_init(uv_default_loop(), ponger));
333
  ASSERT_OK(uv_tcp_open(ponger, fds[0]));
334

335
  pinger_write_ping(pinger);
336

337
  ASSERT_OK(uv_read_start((uv_stream_t*) &pinger->stream.tcp,
338
                          alloc_cb,
339
                          pinger_read_cb));
340
  ASSERT_OK(uv_read_start((uv_stream_t*) ponger,
341
                          alloc_cb,
342
                          ponger_read_cb));
343
}
344

345

346
static void pipe2_pinger_new(int vectored_writes) {
347
  uv_file fds[2];
348
  pinger_t* pinger;
349
  uv_pipe_t* ponger;
350

351
  /* Try to make a pipe and do NUM_PINGS pings. */
352
  ASSERT_OK(uv_pipe(fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE));
353
  ASSERT_EQ(uv_guess_handle(fds[0]), UV_NAMED_PIPE);
354
  ASSERT_EQ(uv_guess_handle(fds[1]), UV_NAMED_PIPE);
355

356
  ponger = malloc(sizeof(*ponger));
357
  ASSERT_NOT_NULL(ponger);
358
  ASSERT_OK(uv_pipe_init(uv_default_loop(), ponger, 0));
359
  ASSERT_OK(uv_pipe_open(ponger, fds[0]));
360

361
  pinger = malloc(sizeof(*pinger));
362
  ASSERT_NOT_NULL(pinger);
363
  pinger->vectored_writes = vectored_writes;
364
  pinger->state = 0;
365
  pinger->pongs = 0;
366
  pinger->pong = PING;
367
  ASSERT_OK(uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0));
368
  ASSERT_OK(uv_pipe_open(&pinger->stream.pipe, fds[1]));
369
  pinger->stream.pipe.data = pinger; /* record for close_cb */
370
  ponger->data = pinger; /* record for read_cb */
371

372
  pinger_write_ping(pinger);
373

374
  ASSERT_OK(uv_read_start((uv_stream_t*) ponger, alloc_cb, pinger_read_cb));
375
}
376

377
static int run_ping_pong_test(void) {
378
  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
379
  ASSERT_EQ(1, completed_pingers);
380

381
  MAKE_VALGRIND_HAPPY(uv_default_loop());
382
  return 0;
383
}
384

385

386
TEST_IMPL(tcp_ping_pong) {
387
  tcp_pinger_new(0);
388
  run_ping_pong_test();
389

390
  completed_pingers = 0;
391
  socketpair_pinger_new(0);
392
  return run_ping_pong_test();
393
}
394

395

396
TEST_IMPL(tcp_ping_pong_vec) {
397
  tcp_pinger_new(1);
398
  run_ping_pong_test();
399

400
  completed_pingers = 0;
401
  socketpair_pinger_new(1);
402
  return run_ping_pong_test();
403
}
404

405

406
TEST_IMPL(tcp6_ping_pong) {
407
  if (!can_ipv6())
408
    RETURN_SKIP("IPv6 not supported");
409
  tcp_pinger_v6_new(0);
410
  return run_ping_pong_test();
411
}
412

413

414
TEST_IMPL(tcp6_ping_pong_vec) {
415
  if (!can_ipv6())
416
    RETURN_SKIP("IPv6 not supported");
417
  tcp_pinger_v6_new(1);
418
  return run_ping_pong_test();
419
}
420

421

422
TEST_IMPL(pipe_ping_pong) {
423
  pipe_pinger_new(0);
424
  run_ping_pong_test();
425

426
  completed_pingers = 0;
427
  pipe2_pinger_new(0);
428
  return run_ping_pong_test();
429
}
430

431

432
TEST_IMPL(pipe_ping_pong_vec) {
433
  pipe_pinger_new(1);
434
  run_ping_pong_test();
435

436
  completed_pingers = 0;
437
  pipe2_pinger_new(1);
438
  return run_ping_pong_test();
439
}
440

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.