/* This file is part of gacopyz. Copyright (C) 2007-2020 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include int _gacopyz_read_tm(gacopyz_iod_t iod, int tm, char *buf, size_t size) { int rc = MI_SUCCESS; while (size) { fd_set rset; fd_set xset; int res; struct timeval to; FD_ZERO(&rset); FD_ZERO(&xset); FD_SET(iod->sd, &rset); FD_SET(iod->sd, &xset); to = iod->timeout[tm]; res = select(iod->sd + 1, &rset, NULL, &xset, &to); if (res == 0) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: connection timed out"), "_gacopyz_read"); errno = ETIMEDOUT; rc = MI_FAILURE; break; } else if (res < 0) { if (errno == EINTR) continue; rc = MI_FAILURE; break; } else if (rc > 0) { if (FD_ISSET(iod->sd, &xset)) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: exception on control fd"), "_gacopyz_read"); rc = MI_FAILURE; break; } /* Otherwise, FD_ISSET(iod->sd, &rset) is true */ } res = read(iod->sd, buf, size); if (res == -1) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: read failed: %s"), "_gacopyz_read", strerror(errno)); rc = MI_FAILURE; break; } else if (res == 0) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: end of file"), "_gacopyz_read"); rc = MI_FAILURE; break; } buf += res; size -= res; } return rc; } int _gacopyz_read(gacopyz_iod_t iod, char *buf, size_t size) { return _gacopyz_read_tm(iod, GACOPYZ_TO_READ, buf, size); } int _gacopyz_write(gacopyz_iod_t iod, const char *buf, size_t size) { int rc = MI_SUCCESS; while (size) { fd_set wset; fd_set xset; int res; struct timeval to; FD_ZERO(&wset); FD_ZERO(&xset); FD_SET(iod->sd, &wset); FD_SET(iod->sd, &xset); to = iod->timeout[GACOPYZ_TO_READ]; res = select(iod->sd + 1, NULL, &wset, &xset, &to); if (res == 0) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: connection timed out"), "_gacopyz_write"); errno = ETIMEDOUT; rc = MI_FAILURE; break; } else if (res < 0) { if (errno == EINTR) continue; rc = MI_FAILURE; break; } else if (rc > 0) { if (FD_ISSET(iod->sd, &xset)) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: exception on control fd"), "_gacopyz_write"); rc = MI_FAILURE; break; } /* Otherwise, FD_ISSET(iod->sd, &wset) is true */ } res = write(iod->sd, buf, size); if (res == -1) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: write failed: %s"), "_gacopyz_write", strerror(errno)); rc = MI_FAILURE; break; } else if (res == 0) { gacopyz_io_log(iod, SMI_LOG_ERR, _("%s: wrote 0 bytes"), "_gacopyz_write"); rc = MI_FAILURE; break; } buf += res; size -= res; } return rc; } union header { struct { gacopyz_uint32_t size; unsigned char cmd; } hdr; char buf[5]; }; int gacopyz_send_command(gacopyz_iod_t iod, int cmd, const void *data, size_t size) { int rc; union header header; gacopyz_io_log(iod, SMI_LOG_DEBUG, _("send header: size=%lu, cmd=%c"), size, cmd); gacopyz_io_logdump(iod, _("send data"), data, size); header.hdr.size = htonl(size + 1); header.hdr.cmd = cmd; rc = _gacopyz_write(iod, header.buf, sizeof header.buf); if (rc != MI_SUCCESS) return rc; if (size) rc = _gacopyz_write(iod, data, size); return rc; } int gacopyz_read_command(gacopyz_iod_t iod, int tm, unsigned char *cmd, size_t *pcount, char **pbuf, size_t *psize) { union header header; size_t size; int rc; if ((rc = _gacopyz_read_tm(iod, tm, header.buf, sizeof header.buf)) != MI_SUCCESS) return rc; size = ntohl(header.hdr.size) - 1; if (size + 1 > *psize) { char *p = realloc(*pbuf, size + 1); if (!p) { gacopyz_io_log(iod, SMI_LOG_ERR, "%s", strerror(errno)); return MI_FAILURE; } *pbuf = p; *psize = size + 1; } gacopyz_io_log(iod, SMI_LOG_DEBUG, _("read header: size=%lu, cmd=%c"), size, header.hdr.cmd); if ((rc = _gacopyz_read(iod, *pbuf, size)) != MI_SUCCESS) return rc; (*pbuf)[size] = 0; gacopyz_io_logdump(iod, _("read data"), *pbuf, size); *pcount = size; *cmd = header.hdr.cmd; return MI_SUCCESS; }