[omniORB] Lost one-way calls

Jan Lessner jan@c-lab.de
Fri, 23 Apr 1999 09:55:14 +0200


This is a multi-part message in MIME format.

--------------33C773A12C0B
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi omniORB'ers
I discovered vanishing oneway-calls already some months ago and we made
some really deep-going invenstigations on that. The reason we found was
somewhat wired and (fortunately!!) not a problem of omniORB but of
sockets in general. Well, except that omniORB automaticallz shuts down
idle connections sometimes which the problem is related to. I'm pretty
shure that you ran into exactly the same problems.

If a receiver application shuts down its incoming socket connection, a
sender is still able to sned at least *one* small package of data within
a varying time period of about 10 to 90 seconds WITHOUT getting notified
of any transmission errors. In fact we made the experience that we could
send *exactly* one data package (not regarding its size) without any
problems while an immediatly following send operation fails as expected.

I know this sounds a little suspicious but I think we really tracked it
down as far as possible. We found the same behaviour on Solaris and on
Windows NT. In the attachment you can find two minimal test programs for
sender and receiver which varified this effect at least in our network.
The only solution we found for this problem was a really nasty
work-around making clients and servers exchange there idle check periods
and run two-way test calls time after time. I.e. I'm afraid I've no
general advice to make. Nevertheless, I hope it helps.

Regards,
Jan Lessner, C-LAB

--------------33C773A12C0B
Content-Type: text/plain; charset=us-ascii; name="socksend.cpp"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="socksend.cpp"

#ifdef _WIN32
#include <windows.h>
#include <io.h>
#define strncasecmp _strnicmp
#define usleep(t) Sleep(t / 1000)
#else
#include <stdlib.h>
#include <unistd.h>     /* getuid() */
#include <sys/socket.h> /* socket() etc. */
#include <netinet/in.h> /* IPPROTO_TCP */
#include <netdb.h>      /* gethostbyname */
#include <errno.h>      /* errno */
#define closesocket(s) close(s)
extern "C" 
{
  int usleep(unsigned int useconds);
};
#endif

#include <iostream.h>
#include <stdio.h>     /* vsprintf() */
#include <string.h>

int main(int argc, char *argv[])
{
  int portno = (argc > 1) ? atoi(argv[1]) : 8080;
  char *host = (argc > 2) ? argv[2] : "bolg";
  int state;
  int socket;
  struct sockaddr_in server;

#ifdef _WIN32
  WSADATA wsadata;
  WORD wVersionRequested = MAKEWORD(1, 1);

  if (state = WSAStartup(wVersionRequested, &wsadata)) {
    printf("WSAStartup() failed\n");
	return 1;
  }
#endif

  memset((char *)&server, 0, sizeof(server));
  struct hostent *hp = gethostbyname(host);
  if (hp) {
    memmove((char *)&server.sin_addr, hp->h_addr, hp->h_length);
    server.sin_family = hp->h_addrtype;
    server.sin_port = (unsigned short)htons(portno);
  }
  else {
    cerr << "no host" << endl;
  }
  
  /*
   * Open socket connection
   */
  if ((socket = ::socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    cerr << "socket" << endl;
    return -1;
  }
  setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
  if (connect(socket, (struct sockaddr *)&server, sizeof(server)) < 0) {
    cerr << "connect" << endl;
    return -1;
  }
  
  /*
   * Send data
   */
  char data[256];
  sprintf(data, "this is data");
  for (int i = 0; i < 10; i++) {
    cerr << "send " << strlen(data) << " ... " << flush;
    if (::send(socket, data, strlen(data), 0) == -1) {
      cerr << "send error" << endl;
    }
    cerr << "done" << endl;
    usleep(5000000);
  }
  cerr << "bye" << endl;
  closesocket(socket);
  return 0;
}

--------------33C773A12C0B
Content-Type: text/plain; charset=us-ascii; name="sockrecv.cpp"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="sockrecv.cpp"

#ifdef _WIN32
#include <windows.h>
#include <io.h>
#define strncasecmp _strnicmp
#else
#include <stdlib.h> /* atoi() */
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h> /* read() */
#include <netinet/in.h> /* IPPROTO_TCP */
#include <macros.h> /* min() */
#define closesocket(s) close(s)
#endif
#include <stdio.h>
#include <string.h>

#include <iostream.h>
#include <fstream.h>

char *code(char *val, char *buf, int buflen)
{
  /*
   * In worst case the coded data is three times as long as the original
   * by the coding of %XX for unprintable and special characters
   */
  if (strlen(val)*3 + 1 > buflen) {
    buf = new char[strlen(val)*3 + 1];
  }
  char *w, *r;
  for (r = val, w = buf; *r; r++, w++) {
    switch(r[0]) {
    case ' ':
      w[0] = '+';
      break;
    default:
      if (r[0] >= '!' && r[0] <= '~') {
	w[0] = r[0];
	break;
      }
      // fall through
    case '%':
    case '&':
    case '+':
      w[0] = '%';
      sprintf(&w[1], "%02X", r[0]);
      w+=2;
    }
  }
  return buf;
}

void decode(char *buf)
{
  int r, w;
  unsigned int val;
  for (r = w = 0; buf[r]; w++, r++) {
    switch(buf[r]) {
    case '%':
      sscanf(&buf[r+1], "%2X", &val);
      buf[w] = (char)val;
      r+=2;
      break;
    case '\r':
      w--;
      break;
    case '+':
      buf[w] = ' ';
      break;
    default:
      buf[w] = buf[r];
      break;
    }
  }
  buf[w] = 0;
}

void split(char *buf)
{
  printf("%s\n", buf);
  char *cut;
  while(cut = strchr(buf, '=')) {
    *cut = 0;
    decode(buf);
    printf("%s = ", buf);
    buf = cut+1;
    cut = strchr(buf, '&');
    if (cut)
      *cut = 0;
    decode(buf);
    printf("%s\n", buf);
    if (!cut)
      break;
    else
      buf = cut+1;
  }
}

int main(int argc, char *argv[])
{
  int state;
  int s;
  int portno = (argc > 1) ? atoi(argv[1]) : 8080;
  struct sockaddr_in name;
  int err;
#ifdef _WIN32
  WSADATA wsadata;
  WORD wVersionRequested = MAKEWORD(1, 1);

  if (err = WSAStartup(wVersionRequested, &wsadata)) {
    printf("WSAStartup() failed\n");
	return 1;
  }
#endif

  name.sin_family = AF_INET;
  name.sin_addr.s_addr = INADDR_ANY;
  name.sin_port = htons(portno);
  
  s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (s == -1) {
    printf("socket() failed\n");
    return 1;
  }
  int valtrue = 1;
  state = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&valtrue, sizeof(int));
  if (state == -1) {
    printf("setsockopt() failed\n");
    return 1;
  }
  state = bind(s, (struct sockaddr *)&name, sizeof(name));
  if (state == -1) {
    printf("bind() failed\n");
    return 1;
  }
  state = listen(s, 5);
  if (state == -1) {
    printf("listen() failed\n");
    return 1;
  }

  struct sockaddr sadr;
  int addrlen = sizeof(sadr);
  printf("listening at port %d\n", portno);
  while(1) {
    int fd = accept(s, &sadr, &addrlen);
    if (fd == -1) {
      printf("accept() failed\n");
      return 1;
    }
    char rbuf[256];
    int rx;
    while(1) {
      cout << "recv... " << flush;
      rx = recv(fd, rbuf, sizeof(rbuf), 0);
      if (rx <= 0) {
	cout << "receive error" << endl;
	break;
      }
      cout << rx << endl;
      break;
    }
    cerr << "closing" << endl;
    shutdown(fd, 2);
    closesocket(fd);
  }
  return 0;
}


--------------33C773A12C0B--