/* * Return a newlly allocated string with the next dpip token in the socket. * Return value: token string and length on success, NULL otherwise. * (useful for handling null characters in the data stream) */ char *a_Dpip_dsh_read_token2(Dsh *dsh, int blocking, int *DataSize) { char *p, *ret = NULL; *DataSize = 0; /* Read all available data without blocking */ Dpip_dsh_read(dsh, 0); /* switch mode upon request */ if (dsh->mode & DPIP_LAST_TAG) dsh->mode = DPIP_RAW; if (blocking) { if (dsh->mode & DPIP_TAG) { /* Only wait for data when the tag is incomplete */ if (!strstr(dsh->rdbuf->str, DPIP_TAG_END)) { do { Dpip_dsh_read(dsh, 1); p = strstr(dsh->rdbuf->str, DPIP_TAG_END); } while (!p && dsh->status == EAGAIN); } } else if (dsh->mode & DPIP_RAW) { /* Wait for data when the buffer is empty and there's no ERR/EOF */ while (dsh->rdbuf->len == 0 && dsh->status != DPIP_ERROR && dsh->status != DPIP_EOF) Dpip_dsh_read(dsh, 1); } } if (dsh->mode & DPIP_TAG) { /* return a full tag */ if ((p = strstr(dsh->rdbuf->str, DPIP_TAG_END))) { ret = dStrndup(dsh->rdbuf->str, p - dsh->rdbuf->str + 3); *DataSize = p - dsh->rdbuf->str + 3; dStr_erase(dsh->rdbuf, 0, p - dsh->rdbuf->str + 3); if (strstr(ret, DPIP_MODE_SWITCH_TAG)) dsh->mode |= DPIP_LAST_TAG; } } else { /* raw mode, return what we have "as is" */ if (dsh->rdbuf->len > 0) { ret = dStrndup(dsh->rdbuf->str, dsh->rdbuf->len); *DataSize = dsh->rdbuf->len; dStr_truncate(dsh->rdbuf, 0); } } return ret; }
/* * Read raw data from the socket into our buffer in * either BLOCKING or NONBLOCKING mode. */ static void Dpip_dsh_read(Dsh *dsh, int blocking) { char buf[RBUF_SZ]; int req_mode, old_flags = 0, st, ret = -3, nb = !blocking; dReturn_if (dsh->status == DPIP_ERROR || dsh->status == DPIP_EOF); req_mode = (nb) ? DPIP_NONBLOCK : 0; if ((dsh->mode & DPIP_NONBLOCK) != req_mode) { /* change mode temporarily... */ old_flags = fcntl(dsh->fd_in, F_GETFL); fcntl(dsh->fd_in, F_SETFL, (nb) ? O_NONBLOCK | old_flags : old_flags & ~O_NONBLOCK); } while (1) { st = read(dsh->fd_in, buf, RBUF_SZ); if (st < 0) { if (errno == EINTR) { continue; } else if (errno == EAGAIN) { dsh->status = DPIP_EAGAIN; ret = -1; break; } else { MSG_ERR("[Dpip_dsh_read] %s\n", dStrerror(errno)); dsh->status = DPIP_ERROR; break; } } else if (st == 0) { dsh->status = DPIP_EOF; break; } else { /* append to buf */ dStr_append_l(dsh->rdbuf, buf, st); if (blocking) break; } } if ((dsh->mode & DPIP_NONBLOCK) != req_mode) { /* restore old mode */ fcntl(dsh->fd_out, F_SETFL, old_flags); } /* assert there's no more data in the wire... * (st < buf upon interrupt || st == buf and no more data) */ if (blocking) Dpip_dsh_read(dsh, 0); }