PageRenderTime 35ms CodeModel.GetById 20ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/test/test-udp-send-and-recv.c

http://github.com/joyent/libuv
C | 209 lines | 126 code | 54 blank | 29 comment | 42 complexity | e1762166dd4a43d3d32c9720de107aec MD5 | raw file
  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>
 28
 29#define CHECK_HANDLE(handle) \
 30  ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
 31
 32static uv_udp_t server;
 33static uv_udp_t client;
 34
 35static int cl_send_cb_called;
 36static int cl_recv_cb_called;
 37
 38static int sv_send_cb_called;
 39static int sv_recv_cb_called;
 40
 41static int close_cb_called;
 42
 43
 44static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
 45  static char slab[65536];
 46
 47  CHECK_HANDLE(handle);
 48  ASSERT(suggested_size <= sizeof slab);
 49
 50  return uv_buf_init(slab, sizeof slab);
 51}
 52
 53
 54static void close_cb(uv_handle_t* handle) {
 55  CHECK_HANDLE(handle);
 56  close_cb_called++;
 57}
 58
 59
 60static void cl_recv_cb(uv_udp_t* handle,
 61                       ssize_t nread,
 62                       uv_buf_t buf,
 63                       struct sockaddr* addr,
 64                       unsigned flags) {
 65  CHECK_HANDLE(handle);
 66  ASSERT(flags == 0);
 67
 68  if (nread < 0) {
 69    ASSERT(0 && "unexpected error");
 70  }
 71
 72  if (nread == 0) {
 73    /* Returning unused buffer */
 74    /* Don't count towards cl_recv_cb_called */
 75    ASSERT(addr == NULL);
 76    return;
 77  }
 78
 79  ASSERT(addr != NULL);
 80  ASSERT(nread == 4);
 81  ASSERT(!memcmp("PONG", buf.base, nread));
 82
 83  cl_recv_cb_called++;
 84
 85  uv_close((uv_handle_t*) handle, close_cb);
 86}
 87
 88
 89static void cl_send_cb(uv_udp_send_t* req, int status) {
 90  int r;
 91
 92  ASSERT(req != NULL);
 93  ASSERT(status == 0);
 94  CHECK_HANDLE(req->handle);
 95
 96  r = uv_udp_recv_start(req->handle, alloc_cb, cl_recv_cb);
 97  ASSERT(r == 0);
 98
 99  cl_send_cb_called++;
100}
101
102
103static void sv_send_cb(uv_udp_send_t* req, int status) {
104  ASSERT(req != NULL);
105  ASSERT(status == 0);
106  CHECK_HANDLE(req->handle);
107
108  uv_close((uv_handle_t*) req->handle, close_cb);
109  free(req);
110
111  sv_send_cb_called++;
112}
113
114
115static void sv_recv_cb(uv_udp_t* handle,
116                       ssize_t nread,
117                       uv_buf_t buf,
118                       struct sockaddr* addr,
119                       unsigned flags) {
120  uv_udp_send_t* req;
121  int r;
122
123  if (nread < 0) {
124    ASSERT(0 && "unexpected error");
125  }
126
127  if (nread == 0) {
128    /* Returning unused buffer */
129    /* Don't count towards sv_recv_cb_called */
130    ASSERT(addr == NULL);
131    return;
132  }
133
134  CHECK_HANDLE(handle);
135  ASSERT(flags == 0);
136
137  ASSERT(addr != NULL);
138  ASSERT(nread == 4);
139  ASSERT(!memcmp("PING", buf.base, nread));
140
141  /* FIXME? `uv_udp_recv_stop` does what it says: recv_cb is not called
142    * anymore. That's problematic because the read buffer won't be returned
143    * either... Not sure I like that but it's consistent with `uv_read_stop`.
144    */
145  r = uv_udp_recv_stop(handle);
146  ASSERT(r == 0);
147
148  req = malloc(sizeof *req);
149  ASSERT(req != NULL);
150
151  buf = uv_buf_init("PONG", 4);
152
153  r = uv_udp_send(req,
154                  handle,
155                  &buf,
156                  1,
157                  *(struct sockaddr_in*)addr,
158                  sv_send_cb);
159  ASSERT(r == 0);
160
161  sv_recv_cb_called++;
162}
163
164
165TEST_IMPL(udp_send_and_recv) {
166  struct sockaddr_in addr;
167  uv_udp_send_t req;
168  uv_buf_t buf;
169  int r;
170
171  addr = uv_ip4_addr("0.0.0.0", TEST_PORT);
172
173  r = uv_udp_init(uv_default_loop(), &server);
174  ASSERT(r == 0);
175
176  r = uv_udp_bind(&server, addr, 0);
177  ASSERT(r == 0);
178
179  r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
180  ASSERT(r == 0);
181
182  addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
183
184  r = uv_udp_init(uv_default_loop(), &client);
185  ASSERT(r == 0);
186
187  /* client sends "PING", expects "PONG" */
188  buf = uv_buf_init("PING", 4);
189
190  r = uv_udp_send(&req, &client, &buf, 1, addr, cl_send_cb);
191  ASSERT(r == 0);
192
193  ASSERT(close_cb_called == 0);
194  ASSERT(cl_send_cb_called == 0);
195  ASSERT(cl_recv_cb_called == 0);
196  ASSERT(sv_send_cb_called == 0);
197  ASSERT(sv_recv_cb_called == 0);
198
199  uv_run(uv_default_loop());
200
201  ASSERT(cl_send_cb_called == 1);
202  ASSERT(cl_recv_cb_called == 1);
203  ASSERT(sv_send_cb_called == 1);
204  ASSERT(sv_recv_cb_called == 1);
205  ASSERT(close_cb_called == 2);
206
207  MAKE_VALGRIND_HAPPY();
208  return 0;
209}