static int tunnelError(TunnelPtr tunnel, int code, AtomPtr message) { int n; if(tunnel->fd2 > 0) { CLOSE(tunnel->fd2); tunnel->fd2 = -1; } if(tunnel->buf2.buf == NULL) tunnel->buf2.buf = get_chunk(); if(tunnel->buf2.buf == NULL) goto fail; n = httpWriteErrorHeaders(tunnel->buf2.buf, CHUNK_SIZE - 1, 0, 1, code, message, 1, NULL, NULL, 0, NULL); if(n <= 0) goto fail; tunnel->buf2.head = n; tunnelDispatch(tunnel); return 1; fail: CLOSE(tunnel->fd1); tunnel->fd1 = -1; tunnelDispatch(tunnel); return 1; }
static int tunnelWrite2Handler(int status, FdEventHandlerPtr event, StreamRequestPtr request) { TunnelPtr tunnel = request->data; if(status || (tunnel->flags & TUNNEL_EPIPE2)) { tunnel->flags |= TUNNEL_EPIPE2; if(status < 0 && status != -EPIPE) do_log_error(L_ERROR, -status, "Couldn't write to server"); /* Empty the buffer to avoid a deadlock */ tunnel->buf1.tail = tunnel->buf1.head; goto done; } tunnel->buf1.tail = request->offset % CHUNK_SIZE; done: tunnel->flags &= ~TUNNEL_WRITER2; tunnelDispatch(tunnel); return 1; }
static int tunnelRead2Handler(int status, FdEventHandlerPtr event, StreamRequestPtr request) { TunnelPtr tunnel = request->data; if(status) { if(status < 0 && status != -EPIPE && status != -ECONNRESET) do_log_error(L_ERROR, -status, "Couldn't read from server"); tunnel->flags |= TUNNEL_EOF2; goto done; } tunnel->buf2.head = request->offset % CHUNK_SIZE; done: /* Keep buffer empty to avoid a deadlock */ if((tunnel->flags & TUNNEL_EPIPE1)) tunnel->buf2.tail = tunnel->buf2.head; tunnel->flags &= ~TUNNEL_READER2; tunnelDispatch(tunnel); return 1; }
static int tunnelRead1Handler(int status, FdEventHandlerPtr event, StreamRequestPtr request) { TunnelPtr tunnel = request->data; if(status) { if(status < 0) do_log_error(L_ERROR, -status, "Couldn't read from client"); tunnel->flags |= TUNNEL_EOF1; goto done; } tunnel->buf1.head = request->offset % CHUNK_SIZE; done: /* Keep buffer empty to avoid a deadlock */ if((tunnel->flags & TUNNEL_EPIPE2)) tunnel->buf1.tail = tunnel->buf1.head; tunnel->flags &= ~TUNNEL_READER1; tunnelDispatch(tunnel); return 1; }
static int tunnelHandlerParent(int fd, TunnelPtr tunnel) { char *message; int n; if(tunnel->buf1.buf == NULL) tunnel->buf1.buf = get_chunk(); if(tunnel->buf1.buf == NULL) { message = "Couldn't allocate buffer"; goto fail; } if(tunnel->buf1.tail != tunnel->buf1.head) { message = "Pipelined connect to parent proxy not implemented"; goto fail; } n = snnprintf(tunnel->buf1.buf, tunnel->buf1.tail, CHUNK_SIZE, "CONNECT %s:%d HTTP/1.1", tunnel->hostname->string, tunnel->port); if (parentAuthCredentials) n = buildServerAuthHeaders(tunnel->buf1.buf, n, CHUNK_SIZE, parentAuthCredentials); n = snnprintf(tunnel->buf1.buf, n, CHUNK_SIZE, "\r\n\r\n"); if(n < 0) { message = "Buffer overflow"; goto fail; } tunnel->buf1.head = n; tunnelDispatch(tunnel); return 1; fail: CLOSE(fd); tunnel->fd2 = -1; tunnelError(tunnel, 501, internAtom(message)); return 1; }
static int tunnelHandlerCommon(int fd, TunnelPtr tunnel) { const char *message = "HTTP/1.1 200 Tunnel established\r\n\r\n"; tunnel->fd2 = fd; if(parentHost) return tunnelHandlerParent(fd, tunnel); if(tunnel->buf2.buf == NULL) tunnel->buf2.buf = get_chunk(); if(tunnel->buf2.buf == NULL) { CLOSE(fd); tunnelError(tunnel, 501, internAtom("Couldn't allocate buffer")); return 1; } memcpy(tunnel->buf2.buf, message, MIN(CHUNK_SIZE - 1, strlen(message))); tunnel->buf2.head = MIN(CHUNK_SIZE - 1, strlen(message)); tunnelDispatch(tunnel); return 1; }