* stoplisten, send, read, pause, close).
*/
+void
+isc__nm_tcp_senddns(isc_nmhandle_t *handle, const isc_region_t *region,
+ isc_nm_cb_t cb, void *cbarg);
+/*%<
+ * The same as 'isc__nm_tcp_send()', but with data length sent
+ * ahead of data (two bytes (16 bit) in big-endian format).
+ */
+
void
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0);
* not negotiated of the underlying protocol of the connection
* represented via the given handle does not support ALPN.
*/
+
+void
+isc__nm_senddns(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
+ void *cbarg);
+/*%<
+ * The same as 'isc_nm_send()', but with data length sent
+ * ahead of data (two bytes (16 bit) in big-endian format).
+ */
return (result);
}
-void
-isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
- isc_nm_cb_t cb, void *cbarg) {
+static void
+tcp_send(isc_nmhandle_t *handle, const isc_region_t *region, isc_nm_cb_t cb,
+ void *cbarg, const bool dnsmsg) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(sock->tid == isc_tid());
uvreq = isc__nm_uvreq_get(sock->worker, sock);
+ if (dnsmsg) {
+ *(uint16_t *)uvreq->tcplen = htons(region->length);
+ }
uvreq->uvbuf.base = (char *)region->base;
uvreq->uvbuf.len = region->length;
return;
}
+void
+isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
+ isc_nm_cb_t cb, void *cbarg) {
+ tcp_send(handle, region, cb, cbarg, false);
+}
+
+void
+isc__nm_tcp_senddns(isc_nmhandle_t *handle, const isc_region_t *region,
+ isc_nm_cb_t cb, void *cbarg) {
+ tcp_send(handle, region, cb, cbarg, true);
+}
+
static void
tcp_send_cb(uv_write_t *req, int status) {
isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data;
REQUIRE(sock->type == isc_nm_tcpsocket);
int r;
+ uv_buf_t bufs[2] = { { 0 }, { 0 } }; /* ugly, but required for old GCC
+ versions */
+ size_t nbufs = 1;
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
- uv_buf_t uvbuf = { .base = req->uvbuf.base, .len = req->uvbuf.len };
+ /* Check if we are not trying to send a DNS message */
+ if (*(uint16_t *)req->tcplen == 0) {
+ bufs[0].base = req->uvbuf.base;
+ bufs[0].len = req->uvbuf.len;
- r = uv_try_write(&sock->uv_handle.stream, &uvbuf, 1);
+ r = uv_try_write(&sock->uv_handle.stream, bufs, nbufs);
- if (r == (int)(uvbuf.len)) {
- /* Wrote everything */
- isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
- return (ISC_R_SUCCESS);
- } else if (r > 0) {
- uvbuf.base += (size_t)r;
- uvbuf.len -= (size_t)r;
- } else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
- return (isc_uverr2result(r));
+ if (r == (int)(bufs[0].len)) {
+ /* Wrote everything */
+ isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
+ return (ISC_R_SUCCESS);
+ } else if (r > 0) {
+ bufs[0].base += (size_t)r;
+ bufs[0].len -= (size_t)r;
+ } else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
+ return (isc_uverr2result(r));
+ }
+ } else {
+ nbufs = 2;
+ bufs[0].base = req->tcplen;
+ bufs[0].len = 2;
+ bufs[1].base = req->uvbuf.base;
+ bufs[1].len = req->uvbuf.len;
+
+ r = uv_try_write(&sock->uv_handle.stream, bufs, nbufs);
+
+ if (r == (int)(bufs[0].len + bufs[1].len)) {
+ /* Wrote everything */
+ isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
+ return (ISC_R_SUCCESS);
+ } else if (r == 1) {
+ /* Partial write of DNSMSG length */
+ bufs[0].base = req->tcplen + 1;
+ bufs[0].len = 1;
+ } else if (r > 0) {
+ /* Partial write of DNSMSG */
+ nbufs = 1;
+ bufs[0].base = req->uvbuf.base + (r - 2);
+ bufs[0].len = req->uvbuf.len - (r - 2);
+ } else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
+ return (isc_uverr2result(r));
+ }
}
- r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, &uvbuf, 1,
+ r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, bufs, nbufs,
tcp_send_cb);
if (r < 0) {
return (isc_uverr2result(r));