/* I wrote this program to test how feasible it was to fake a slow
 * network connection by twiddling SO_RCVBUF.  The idea is to read
 * data from the socket relatively slowly, but keep SO_RCVBUF small
 * from the beginning of the connection to make sure that the remote
 * side's TCP is aware that (a) you really haven't read those 24K of
 * data their application program has written to its output buffer, but
 * (b) you are reading them, just very slowly, so don't hang up.  It shows
 * that it works reasonably well, at least on Linux 2.4.
 *
 * In a FoRKpost in 2001, Dave Long suggested that this was a possible
 * alternative handling for things like the DUL and RBL --- rather
 * than simply rejecting mail from blacklisted hosts, you could simply
 * accept it very slowly, making you costly to deliver spam to.
 *
 * On my Linux 2.4 box, attempting to set SO_RCVBUF to 1 actually sets
 * it to 256, which is probably good enough; the connection sockets do
 * indeed inherit SO_RCVBUF from their server socket; and 256 bytes of
 * buffer space actually means 96 or 192 bytes of TCP data, which
 * tcpdump says is reflected in the window sizes advertised in TCP,
 * even as early as the SYN-ACK packet when the connection opens.  */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

void err(char *format, ...) {
  va_list x;
  va_start(x, format);
  vfprintf(stderr, format, x);
  if (errno) {fprintf(stderr, ": "); perror(""); }
  va_end(x);
  exit(1);
}

int main(int argc, char **argv) {
  int serversocket, connectionsocket;
  struct sockaddr_in me;
  struct sockaddr_in them;
  int themlen;
  int one = 1;
  int bufsiz;
#define charbufsiz 4096
  char charbuf[charbufsiz];
  int recvsiz;
  int fucking_triplicate;

  serversocket = socket(PF_INET, SOCK_STREAM, 0);
  if (serversocket < 0) err("socket");

  if (setsockopt(serversocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))<0)
    err("setsockopt with SO_REUSEADDR");

  if (setsockopt(serversocket, SOL_SOCKET, SO_RCVBUF, &one, sizeof(one))<0)
    err("setsockopt with SO_RCVBUF");
  fucking_triplicate = sizeof(bufsiz);
  if (getsockopt(serversocket, SOL_SOCKET, SO_RCVBUF, &bufsiz, 
                 &fucking_triplicate)
      < 0)
    err("getsockopt with SO_RCVBUF");
  printf("Receive buffer size on server socket is %d bytes\n", bufsiz);

  me.sin_family = AF_INET;
  me.sin_port = htons(5100);  /* "sloo" -- slow */
  me.sin_addr.s_addr = INADDR_ANY;
  if (bind(serversocket, &me, sizeof(me)) < 0) err("bind");
  if (listen(serversocket, 5) < 0) err("listen");
  
  connectionsocket = accept(serversocket, &them, &themlen);
  fucking_triplicate = sizeof(bufsiz);
  if (getsockopt(connectionsocket, SOL_SOCKET, SO_RCVBUF, &bufsiz,
                 &fucking_triplicate)
      < 0)
    err("getsockopt with SO_RCVBUF on connection socket");
  printf("Receive buffer size on connection socket is %d bytes\n", bufsiz);
  for (;;) {
    recvsiz = recv(connectionsocket, charbuf, charbufsiz, 0);
    if (recvsiz == 0) {
      printf("Received end of file on socket; exiting.\n");
      exit(0);
    }
    printf("%d bytes\n", recvsiz);
    sleep(1);
  }
}


Reply via email to