Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
test: add udp4_echo_server helper
Browse files Browse the repository at this point in the history
  • Loading branch information
bnoordhuis committed Jan 13, 2012
1 parent a13584b commit dc3b80a
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
64 changes: 64 additions & 0 deletions test/echo-server.c
Expand Up @@ -34,6 +34,7 @@ static uv_loop_t* loop;
static int server_closed;
static stream_type serverType;
static uv_tcp_t tcpServer;
static uv_udp_t udpServer;
static uv_pipe_t pipeServer;
static uv_handle_t* server;

Expand Down Expand Up @@ -176,6 +177,34 @@ static void on_server_close(uv_handle_t* handle) {
}


static void on_send(uv_udp_send_t* req, int status);


static void on_recv(uv_udp_t* handle,
ssize_t nread,
uv_buf_t buf,
struct sockaddr* addr,
unsigned flags) {
uv_udp_send_t* req;
int r;

ASSERT(nread > 0);
ASSERT(addr->sa_family == AF_INET);

req = malloc(sizeof(*req));
ASSERT(req != NULL);

r = uv_udp_send(req, handle, &buf, 1, *(struct sockaddr_in*)addr, on_send);
ASSERT(r == 0);
}


static void on_send(uv_udp_send_t* req, int status) {
ASSERT(status == 0);
free(req);
}


static int tcp4_echo_start(int port) {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port);
int r;
Expand Down Expand Up @@ -242,6 +271,30 @@ static int tcp6_echo_start(int port) {
}


static int udp4_echo_start(int port) {
int r;

server = (uv_handle_t*)&udpServer;
serverType = UDP;

r = uv_udp_init(loop, &udpServer);
if (r) {
fprintf(stderr, "uv_udp_init: %s\n",
uv_strerror(uv_last_error(loop)));
return 1;
}

r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv);
if (r) {
fprintf(stderr, "uv_udp_recv_start: %s\n",
uv_strerror(uv_last_error(loop)));
return 1;
}

return 0;
}


static int pipe_echo_start(char* pipeName) {
int r;

Expand Down Expand Up @@ -304,3 +357,14 @@ HELPER_IMPL(pipe_echo_server) {
uv_run(loop);
return 0;
}


HELPER_IMPL(udp4_echo_server) {
loop = uv_default_loop();

if (udp4_echo_start(TEST_PORT))
return 1;

uv_run(loop);
return 0;
}
1 change: 1 addition & 0 deletions test/task.h
Expand Up @@ -42,6 +42,7 @@

typedef enum {
TCP = 0,
UDP,
PIPE
} stream_type;

Expand Down
1 change: 1 addition & 0 deletions test/test-list.h
Expand Up @@ -128,6 +128,7 @@ TEST_DECLARE (listen_no_simultaneous_accepts)
#endif
HELPER_DECLARE (tcp4_echo_server)
HELPER_DECLARE (tcp6_echo_server)
HELPER_DECLARE (udp4_echo_server)
HELPER_DECLARE (pipe_echo_server)


Expand Down

7 comments on commit dc3b80a

@DavidJFelix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this will be seen, but it's worth a question.

Isn't the process:

  • uv_udp_init
  • uv_udp_open / uv_udp_bind
  • uv_udp_recv_start / uv_udp_send

??

In this test the recv_start happens immediately after init without an open or bind. So then what's the point of open and bind?

@bnoordhuis
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DavidJFelix uv_udp_open() is for using a file descriptor you control, uv_udp_bind() for binding to a specific address and port. If you don't call uv_udp_bind() first, the operating system will do an implicit bind to the 'any address' with a random port. You can also do an explicit bind to a random port by specifying 0 as the port number, by the way.

@DavidJFelix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick response. This makes some sense, but I'm still not clear on why the bind is unneeded in this test. Doesn't the implied client need to know which port to send it's message to on the server? I'm not trying to imply that the test is incorrect in anyway, I'm just using it and the libuv tutorials as models and this was an inconsistency I noted between the two.

@bnoordhuis
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server's recv callback gets a struct sockaddr that contains the address and the port of the sender. If you look at line 197, you can see how the server basically bounces back the message to the sender.

@DavidJFelix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand how the server gets the client's port, but how does the client get the server's port:

  • Client sends message to server addr:port
  • Server receives message and client addr:port
  • Sever echos message to client addr:port

So in theory, an echo server should always bind (or at least check what it's port is so that clients can be told which port it is operating on). Is this a correct assumption on my part?

@bnoordhuis
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in theory, an echo server should always bind

If you want to be reachable at a well-known address/port (e.g. 0.0.0.0:53 for a DNS server), then yes: you must call uv_udp_bind().

@DavidJFelix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thanks for your help and writing this in the first place. I wouldn't be nearly as far into my project without it.

Please sign in to comment.