📄 tunnel.c
字号:
tunnel_write_data (Tunnel *tunnel, void *data, size_t length){ if (write_all (tunnel->out_fd, data, length) == -1) { log_error ("tunnel_write_data: write error: %s", strerror (errno)); return -1; } tunnel->bytes += length; return length;}static inttunnel_write_request (Tunnel *tunnel, Request request, void *data, Length length){ if (tunnel->bytes + sizeof request + (data ? sizeof length + length : 0) > tunnel->content_length) tunnel_padding (tunnel, tunnel->content_length - tunnel->bytes);#if 1 /* FIXME: this is a kludge */ { time_t t; time (&t); if (tunnel_is_client (tunnel) && tunnel_is_connected (tunnel) && t - tunnel->out_connect_time > tunnel->max_connection_age) { char c = TUNNEL_DISCONNECT; log_debug ("tunnel_write_request: connection > %d seconds old", tunnel->max_connection_age); if (tunnel->strict_content_length) { int l = tunnel->content_length - tunnel->bytes - 1; log_debug ("tunnel_write_request: write padding (%d bytes)", tunnel->content_length - tunnel->bytes - 1); if (l > 3) { char c; short s; int i; c = TUNNEL_PADDING; tunnel_write_data (tunnel, &c, sizeof c); s = htons(l-2); tunnel_write_data (tunnel, &s, sizeof s); l -= 2; c = 0; for (i=0; i<l; i++) tunnel_write_data (tunnel, &c, sizeof c); } else { char c = TUNNEL_PAD1; int i; for (i=0; i<l; i++) tunnel_write_data (tunnel, &c, sizeof c); } } log_debug ("tunnel_write_request: closing old connection"); if (tunnel_write_data (tunnel, &c, sizeof c) <= 0) return -1; tunnel_out_disconnect (tunnel); } }#endif if (tunnel_is_disconnected (tunnel)) { if (tunnel_is_client (tunnel)) { if (tunnel_out_connect (tunnel) == -1) return -1; } else {#if 0 log_error ("tunnel_write_request: output is disconnected"); errno = EIO; return -1;#else if (tunnel_accept (tunnel) == -1) return -1;#endif } } if (request != TUNNEL_PADDING && request != TUNNEL_PAD1) tunnel->padding_only = FALSE; if (tunnel_write_data (tunnel, &request, sizeof request) == -1) { if (errno != EPIPE) return -1; tunnel_out_disconnect (tunnel); if (tunnel_is_client (tunnel)) tunnel_out_connect (tunnel); else { log_error ("tunnel_write_request: couldn't write request: " "output is disconnected"); errno = EIO; return -1; } /* return tunnel_write_request (tunnel, request, data, length); */ if (tunnel_write_data (tunnel, &request, sizeof request) == -1) return -1; } if (data) { Length network_length = htons ((short)length); if (tunnel_write_data (tunnel, &network_length, sizeof network_length) == -1) return -1;#ifdef DEBUG_MODE if (request == TUNNEL_DATA && debug_level >= 5) { log_annoying ("tunnel_write_request: TUNNEL_DATA:"); dump_buf (debug_file, data, (size_t)length); }#endif if (tunnel_write_data (tunnel, data, (size_t)length) == -1) return -1; } if (data) { tunnel->out_total_raw += 3 + length; if (request == TUNNEL_DATA) log_verbose ("tunnel_write_request: %s (%d)", REQ_TO_STRING (request), length); else log_debug ("tunnel_write_request: %s (%d)", REQ_TO_STRING (request), length); } else { tunnel->out_total_raw += 1; log_debug ("tunnel_write_request: %s", REQ_TO_STRING (request)); } log_annoying ("tunnel_write_data: out_total_raw = %u", tunnel->out_total_raw);#ifdef DEBUG_MODE if (tunnel->bytes > tunnel->content_length) log_debug ("tunnel_write_request: tunnel->bytes > tunnel->content_length");#endif if (tunnel->bytes >= tunnel->content_length) { char c = TUNNEL_DISCONNECT; tunnel_write_data (tunnel, &c, sizeof c); tunnel_out_disconnect (tunnel);#if 0 if (tunnel_is_server (tunnel)) tunnel_accept (tunnel);#endif } return 0;}inttunnel_connect (Tunnel *tunnel){ char auth_data[1] = { 42 }; /* dummy data, not used by server */ log_verbose ("tunnel_connect()"); if (tunnel_is_connected (tunnel)) { log_error ("tunnel_connect: already connected"); errno = EINVAL; return -1; } if (tunnel_write_request (tunnel, TUNNEL_OPEN, auth_data, sizeof auth_data) == -1) return -1; if (tunnel_in_connect (tunnel) <= 0) return -1; return 0;}static inline inttunnel_write_or_padding (Tunnel *tunnel, Request request, void *data, size_t length){ static char padding[65536]; size_t n, remaining; char *wdata = data; for (remaining = length; remaining > 0; remaining -= n, wdata += n) { if (tunnel->bytes + remaining > tunnel->content_length - sizeof_header && tunnel->content_length - tunnel->bytes > sizeof_header) n = tunnel->content_length - sizeof_header - tunnel->bytes; else if (remaining > tunnel->content_length - sizeof_header) n = tunnel->content_length - sizeof_header; else n = remaining; if (n > 65535) n = 65535; if (request == TUNNEL_PADDING) { if (n + sizeof_header > remaining) n = remaining - sizeof_header; if (tunnel_write_request (tunnel, request, padding, n) == -1) break; n += sizeof_header; } else { if (tunnel_write_request (tunnel, request, wdata, n) == -1) break; } } return length - remaining;}ssize_ttunnel_write (Tunnel *tunnel, void *data, size_t length){ ssize_t n; n = tunnel_write_or_padding (tunnel, TUNNEL_DATA, data, length); tunnel->out_total_data += length; log_verbose ("tunnel_write: out_total_data = %u", tunnel->out_total_data); return n;}ssize_ttunnel_padding (Tunnel *tunnel, size_t length){ if (length < sizeof_header + 1) { int i; for (i = 0; i < length; i++) tunnel_write_request (tunnel, TUNNEL_PAD1, NULL, 0); return length; } return tunnel_write_or_padding (tunnel, TUNNEL_PADDING, NULL, length);}inttunnel_close (Tunnel *tunnel){ struct pollfd p; char buf[10240]; ssize_t n; if (tunnel->strict_content_length) { log_debug ("tunnel_close: write padding (%d bytes)", tunnel->content_length - tunnel->bytes - 1); tunnel_padding (tunnel, tunnel->content_length - tunnel->bytes - 1); } log_debug ("tunnel_close: write TUNNEL_CLOSE request"); tunnel_write_request (tunnel, TUNNEL_CLOSE, NULL, 0); tunnel_out_disconnect (tunnel); log_debug ("tunnel_close: reading trailing data from input ..."); p.fd = tunnel->in_fd; p.events = POLLIN; while (poll (&p, 1, READ_TRAIL_TIMEOUT) > 0) { if (p.revents & POLLIN) { n = read (tunnel->in_fd, buf, sizeof buf); if (n > 0) { log_annoying ("read (%d, %p, %d) = %d", tunnel->in_fd, buf, sizeof buf, n); continue; } else if (n == -1 && errno == EAGAIN) continue; else if (n == -1) log_debug ("tunnel_close: ... error: %s", strerror (errno)); else log_debug ("tunnel_close: ... done (tunnel closed)"); } if (p.revents & POLLHUP) log_debug ("POLLHUP"); if (p.revents & POLLERR) log_debug ("POLLERR"); if (p.revents & POLLNVAL) log_debug ("POLLNVAL"); break; } tunnel_in_disconnect (tunnel); tunnel->buf_len = 0; tunnel->in_total_raw = 0; tunnel->in_total_data = 0; tunnel->out_total_raw = 0; tunnel->out_total_data = 0; return 0;}static inttunnel_read_request (Tunnel *tunnel, enum tunnel_request *request, unsigned char *buf, size_t *length){ Request req; Length len; ssize_t n; log_annoying ("read (%d, %p, %d) ...", tunnel->in_fd, &req, 1); n = read (tunnel->in_fd, &req, 1); log_annoying ("... = %d", n); if (n == -1) { if (errno != EAGAIN) log_error ("tunnel_read_request: error reading request: %s", strerror (errno)); return n; } else if (n == 0) { log_debug ("tunnel_read_request: connection closed by peer"); tunnel_in_disconnect (tunnel); if (tunnel_is_client (tunnel) && tunnel_in_connect (tunnel) == -1) return -1; errno = EAGAIN; return -1; } *request = req; tunnel->in_total_raw += n; log_annoying ("request = 0x%x (%s)", req, REQ_TO_STRING (req)); if (req & TUNNEL_SIMPLE) { log_annoying ("tunnel_read_request: in_total_raw = %u", tunnel->in_total_raw); log_debug ("tunnel_read_request: %s", REQ_TO_STRING (req)); *length = 0; return 1; } n = read_all (tunnel->in_fd, &len, 2); if (n <= 0) { log_error ("tunnel_read_request: error reading request length: %s", strerror (errno)); if (n == 0) errno = EIO; return -1; } len = ntohs (len); *length = len; tunnel->in_total_raw += n; log_annoying ("length = %d", len); if (len > 0) { n = read_all (tunnel->in_fd, buf, (size_t)len); if (n <= 0) { log_error ("tunnel_read_request: error reading request data: %s", strerror (errno)); if (n == 0) errno = EIO; return -1; } tunnel->in_total_raw += n; log_annoying ("tunnel_read_request: in_total_raw = %u", tunnel->in_total_raw); } if (req == TUNNEL_DATA) log_verbose ("tunnel_read_request: %s (%d)", REQ_TO_STRING (req), len); else log_debug ("tunnel_read_request: %s (%d)", REQ_TO_STRING (req), len); return 1;}ssize_ttunnel_read (Tunnel *tunnel, void *data, size_t length){ enum tunnel_request req; size_t len; ssize_t n; if (tunnel->buf_len > 0) { n = min (tunnel->buf_len, length); memcpy (data, tunnel->buf_ptr, n); tunnel->buf_ptr += n; tunnel->buf_len -= n; return n; } if (tunnel->in_fd == -1) { if (tunnel_is_client (tunnel)) { if (tunnel_in_connect (tunnel) == -1) return -1; } else {#if 1 if (tunnel_accept (tunnel) == -1) return -1;#else errno = EAGAIN; return -1;#endif } errno = EAGAIN; return -1; } if (tunnel->out_fd == -1 && tunnel_is_server (tunnel)) { tunnel_accept (tunnel); errno = EAGAIN; return -1; } if (tunnel_read_request (tunnel, &req, tunnel->buf, &len) <= 0) {log_annoying ("tunnel_read_request returned <= 0, returning -1"); return -1; } switch (req) { case TUNNEL_OPEN: /* do something with tunnel->buf */ break; case TUNNEL_DATA: tunnel->buf_ptr = tunnel->buf; tunnel->buf_len = len; tunnel->in_total_data += len; log_verbose ("tunnel_read: in_total_data = %u", tunnel->in_total_data); return tunnel_read (tunnel, data, length); case TUNNEL_PADDING: /* discard data */ break; case TUNNEL_PAD1: /* do nothing */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -