~james-page/ubuntu/precise/nodejs/0.6.x-merge

« back to all changes in this revision

Viewing changes to deps/uv/test/dns-server.c

  • Committer: James Page
  • Date: 2012-03-30 12:09:16 UTC
  • mfrom: (7.1.23 sid)
  • Revision ID: james.page@canonical.com-20120330120916-40hfu9o00qr5t87b
* Merge from Debian unstable:
  - New upstream release (LP: #892034).
  - This package is x86/arm only. Update control to match
  - d/patches/2009_increase_test_timeout.patch: Increased default test
    timeout from 60 to 120 seconds to support reliable execution of all
    tests on armhf/armel architectures.
  - d/patches/2005_expected_failing_tests.patch: 
    - Allow racey tests to fail: test-cluster-kill-workers,
      test-child-process-fork2 
    - Allow test-fs-watch to fail as LP buildd's don't support
      inotify.
    - Revert all other Ubuntu changes as no longer required.
* Update Standards-Version to 3.9.3.
* Patch wscript to enable build on mipsel arch, libv8 being available.
  Upstream does not support that arch, failure expected.
* test-cluster-kill-workers is expected to fail on armhf,
  Bug#660802 will be closed when test pass.
* test-buffer is expected to fail on armel,
  Bug#660800 will be closed when test pass.
* Add epoch to dependency on libev >= 1:4.11. Closes: bug#658441.
* Remove tools/doc because node-doc-generator has no license for now.
* Add copyright for doc/sh* files (shjs).
* source.lintian-overrides : source-contains-waf-binary tools/node-waf
  it is simply not the case here.
* test-stream-pipe-multi expected to timeout sometimes on busy builds. 
* New upstream release.
* Remove upstream patches.
* test-dgram-pingpong expected to timeout, the test itself is buggy.
* test-buffer expected to fail on armel, allow building package to make
  it easier to find the cause of the failure.
  Closes: bug#639636.
* Expect tests dgram-multicast and broadcast to fail.
  debian/patches/2005_expected_failing_tests.patch
* Drop dpkg-source local-options: Defaults since dpkg-source 1.16.1.
* New upstream release.
* Depend on libev-dev 4.11, see bug#657080.
* Bump dependency on openssl to 1.0.0g.
* Remove useless uv_loop_refcount from libuv,
  refreshed 2009_fix_shared_ev.patch.
* Apply to upstream patches landed after 0.6.10 release,
  to fix debugger repl and http client.
* New upstream release. Closes:bug#650661
* Repackage to remove non-dfsg font files ./deps/npm/html/*/*.ttf
* Remove unneeded bundled dependencies: lighter tarball,
  debian/copyright is easier to maintain.
* Drop unneeded build-dependency on scons.
* Depend on zlib1g, libc-ares, libev.
  Patches done to support building with those shared libs.
* Fix DEB_UPSTREAM_URL in debian/rules, and debian/watch.
* nodejs.pc file for pkgconfig is no more available.
* Build-depend on procps package, a test is using /bin/ps.
* Refreshed debian/patches/2005_expected_failing_tests.patch,
  only for tests that need networking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
 
 
28
 
 
29
typedef struct {
 
30
  uv_write_t req;
 
31
  uv_buf_t buf;
 
32
} write_req_t;
 
33
 
 
34
 
 
35
/* used to track multiple DNS requests received */
 
36
typedef struct {
 
37
  char* prevbuf_ptr;
 
38
  int prevbuf_pos;
 
39
  int prevbuf_rem;
 
40
} dnsstate;
 
41
 
 
42
 
 
43
/* modify handle to append dnsstate */
 
44
typedef struct {
 
45
  uv_tcp_t handle;
 
46
  dnsstate state;
 
47
} dnshandle;
 
48
 
 
49
 
 
50
static uv_loop_t* loop;
 
51
 
 
52
 
 
53
static int server_closed;
 
54
static uv_tcp_t server;
 
55
 
 
56
 
 
57
static void after_write(uv_write_t* req, int status);
 
58
static void after_read(uv_stream_t*, ssize_t nread, uv_buf_t buf);
 
59
static void on_close(uv_handle_t* peer);
 
60
static void on_server_close(uv_handle_t* handle);
 
61
static void on_connection(uv_stream_t*, int status);
 
62
 
 
63
#define WRITE_BUF_LEN   (64*1024)
 
64
#define DNSREC_LEN      (4)
 
65
 
 
66
#define LEN_OFFSET 0
 
67
#define QUERYID_OFFSET 2
 
68
unsigned char DNSRsp[] = {0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0 };
 
69
unsigned char qrecord[] = {5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1};
 
70
unsigned char arecord[] = {0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1 };
 
71
 
 
72
 
 
73
static void after_write(uv_write_t* req, int status) {
 
74
  write_req_t* wr;
 
75
 
 
76
  if (status) {
 
77
    uv_err_t err = uv_last_error(loop);
 
78
    fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));
 
79
    ASSERT(0);
 
80
  }
 
81
 
 
82
  wr = (write_req_t*) req;
 
83
 
 
84
  /* Free the read/write buffer and the request */
 
85
  free(wr->buf.base);
 
86
  free(wr);
 
87
}
 
88
 
 
89
 
 
90
static void after_shutdown(uv_shutdown_t* req, int status) {
 
91
  uv_close((uv_handle_t*) req->handle, on_close);
 
92
  free(req);
 
93
}
 
94
 
 
95
 
 
96
static void addrsp(write_req_t* wr, char* hdr) {
 
97
  char * dnsrsp;
 
98
  short int rsplen;
 
99
  short int* reclen;
 
100
 
 
101
  rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord);
 
102
 
 
103
  ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN);
 
104
 
 
105
  dnsrsp = wr->buf.base + wr->buf.len;
 
106
 
 
107
  /* copy stock response */
 
108
  memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp));
 
109
  memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord));
 
110
  memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord));
 
111
 
 
112
  /* overwrite with network order length and id from request header */
 
113
  reclen = (short int*)dnsrsp;
 
114
  *reclen = htons(rsplen-2);
 
115
  dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET];
 
116
  dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1];
 
117
 
 
118
  wr->buf.len += rsplen;
 
119
}
 
120
 
 
121
static void process_req(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
 
122
  write_req_t* wr;
 
123
  dnshandle* dns = (dnshandle*)handle;
 
124
  char hdrbuf[DNSREC_LEN];
 
125
  int hdrbuf_remaining = DNSREC_LEN;
 
126
  int rec_remaining = 0;
 
127
  int readbuf_remaining;
 
128
  char* dnsreq;
 
129
  char* hdrstart;
 
130
  int usingprev = 0;
 
131
 
 
132
  wr = (write_req_t*) malloc(sizeof *wr);
 
133
  wr->buf.base = (char*)malloc(WRITE_BUF_LEN);
 
134
  wr->buf.len = 0;
 
135
 
 
136
  if (dns->state.prevbuf_ptr != NULL) {
 
137
    dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos;
 
138
    readbuf_remaining = dns->state.prevbuf_rem;
 
139
    usingprev = 1;
 
140
  } else {
 
141
    dnsreq = buf.base;
 
142
    readbuf_remaining = nread;
 
143
  }
 
144
  hdrstart = dnsreq;
 
145
 
 
146
  while (dnsreq != NULL) {
 
147
    /* something to process */
 
148
    while (readbuf_remaining > 0) {
 
149
      /* something to process in current buffer */
 
150
      if (hdrbuf_remaining > 0) {
 
151
        /* process len and id */
 
152
        if (readbuf_remaining < hdrbuf_remaining) {
 
153
          /* too little to get request header. save for next buffer */
 
154
          memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], dnsreq, readbuf_remaining);
 
155
          hdrbuf_remaining = DNSREC_LEN - readbuf_remaining;
 
156
          break;
 
157
        } else {
 
158
          short int reclen_n;
 
159
          /* save header */
 
160
          memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], dnsreq, hdrbuf_remaining);
 
161
          dnsreq += hdrbuf_remaining;
 
162
          readbuf_remaining -= hdrbuf_remaining;
 
163
          hdrbuf_remaining = 0;
 
164
 
 
165
          /* get record length */
 
166
          reclen_n = *((short int*)hdrbuf);
 
167
          rec_remaining = ntohs(reclen_n) - (DNSREC_LEN - 2);
 
168
        }
 
169
      }
 
170
 
 
171
      if (rec_remaining <= readbuf_remaining) {
 
172
        /* prepare reply */
 
173
        addrsp(wr, hdrbuf);
 
174
 
 
175
        /* move to next record */
 
176
        dnsreq += rec_remaining;
 
177
        hdrstart = dnsreq;
 
178
        readbuf_remaining -= rec_remaining;
 
179
        rec_remaining = 0;
 
180
        hdrbuf_remaining = DNSREC_LEN;
 
181
      } else {
 
182
        /* otherwise this buffer is done. */
 
183
        rec_remaining -= readbuf_remaining;
 
184
        break;
 
185
      }
 
186
    }
 
187
 
 
188
    /* if we had to use bytes from prev buffer, start processing the current one */
 
189
    if (usingprev == 1) {
 
190
      /* free previous buffer */
 
191
      free(dns->state.prevbuf_ptr);
 
192
      dnsreq = buf.base;
 
193
      readbuf_remaining = nread;
 
194
      usingprev = 0;
 
195
    } else {
 
196
      dnsreq = NULL;
 
197
    }
 
198
  }
 
199
 
 
200
  /* send write buffer */
 
201
  if (wr->buf.len > 0) {
 
202
    if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) {
 
203
      FATAL("uv_write failed");
 
204
    }
 
205
  }
 
206
 
 
207
  if (readbuf_remaining > 0) {
 
208
    /* save start of record position, so we can continue on next read */
 
209
    dns->state.prevbuf_ptr = buf.base;
 
210
    dns->state.prevbuf_pos = hdrstart - buf.base;
 
211
    dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos;
 
212
  } else {
 
213
    /* nothing left in this buffer */
 
214
    dns->state.prevbuf_ptr = NULL;
 
215
    dns->state.prevbuf_pos = 0;
 
216
    dns->state.prevbuf_rem = 0;
 
217
    free(buf.base);
 
218
  }
 
219
}
 
220
 
 
221
static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
 
222
  uv_shutdown_t* req;
 
223
 
 
224
  if (nread < 0) {
 
225
    /* Error or EOF */
 
226
    ASSERT (uv_last_error(loop).code == UV_EOF);
 
227
 
 
228
    if (buf.base) {
 
229
      free(buf.base);
 
230
    }
 
231
 
 
232
    req = malloc(sizeof *req);
 
233
    uv_shutdown(req, handle, after_shutdown);
 
234
 
 
235
    return;
 
236
  }
 
237
 
 
238
  if (nread == 0) {
 
239
    /* Everything OK, but nothing read. */
 
240
    free(buf.base);
 
241
    return;
 
242
  }
 
243
  /* process requests and send responses */
 
244
  process_req(handle, nread, buf);
 
245
}
 
246
 
 
247
 
 
248
static void on_close(uv_handle_t* peer) {
 
249
  free(peer);
 
250
}
 
251
 
 
252
 
 
253
static uv_buf_t buf_alloc(uv_handle_t* handle, size_t suggested_size) {
 
254
  uv_buf_t buf;
 
255
  buf.base = (char*) malloc(suggested_size);
 
256
  buf.len = suggested_size;
 
257
  return buf;
 
258
}
 
259
 
 
260
 
 
261
static void on_connection(uv_stream_t* server, int status) {
 
262
  dnshandle* handle;
 
263
  int r;
 
264
 
 
265
  ASSERT(status == 0);
 
266
 
 
267
  handle = (dnshandle*) malloc(sizeof *handle);
 
268
  ASSERT(handle != NULL);
 
269
 
 
270
  /* initialize read buffer state */
 
271
  handle->state.prevbuf_ptr = 0;
 
272
  handle->state.prevbuf_pos = 0;
 
273
  handle->state.prevbuf_rem = 0;
 
274
 
 
275
  r = uv_tcp_init(loop, (uv_tcp_t*)handle);
 
276
  ASSERT(r == 0);
 
277
 
 
278
  r = uv_accept(server, (uv_stream_t*)handle);
 
279
  ASSERT(r == 0);
 
280
 
 
281
  r = uv_read_start((uv_stream_t*)handle, buf_alloc, after_read);
 
282
  ASSERT(r == 0);
 
283
}
 
284
 
 
285
 
 
286
static void on_server_close(uv_handle_t* handle) {
 
287
  ASSERT(handle == (uv_handle_t*)&server);
 
288
}
 
289
 
 
290
 
 
291
static int dns_start(int port) {
 
292
  struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port);
 
293
  int r;
 
294
 
 
295
  r = uv_tcp_init(loop, &server);
 
296
  if (r) {
 
297
    /* TODO: Error codes */
 
298
    fprintf(stderr, "Socket creation error\n");
 
299
    return 1;
 
300
  }
 
301
 
 
302
  r = uv_tcp_bind(&server, addr);
 
303
  if (r) {
 
304
    /* TODO: Error codes */
 
305
    fprintf(stderr, "Bind error\n");
 
306
    return 1;
 
307
  }
 
308
 
 
309
  r = uv_listen((uv_stream_t*)&server, 128, on_connection);
 
310
  if (r) {
 
311
    /* TODO: Error codes */
 
312
    fprintf(stderr, "Listen error\n");
 
313
    return 1;
 
314
  }
 
315
 
 
316
  return 0;
 
317
}
 
318
 
 
319
 
 
320
HELPER_IMPL(dns_server) {
 
321
  loop = uv_default_loop();
 
322
 
 
323
  if (dns_start(TEST_PORT_2))
 
324
    return 1;
 
325
 
 
326
  uv_run(loop);
 
327
  return 0;
 
328
}