libserverframe/src/sf_iov.c

198 lines
5.1 KiB
C

/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "fastcommon/logger.h"
#include "fastcommon/sockopt.h"
#include "sf_define.h"
#include "sf_iov.h"
int sf_iova_consume(SFDynamicIOVArray *iova, const int consume_len)
{
struct iovec *iob;
struct iovec *end;
int sum_bytes;
int remain_len;
int result;
if (iova->cnt <= 0) {
logError("file: "__FILE__", line: %d, "
"invalid iov count: %d", __LINE__, iova->cnt);
return EINVAL;
}
if ((result=sf_iova_check_alloc(iova)) != 0) {
return result;
}
end = iova->iov + iova->cnt;
iob = iova->iov;
sum_bytes = iob->iov_len;
for (iob=iob + 1; sum_bytes <= consume_len && iob < end; iob++) {
sum_bytes += iob->iov_len;
}
if (sum_bytes < consume_len) {
logError("file: "__FILE__", line: %d, "
"iov length: %d < consume length: %d",
__LINE__, sum_bytes, consume_len);
return EOVERFLOW;
}
iova->cnt -= (iob - iova->iov);
iova->iov = iob;
if (iova->cnt == 0) {
struct iovec *last;
/* update the last iov for next slice */
last = iob - 1;
last->iov_base = (char *)last->iov_base + last->iov_len;
last->iov_len = 0;
} else {
/* adjust the first element */
remain_len = sum_bytes - consume_len;
if (remain_len < iob->iov_len) {
iob->iov_base = (char *)iob->iov_base +
(iob->iov_len - remain_len);
iob->iov_len = remain_len;
}
}
return 0;
}
static inline int iova_slice(SFDynamicIOVArray *iova, const int slice_len)
{
struct iovec *iob;
struct iovec *end;
int sum_bytes;
int exceed_len;
sum_bytes = 0;
end = iova->ptr + iova->input.cnt;
for (iob=iova->iov; iob<end; iob++) {
sum_bytes += iob->iov_len;
if (sum_bytes > slice_len) {
exceed_len = sum_bytes - slice_len;
iob->iov_len -= exceed_len;
break;
} else if (sum_bytes == slice_len) {
break;
}
}
if (iob < end) {
iova->cnt = (iob - iova->iov) + 1;
return 0;
} else {
logError("file: "__FILE__", line: %d, "
"iov remain bytes: %d < slice length: %d",
__LINE__, sum_bytes, slice_len);
iova->cnt = 0;
return EOVERFLOW;
}
}
int sf_iova_first_slice(SFDynamicIOVArray *iova, const int slice_len)
{
int result;
if ((result=sf_iova_check_alloc(iova)) != 0) {
return result;
}
return iova_slice(iova, slice_len);
}
int sf_iova_next_slice(SFDynamicIOVArray *iova,
const int consume_len, const int slice_len)
{
struct iovec *last;
const struct iovec *origin;
int remain_len;
int result;
if ((result=sf_iova_consume(iova, consume_len)) != 0) {
return result;
}
last = iova->iov + iova->cnt - 1;
origin = iova->input.iov + (last - iova->ptr);
remain_len = ((char *)origin->iov_base + origin->iov_len) -
(char *)last->iov_base;
if (last->iov_len != remain_len) {
last->iov_len = remain_len;
if (iova->cnt == 0) {
iova->iov = last;
}
}
return iova_slice(iova, slice_len);
}
int sf_iova_memset_ex(const struct iovec *iov, const int iovcnt,
int c, const int offset, const int length)
{
const struct iovec *iob;
const struct iovec *end;
int sum_bytes;
int remain_len;
int left_bytes;
char *start;
if (length == 0) {
return 0;
}
sum_bytes = 0;
end = iov + iovcnt;
for (iob=iov; iob<end; iob++) {
sum_bytes += iob->iov_len;
if (sum_bytes > offset) {
break;
}
}
if (iob == end) {
logError("file: "__FILE__", line: %d, "
"iov length: %d < (offset: %d + length: %d)",
__LINE__, sum_bytes, offset, length);
return EOVERFLOW;
}
remain_len = sum_bytes - offset;
start = (char *)iob->iov_base + (iob->iov_len - remain_len);
if (length <= remain_len) {
memset(start, c, length);
return 0;
}
memset(start, c, remain_len);
left_bytes = length - remain_len;
while (++iob < end) {
if (left_bytes <= iob->iov_len) {
memset(iob->iov_base, c, left_bytes);
return 0;
}
memset(iob->iov_base, c, iob->iov_len);
left_bytes -= iob->iov_len;
}
logError("file: "__FILE__", line: %d, "
"iov length is too short, overflow bytes: %d",
__LINE__, left_bytes);
return EOVERFLOW;
}