Как я могу надежно заставить send (2) сделать короткую отправку? - PullRequest
5 голосов
/ 15 января 2020

send(2) принимает буфер и длину буфера. Может возвращать либо ошибку, либо некоторое количество успешно отправленных байтов, вплоть до размера буфера. В некоторых случаях send отправит меньше запрошенного количества байтов (например, { ссылка }).

Есть ли способ последовательно инициировать короткую отправку в модульном тесте, кроме отправки большого сообщения и запуска сигнала из другого потока и надежды на удачу?

Ответы [ 3 ]

2 голосов
/ 15 января 2020

Просто сверните свои собственные:


#include <sys/types.h>
#include <sys/socket.h>

ssize_t mysend(int fd, void * buff, size_t len, int flags)
{

#if WANT_PARTIAL_SEND
len = 1 + urand(len -1);
#endif

return send(fd, buff, len, flags);
}
1 голос
/ 16 января 2020

Если вы упакуете тестируемый код в общую библиотеку (или в библиотеку stati c с ослабленными символами), тогда ваш исполняемый файл тестирования (который связывается с библиотекой) сможет переопределить send для себя и для библиотек, на которые он ссылается.

Пример (переопределяет write вместо send):

#!/bin/sh -eu
cat > code.c <<EOF
#include <unistd.h>
#include <stdio.h>
ssize_t hw(void)
{
    static const char b[]="hello world\n";
    return write(1, b, sizeof(b)-1);
}
void libfunc(void)
{
    puts(__func__);
    hw();
}
EOF

cat > test.c <<'EOF'
#include <stdio.h>
void libfunc(void);
ssize_t hw(void);

#if TEST
ssize_t hw(void)
{
    puts("override");
    return 42;
}
#endif
int main()
{
    libfunc();
    puts("====");
    printf("%zu\n", hw());
}

EOF

gcc code.c -fpic -shared -o libcode.so
gcc test.c $PWD/libcode.so -o real
gcc -DTEST test.c $PWD/libcode.so -o mocked
set -x
./real
./mocked

Пример вывода:

hello world
hello world
libfunc
====
12
libfunc
override
====
override
42

This затмевает реализацию символа в lib c, и хотя существует механизм доступа к переопределенному элементу (а именно dlopen и / или -Wl,--wrap), вам не нужно обращаться к нему в модульном тесте (если он вам нужен) в других модульных тестах проще всего поместить эти другие модульные тесты в другую программу).

0 голосов
/ 16 января 2020

send(2) по умолчанию возвращается только тогда, когда все данные были успешно скопированы в буферы отправки. Возможные способы заставить его отправлять меньше байтов сильно зависят от обстоятельств.

Если вы 1. можете получить доступ к сокету 2. не хотите изменять поведение всех вызовов на send в связанном двоичном файле ,

тогда вы можете установить неблокирование сокета. Затем вызов send отправит как можно больше октетов. Количество отправляемых октетов зависит в основном от объема свободной памяти в буфере отправки сокета, на который вы хотите отправить. Таким образом, если вы получили

uint8_t my_data[NUM_BYTES_TO_SEND] = {0}; /* We don't care what your buffer actually contains in this example ... */

size_t num_bytes = sizeof(my_data);

send(fd, my_data, num_bytes);

и хотите, чтобы send отправил меньше num_bytes, вы можете попытаться уменьшить буфер отправки вашего сокета fd. Возможно ли это, как выполнить sh, это может зависеть от вашей ОС.

В разделе Linux вы можете попытаться уменьшить буфер отправки, установив размер буфера вручную, используя setsockopt(2) через опция SO_SNDBUF, описанная в man-странице `socket (7):

uint8_t my_data[NUM_BYTES_TO_SEND] = {0};
size_t num_bytes = sizeof(my_data);
size_t max_bytes_to_send = num_bytes - 1;   /* Force to send at most 1 byte less than in our buffer */

/* Set the socket non-blocking - you should check status afterwards */
int status = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);

/* reduce the size of the send buffer below the number of bytes you want to send */
setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &max_bytes_to_send, sizeof (size_t));

...

send(fd, my_data, num_bytes);

/* Possibly restore the old socket state */

Возможно, вам также придется возиться с опцией SO_SNDBUFFORCE.

Дополнительная информация для

В любом случае, лучший способ для go для вас зависит от обстоятельств. Если вы ищете надежное решение для проверки кода, к которому вы, возможно, даже не можете получить доступ, но можете динамически ссылаться на ваш проект, вы можете go воспользоваться другим подходом, предложенным здесь: затемните символ send в скомпилированном коде. С другой стороны, это повлияет на все вызовы send в вашем коде (вы, конечно, можете обойти эту проблему, например, если ваша замена send будет зависеть от некоторых флагов, которые вы можете установить).

Если вы можете получить доступ к сокету fd и хотите, чтобы на него влияли только определенные вызовы c send (как я полагаю, это касается вас, поскольку вы говорите о модульных тестах и ​​проверке на отправку меньшего количества байтов чем ожидалось во всех ваших тестах, вероятно, не то, что вы хотите?), тогда путь к уменьшению буфера отправки может быть способом к go.

...