From 390f83ddc0b535eb134d1238576f976c4696c10d Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Sat, 11 Jan 2014 19:02:34 +0000 Subject: [PATCH] Wrote unit tests for sending/receiving IPX packets. --- Makefile | 5 +- manifest.src.txt | 2 + tests/ipx-sendrecv.c | 166 +++++++++++++++++++++++++++++++++++++++++++ tests/test.h | 164 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 tests/ipx-sendrecv.c create mode 100644 tests/test.h diff --git a/Makefile b/Makefile index a066ba9..2c3f0fb 100644 --- a/Makefile +++ b/Makefile @@ -63,16 +63,19 @@ dist: all zip -r ipxwrapper-$(VERSION)-src.zip ipxwrapper-$(VERSION)-src/ rm -r ipxwrapper-$(VERSION)-src/ -test: $(TEST_DLLS) tests/addr.exe tests/socket.exe tests/bind.exe +test: $(TEST_DLLS) tests/addr.exe tests/socket.exe tests/bind.exe tests/ipx-sendrecv.exe cp $(TEST_DLLS) tests/ ./tests/addr.exe ./tests/socket.exe cd tests/; prove bind.t + + ./tests/ipx-sendrecv.exe tests/addr.exe: tests/addr.c src/addr.o tests/bind.exe: tests/bind.c +tests/ipx-sendrecv.exe: tests/ipx-sendrecv.c tests/test.h tests/socket.exe: tests/socket.c tests/%.exe: diff --git a/manifest.src.txt b/manifest.src.txt index 2c19ec5..101fefe 100644 --- a/manifest.src.txt +++ b/manifest.src.txt @@ -58,4 +58,6 @@ directplay-win64.reg tests/addr.c tests/bind.c tests/bind.t +tests/ipx-sendrecv.c tests/socket.c +tests/test.h diff --git a/tests/ipx-sendrecv.c b/tests/ipx-sendrecv.c new file mode 100644 index 0000000..1778ced --- /dev/null +++ b/tests/ipx-sendrecv.c @@ -0,0 +1,166 @@ +/* IPXWrapper - Unit tests + * Copyright (C) 2014 Daniel Collins + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 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. 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, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include + +#include "test.h" + +int main() +{ + { + WSADATA wsaData; + assert(WSAStartup(MAKEWORD(2,2), &wsaData) == 0); + } + + /* Setup sock1... */ + + int sock1 = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX); + assert(sock1 != -1); + + struct sockaddr_ipx addr1; + memset(&addr1, 0, sizeof(addr1)); + addr1.sa_family = AF_IPX; + + assert(bind(sock1, (struct sockaddr*)(&addr1), sizeof(addr1)) == 0); + + { + int addrlen = sizeof(addr1); + assert(getsockname(sock1, (struct sockaddr*)(&addr1), &addrlen) == 0); + } + + { + unsigned long nonblock = 1; + assert(ioctlsocket(sock1, FIONBIO, &nonblock) == 0); + } + + /* Setup sock2... */ + + int sock2 = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX); + assert(sock2); + + struct sockaddr_ipx addr2; + memset(&addr2, 0, sizeof(addr2)); + addr2.sa_family = AF_IPX; + + assert(bind(sock2, (struct sockaddr*)(&addr2), sizeof(addr2)) == 0); + + { + int addrlen = sizeof(addr2); + assert(getsockname(sock2, (struct sockaddr*)(&addr2), &addrlen) == 0); + } + + { + unsigned long nonblock = 1; + assert(ioctlsocket(sock2, FIONBIO, &nonblock) == 0); + } + + /* Send a single packet between the sockets using sendto/recvfrom. */ + + assert(sendto(sock1, test_data_1, sizeof(test_data_1), 0, (struct sockaddr*)(&addr2), sizeof(addr2)) == sizeof(test_data_1)); + + Sleep(50); + + EXPECT_PACKET_FROM(sock2, test_data_1, addr1); + EXPECT_NO_PACKETS(); + + /* Send two packets, then read them out seperately using sendto/recv. */ + + assert(sendto(sock1, test_data_2, sizeof(test_data_2), 0, (struct sockaddr*)(&addr2), sizeof(addr2)) == sizeof(test_data_2)); + assert(sendto(sock1, test_data_2, sizeof(test_data_2), 0, (struct sockaddr*)(&addr2), sizeof(addr2)) == sizeof(test_data_2)); + + Sleep(50); + + EXPECT_PACKET(sock2, test_data_2); + EXPECT_PACKET(sock2, test_data_2); + EXPECT_NO_PACKETS(); + + /* The socket is currently disconnected... */ + + /* ...getpeername should fail */ + + { + struct sockaddr_ipx remote_addr; + int addrlen = sizeof(remote_addr); + + assert(getpeername(sock1, (struct sockaddr*)(&remote_addr), &addrlen) == -1); + assert(WSAGetLastError() == WSAENOTCONN); + } + + /* ...send should fail */ + + assert(send(sock1, test_data_1, sizeof(test_data_1), 0) == -1); + assert(WSAGetLastError() == WSAENOTCONN); + + /* Connect the socket... */ + + assert(connect(sock1, (struct sockaddr*)(&addr2), sizeof(addr2)) == 0); + + /* ...getpeername should work now */ + + { + struct sockaddr_ipx remote_addr; + int addrlen = sizeof(remote_addr); + + assert(getpeername(sock1, (struct sockaddr*)(&remote_addr), &addrlen) == 0); + assert(memcmp(&remote_addr, &addr2, sizeof(addr2)) == 0); + } + + /* ...send should succeed now */ + + assert(send(sock1, test_data_1, sizeof(test_data_1), 0) == sizeof(test_data_1)); + + Sleep(100); + + EXPECT_PACKET_FROM(sock2, test_data_1, addr1); + EXPECT_NO_PACKETS(); + + /* Call connect with an address full of zeroes to "disconnect" it... */ + + { + struct sockaddr_ipx zero_addr; + memset(&zero_addr, 0, sizeof(zero_addr)); + zero_addr.sa_family = AF_IPX; + + assert(connect(sock1, (struct sockaddr*)(&zero_addr), sizeof(zero_addr)) == 0); + } + + /* ...getpeername should fail once more */ + + { + struct sockaddr_ipx remote_addr; + int addrlen = sizeof(remote_addr); + + assert(getpeername(sock1, (struct sockaddr*)(&remote_addr), &addrlen) == -1); + assert(WSAGetLastError() == WSAENOTCONN); + } + + /* ...and so should send */ + + assert(send(sock1, test_data_1, sizeof(test_data_1), 0) == -1); + assert(WSAGetLastError() == WSAENOTCONN); + + /* Clean up */ + + closesocket(sock2); + closesocket(sock1); + + return 0; +} diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 0000000..e578510 --- /dev/null +++ b/tests/test.h @@ -0,0 +1,164 @@ +/* IPXWrapper - Unit tests + * Copyright (C) 2014 Daniel Collins + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 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. 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, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef IPXWRAPPER_TEST_H +#define IPXWRAPPER_TEST_H + +#include +#include + +#define FAIL(fmt, ...) \ +{ \ + fprintf(stderr, "Failure at %s:%d: " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ + exit(1); \ +} + +#define EXPECT_NO_PACKETS(sock) \ +{ \ + char recv_buf[1024]; \ + int r = recv(sock2, recv_buf, sizeof(recv_buf), 0); \ + if(r != -1) \ + { \ + FAIL("Received %d byte packet", r); \ + } \ + if(WSAGetLastError() != WSAEWOULDBLOCK) \ + { \ + FAIL("Received no packets, but WSAGetLastError() is %d", WSAGetLastError()); \ + } \ +} + +#define EXPECT_PACKET(sock, data) \ +{ \ + char buf[1024]; \ + int r = recv(sock, buf, sizeof(buf), 0); \ + if(r == -1) \ + { \ + FAIL("Received no packets, WSAGetLastError = %d", WSAGetLastError()); \ + } \ + else if(r != sizeof(data)) \ + { \ + FAIL("Received %d byte packet (expected %d)", r, (int)(sizeof(data))); \ + } \ + if(memcmp(buf, data, sizeof(data)) != 0)\ + { \ + FAIL("Received packet with wrong payload"); \ + } \ +} + +#define EXPECT_PACKET_FROM(sock, data, src) \ +{ \ + char buf[1024]; \ + struct sockaddr_ipx addrbuf; \ + int addrlen = sizeof(addrbuf); \ + int r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)(&addrbuf), &addrlen); \ + if(r == -1) \ + { \ + FAIL("Received no packets, WSAGetLastError = %d", WSAGetLastError()); \ + } \ + else if(r != sizeof(data)) \ + { \ + FAIL("Received %d byte packet (expected %d)", r, (int)(sizeof(data))); \ + } \ + if(memcmp(buf, data, sizeof(data)) != 0)\ + { \ + FAIL("Received packet with wrong payload"); \ + } \ + if(addrlen != sizeof(struct sockaddr_ipx)) \ + { \ + FAIL("Received packet, but addrlen is %d bytes (expected %d)", addrlen, (int)(sizeof(struct sockaddr_ipx))); \ + } \ + if(memcmp(&addrbuf, &src, sizeof(struct sockaddr_ipx)) != 0) \ + { \ + FAIL("Received packet, but the source address is wrong"); \ + } \ +} + +static const char test_data_1[] = { + 0x57, 0x65, 0x27, 0x72, 0x65, 0x20, 0x4b, 0x6e, 0x69, 0x67, 0x68, 0x74, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x6f, 0x75, + 0x6e, 0x64, 0x20, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x2e, + + 0x57, 0x65, 0x20, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x77, 0x68, 0x65, + 0x6e, 0x65, 0x27, 0x65, 0x72, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, + 0x61, 0x62, 0x6c, 0x65, 0x2e, + + 0x57, 0x65, 0x20, 0x64, 0x6f, 0x20, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, + 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x6f, 0x72, 0x75, + 0x73, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x73, + + 0x57, 0x69, 0x74, 0x68, 0x20, 0x66, 0x6f, 0x6f, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x20, 0x69, 0x6d, 0x70, 0x65, 0x63, 0x63, 0x61, 0x62, 0x6c, 0x65, + 0x2e, + + 0x57, 0x65, 0x20, 0x64, 0x69, 0x6e, 0x65, 0x20, 0x77, 0x65, 0x6c, 0x6c, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x61, 0x6d, + 0x65, 0x6c, 0x6f, 0x74, 0x2e, + + 0x57, 0x65, 0x20, 0x65, 0x61, 0x74, 0x20, 0x68, 0x61, 0x6d, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x6a, 0x61, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, + 0x70, 0x61, 0x6d, 0x20, 0x61, 0x20, 0x6c, 0x6f, 0x74, 0x2e, + + 0x57, 0x65, 0x27, 0x72, 0x65, 0x20, 0x4b, 0x6e, 0x69, 0x67, 0x68, 0x74, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x6f, 0x75, + 0x6e, 0x64, 0x20, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x2e, + + 0x4f, 0x75, 0x72, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x73, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x69, 0x64, 0x61, 0x62, 0x6c, 0x65, + 0x2c, + + 0x42, 0x75, 0x74, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, 0x67, 0x69, 0x76, + 0x65, 0x6e, 0x20, 0x72, 0x68, 0x79, 0x6d, 0x65, 0x73, + + 0x54, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x71, 0x75, 0x69, + 0x74, 0x65, 0x20, 0x75, 0x6e, 0x73, 0x69, 0x6e, 0x67, 0x61, 0x62, 0x6c, + 0x65, 0x2e, + + 0x57, 0x65, 0x27, 0x72, 0x65, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x20, + 0x6d, 0x61, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x61, 0x6d, 0x65, 0x6c, + 0x6f, 0x74, 0x2e, + + 0x57, 0x65, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x61, 0x70, 0x68, 0x72, 0x61, + 0x67, 0x6d, 0x20, 0x61, 0x20, 0x6c, 0x6f, 0x74, 0x2e +}; + +static const char test_data_2[] = { + 0x49, 0x6e, 0x20, 0x77, 0x61, 0x72, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, + 0x20, 0x74, 0x6f, 0x75, 0x67, 0x68, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, + 0x62, 0x6c, 0x65, 0x2c, + + 0x51, 0x75, 0x69, 0x74, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x66, 0x61, + 0x74, 0x69, 0x67, 0x61, 0x62, 0x6c, 0x65, 0x2e, + + 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x6f, 0x75, 0x72, 0x20, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x20, 0x77, 0x65, 0x20, 0x73, 0x65, + 0x71, 0x75, 0x69, 0x6e, 0x20, 0x76, 0x65, 0x73, 0x74, 0x73, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, + 0x74, 0x65, 0x20, 0x43, 0x6c, 0x61, 0x72, 0x6b, 0x20, 0x47, 0x61, 0x62, + 0x6c, 0x65, 0x2e, + + 0x49, 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, 0x62, 0x75, 0x73, 0x79, 0x20, + 0x6c, 0x69, 0x66, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x61, 0x6d, 0x65, + 0x6c, 0x6f, 0x74, 0x2e, + + 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x75, + 0x73, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x61, 0x6d, 0x20, + 0x61, 0x20, 0x6c, 0x6f, 0x74, 0x2e +}; + +#endif /* !IPXWRAPPER_TEST_H */