- int d = recv_send ? 0 : start_magic;
- int flags = recv_send ? 0 : MSG_NOSIGNAL;
- enum tx_rx_state state = TX_RX_START;
- void *buf = &d;
- size_t size = sizeof(d);
- off_t n = 0;
- int rc;
- int again;
-
- do {
- again = 0;
- rc = txrx(fd, buf + n, size - n, flags);
- if (rc <= 0) { /* error */
- if (rc == -1 && errno == EAGAIN)
- again = 1;
- else
- state = TX_RX_ERR;
- } else if (rc + n == size) /* done */
- switch (state) {
- case TX_RX_START:
- if (recv_send && d != start_magic)
- state = TX_RX_ERR;
- else {
- state = TX_RX_SEQ;
- buf = &msg->seq;
- size = sizeof(msg->seq);
- n = 0;
- }
- break;
- case TX_RX_SEQ:
- state = TX_RX_NUM_BYTES;
- buf = &msg->num_bytes;
- size = sizeof(msg->num_bytes);
- n = 0;
- break;
- case TX_RX_NUM_BYTES:
- if (msg->num_bytes >
- 1024*1024)
- state = TX_RX_ERR;
- else if (recv_send && msg->num_bytes) {
- msg->buf = malloc(msg->num_bytes);
- if (!msg->buf)
- state = TX_RX_ERR;
- else {
- state = TX_RX_BUF;
- buf = msg->buf;
- size = msg->num_bytes;
- n = 0;
- }
- } else if (!recv_send && msg->num_bytes) {
- state = TX_RX_BUF;
- buf = msg->buf;
- size = msg->num_bytes;
- n = 0;
- } else {
- d = recv_send ? 0 : end_magic;
- state = TX_RX_END;
- buf = &d;
- size = sizeof(d);
- n = 0;
- }
- break;
- case TX_RX_BUF:
- d = recv_send ? 0 : end_magic;
- state = TX_RX_END;
- buf = &d;
- size = sizeof(d);
- n = 0;
- break;
- case TX_RX_END:
- if (recv_send && d != end_magic)
- state = TX_RX_ERR;
- else
- state = TX_RX_SUCCESS;
- break;
- case TX_RX_ERR:
- case TX_RX_SUCCESS:
- break;
- }
- else /* continue */
- n += rc;
-
- if (again) {
- fd_set set;
- struct timeval timeout = { tmo, 0 };
- struct timeval *ptmo = tmo ? &timeout : NULL;
-
- FD_ZERO(&set);
- FD_SET(fd, &set);
-
- if (recv_send)
- rc = select(fd + 1, &set, NULL, NULL, ptmo);
- else
- rc = select(fd + 1, NULL, &set, NULL, ptmo);
-
- if (rc <= 0)
- state = TX_RX_ERR;
- }
- } while (state < TX_RX_SUCCESS);
+ fd_set set;
+ int rv;
+ struct timeval timeout = {tmo, 0};
+ struct timeval *ptmo = tmo ? &timeout : NULL;
+
+ while (len) {
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ rv = select(fd+1, NULL, &set, NULL, ptmo);
+ if (rv <= 0)
+ return -1;
+ rv = write(fd, buf, len);
+ if (rv <= 0)
+ return -1;
+ len -= rv;
+ buf += rv;
+ }
+ return 0;
+}