/* * moves data from one fd to other * * returns number of bytes copied if success * returns 0 (FD_CNXCLOSED) if incoming socket closed * returns FD_NODATA if no data was available * returns FD_STALLED if data was read, could not be written, and has been * stored in temporary buffer. */ int fd2fd(struct queue *target_q, struct queue *from_q) { char buffer[BUFSIZ]; int target, from, size_r, size_w; target = target_q->fd; from = from_q->fd; size_r = read(from, buffer, sizeof(buffer)); if (size_r == -1) { switch (errno) { case EAGAIN: if (verbose) fprintf(stderr, "reading 0 from %d\n", from); return FD_NODATA; case ECONNRESET: case EPIPE: return FD_CNXCLOSED; } } CHECK_RES_RETURN(size_r, "read"); if (size_r == 0) return FD_CNXCLOSED; size_w = write(target, buffer, size_r); /* process -1 when we know how to deal with it */ if (size_w == -1) { switch (errno) { case EAGAIN: /* write blocked: Defer data */ defer_write(target_q, buffer, size_r); return FD_STALLED; case ECONNRESET: case EPIPE: /* remove end closed -- drop the connection */ return FD_CNXCLOSED; } } else if (size_w < size_r) { /* incomplete write -- defer the rest of the data */ defer_write(target_q, buffer + size_w, size_r - size_w); return FD_STALLED; } CHECK_RES_RETURN(size_w, "write"); return size_w; }
/* * Read the beginning of data coming from the client connection and check if * it's a known protocol. * Return PROBE_AGAIN if not enough data, or PROBE_MATCH if it succeeded in * which case cnx->proto is set to the appropriate protocol. */ int probe_client_protocol(struct connection *cnx) { char buffer[BUFSIZ]; struct proto *p; int n; n = read(cnx->q[0].fd, buffer, sizeof(buffer)); /* It's possible that read() returns an error, e.g. if the client * disconnected between the previous call to select() and now. If that * happens, we just connect to the default protocol so the caller of this * function does not have to deal with a specific failure condition (the * connection will just fail later normally). */ if (n > 0) { int res = PROBE_NEXT; defer_write(&cnx->q[1], buffer, n); for (p = cnx->proto; p && res == PROBE_NEXT; p = p->next) { if (! p->probe) continue; if (verbose) fprintf(stderr, "probing for %s\n", p->description); cnx->proto = p; res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p); } if (res != PROBE_NEXT) return res; } if (verbose) fprintf(stderr, "all probes failed, connecting to first protocol: %s\n", protocols->description); /* If none worked, return the first one affected (that's completely * arbitrary) */ cnx->proto = protocols; return PROBE_MATCH; }