5

send(2) takes a buffer and a buffer length. It can return either an error, or some number of bytes successfully sent up to the size of the buffer length. In some cases, send will send fewer than the number of bytes requested (e.g. https://stackoverflow.com/a/2618755/939259).

Is there a way to consistently trigger a short send in a unit test, other than sending a big message and firing a signal from another thread and hoping to get lucky?

Thomas Johnson
  • 10,776
  • 18
  • 60
  • 98
  • 3
    Have you tried mocking `send` and returning a specific test value? – dbush Jan 15 '20 at 18:18
  • 2
    Interrupting `send()` with a signal probably won't do it. You may need to fill up the kernel's socket buffer, by stopping the reading process, and then try to send more than will fit in the remainder of the buffer. – Barmar Jan 15 '20 at 18:21
  • @dbush I’m using gmock in performance-sensitive code, so this would mean adding a class and templatizing my code that uses send just for testing a very specific case. I’ll do it if I have to, but I’m hoping there’s an alternative. – Thomas Johnson Jan 15 '20 at 18:23
  • 1
    I don't really see a better option. Other than mocking you could send signals yourself (which seems hard to make deterministic) or write a custom kernel module. – Marco Bonelli Jan 15 '20 at 18:27
  • If you can manipulate the socket on the sending end, you could try to decrease the send buffer size of the socket to some value less than the length of the data you are going to pass to `send` . I never fiddled around with that, thus I am not sure whether and how precisely it works, but under linux, there is a socket option `SO_SNDBUF` (documented in `socket(7)`, which you can set using `setsockopt(2)` to set the send buffer size. However, I never did that myself, thus I don't know whether this works as I anticipate and whether it helps to solve your problem. – Michael Beer Jan 16 '20 at 14:39
  • The only cases where it will return less are an interrupt or non-blocking mode. Your link is packed with misinformation. – user207421 Jan 17 '20 at 08:45

3 Answers3

2

Just roll your own:


#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);
}
wildplasser
  • 43,142
  • 8
  • 66
  • 109
  • OP most probably does *not* want to use a different (differently named) function (that would require modifying the code to be tested). – Marco Bonelli Jan 15 '20 at 18:42
  • Well, you could always detour `send()` itself to a custom function that internally calls the original `send()` with a smaller buffer. – Remy Lebeau Jan 15 '20 at 21:14
1

If you pack the code-to-be tested into a shared library (or a static library with the symbols weakened), then your testing executable (which links with the library) will be able to override send for both itself and the libraries it links.

Example (overrides write rather than 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

Example output:

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

This overshadows the libc implementation of the symbol and while there are mechanism for accessing the overridee (namely dlopen and/or -Wl,--wrap), you shouldn't need to access it in a unit test (if you do need it in other unit tests, it's simplest to just put those other unit tests in a different program).

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
0

send(2) by default returns only when all data was successfully copied to the send buffers. The possible ways to force it to send less bytes highly depend on the circumstances.

If you 1. can access the socket 2. do not want to alter the behaviour of all calls to send in your linked binary,

then you could set the socket non-blocking. Then, a call to send will send as much octects as possible. The amount of octets sent depends mainly on the amount of free memory in the send buffer of the socket you want to send on. Thus, if you got

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);

and want send to send less than num_bytes, you could try to decrease the send buffer of your socket fd . Whether this is possible, how to accomplish this might depend on your OS.

Under Linux, you could try to shrink the send buffer by setting the buffer size manually by using setsockopt(2) via the option SO_SNDBUF, descibed in the man page `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 */

Possibly you also have to fiddle around with the option SO_SNDBUFFORCE .

Further info for

Anyhow, the best way to go for you depends on the circumstance. If you look for a reliable solution to check code you perhaps cannot even access, but link into your project dynamically, you might go with the other approach suggested here: Overshadow the send symbol in your compiled code . On the other hand, this will impact all calls to send in your code (you could, of course bypass this problem e.g. by having your send replacement depend on some flags you could set).

If you can access the socket fd, and want only specific send calls to be impacted (as I guess is the case with you, since you talk about unit tests, and checking for sending less bytes than expected in all your tests is probably not what you want?), then going the way to shrink the send buffer could be the way to go.

Michael Beer
  • 853
  • 5
  • 12
  • `send()` will send it all in blocking mode, unless an interrupt or error occurs. – user207421 Jan 17 '20 at 22:48
  • @user207421 good point. You can set the socket non-blocking via the SO_NONBLOCK option ( see https://stackoverflow.com/q/1525050/8219383 ), cant you? – Michael Beer Jan 17 '20 at 22:55
  • Well yes of course, but is the OP using non-blocking mode? If not, it would be otiose to change the mode just to make a test possible. The point is that if he's using blocking mode there up is nothing to test. – user207421 Jan 17 '20 at 23:48
  • Of course, just as I said in the answer, this solution depends on the circumstances. OP talks about implementing unit tests, thus the odds are high that he is in control of the socket. – Michael Beer Jan 17 '20 at 23:51
  • it is a suggestion, just as all other solutions here are. there wont be the solution for all circumstances. overshadowing the `send` function as suggested might be suitable in other circumstances, but will affect every call to send in the linked program. for unit tests e.g. this would be a bad idea, as the scenario if sending to less is only one case to test. fiddling around with the socket itself is more tedious, but can be applied specifically for one dedicated call to `send`. – Michael Beer Jan 17 '20 at 23:56
  • @user207421 Thanks for the hint, updated the answer accordingly. – Michael Beer Jan 18 '20 at 00:36