// This is a test program to check the SCTP implementation:
// 1. Is it usable?
// 2. Does it have quirks such as not notifying poll() correctly.
#include <ext_socket.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <unistd.h>
template<typename T>
static T check (T value, const char * file, int line, const char * what)
{
if (value != (T) -1)
return value;
fprintf (stderr, "%s:%i: %s: %s\n", file, line, what, strerror (errno));
abort();
}
#define CHECK(X) (check (X, __FILE__, __LINE__, #X))
static void socket_pair (int & fd1, int & fd2, int proto)
{
int listn = CHECK (ext_socket (PF_INET, SOCK_STREAM, proto));
CHECK (ext_listen (listn, SOMAXCONN));
sockaddr_in addr;
socklen_t addr_len = sizeof (addr);
CHECK (ext_getsockname (listn, (sockaddr *) &addr, &addr_len));
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
fd1 = CHECK (ext_socket (PF_INET, SOCK_STREAM, proto));
CHECK (ext_connect (fd1, (sockaddr *) &addr, addr_len));
fd2 = CHECK (accept (listn, NULL, 0));
CHECK (ext_close (listn));
}
// The scenario:
// 1. Build a connection.
// 2. Shutdown one end with shutdown(SHUT_WR).
// 3. Propagate shutdown.
// 4. poll() for read should hit.
static bool shutdown_poll_test()
{
int fd1;
int fd2;
socket_pair (fd1, fd2, IPPROTO_SCTP);
CHECK (ext_shutdown (fd1, SHUT_WR));
char c;
int r = CHECK (ext_read (fd2, &c, 1));
assert (r == 0);
CHECK (ext_close (fd2));
pollfd p;
p.fd = fd1;
p.events = POLLIN;
CHECK (ext_poll (&p, 1, 1000));
CHECK (ext_close (fd1));
return (p.revents & POLLIN) != 0;
}
// The scenario:
// 1. Build a connection.
// 2. Abort one end.
// 4. poll() for read should hit.
static bool abort_poll_test()
{
int fd1;
int fd2;
socket_pair (fd1, fd2, IPPROTO_SCTP);
linger l;
l.l_onoff = 1;
l.l_linger = 0;
CHECK (ext_setsockopt (fd2, SOL_SOCKET, SO_LINGER, &l, sizeof (l)));
CHECK (ext_close (fd2));
CHECK (sleep (1));
char c = 0;
int r = ext_write (fd1, &c, 1);
// Solaris 10 gives EPIPE not ECONNRESET here...
assert (r == -1 && (errno == ECONNRESET || errno == EPIPE));
pollfd p;
p.fd = fd1;
p.events = POLLIN;
CHECK (ext_poll (&p, 1, 1000));
CHECK (ext_close (fd1));
return (p.revents & POLLIN) != 0;
}
static bool sctp_usable_test()
{
int fd = ext_socket (PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (fd == -1)
return false;
CHECK (ext_close (fd));
return true;
}
static const char * P (bool b)
{
return b ? "true" : "false";
}
int main (int argc, const char * const * argv)
{
CHECK (alarm (60));
CHECK (signal (SIGPIPE, SIG_IGN));
bool usable = sctp_usable_test();
bool shutdown_poll_guess = true;
bool abort_poll_guess = true;
printf (
"// This file was generated by %s. Do not edit. -*- C++ -*-\n"
"\n"
"#ifndef SCTP_QUIRKS_H\n"
"#define SCTP_QUIRKS_H\n"
"\n"
"#define SCTP_USABLE_AT_BUILD %s\n"
"#define SCTP_SHUTDOWN_POLL_OK %s\n"
"#define SCTP_ABORT_POLL_OK %s\n"
"\n"
"#define SCTP_POLL_OK (SCTP_SHUTDOWN_POLL_OK && SCTP_ABORT_POLL_OK)\n"
"\n"
"#endif\n",
argv[0],
P (usable),
P (usable ? shutdown_poll_test() : shutdown_poll_guess),
P (usable ? abort_poll_test() : abort_poll_guess));
return 0;
}
Archive powered by MHonArc 2.6.19+.