Hello Mark Geisert,

i have an other testprogram making the connections not using RPC. Instead it 
uses socket-connections directly (without setsockopt()). The operations in the 
program are  the same as in my RPC-testprogram.
But now the program works perfectly (in Cygwin 1.5.18 and Cygwin 2.5.1). There 
are no errors. 
Therefore I think the cause for the error in my RPC-testprogram is not the 
socket-handling but the RPC-handling in libtirpc. But I have no idea to control 
the RPC-handling to avoid the error.

Raimund Paulus

Source of socket-testprogram:

/*=================*/
/*  Include-Files  */
/*=================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <libgen.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*=======================*/ 
/*  global definitions                       */
/*=======================*/ 
// max. nr. of connection attempts
#define CONNECT_MAX                 (int)3
// waittime for connection
#define CONNECT_WAITTIME      (unsigned int)5

char host_ip[] = "128.2.9.1";  // IP host
int svc_port    = 49154;         // port-nr. for service

char local_errmsg[512];

/*===============*/
/*  prototyping              */
/*===============*/
// function for open a connection
int SVC_Open(void);
// function for close a connection
int SVC_Close(int fd_svc);

/*============================*/
/*  main-program                                     */
/*============================*/
int main(int argc, char *argv[])
{
int retval = 0; 
int sleeptime = 0;
int fd_sock = 0;                // socket descriptor

  // read sleep-Time
  if(argc < 2)
  {
    printf("no input for sleep-Time --> default\n");
    sleeptime = 10;
  }
  else
  {
    char *endptr;
    errno = 0;
    sleeptime = (int)strtol(argv[1], &endptr, 10);
    if ( (errno == ERANGE && (sleeptime == LONG_MAX || sleeptime == LONG_MIN))
         || (errno != 0 && sleeptime == 0))
    {
      fprintf(stderr, "input for sleeptime (%s) invalid: %s\n",
                      argv[1], strerror(errno));
      exit(1);
    }
  }

  printf("sleep-Time = %d \n", sleeptime);

  // loop for 20 connection 
  int i;
  for(i=0; i<20; i++)
  {
    fd_sock = SVC_Open();
    if(retval < 0)
      break;

    printf("connection nr. %d established \n", i+1);
    sleep(1);

    retval = SVC_Close(fd_sock);
    if(retval < 0)
      break;

    printf("connection closed\n");

    printf("wait for %d sec.\n", sleeptime);
    sleep(sleeptime);
  }
    
  if(retval < 0)
    fprintf(stderr, "%s\n", local_errmsg);

  return(0);
}

int SVC_Open(void)
{
int nr_connects = 0;    // nr of connection attempts
int retval = 0;
struct sockaddr_in server_address;
int fd_svc = -1;                // socket descriptor

  // get socket descriptor
  errno = 0;
  fd_svc = socket (AF_INET, SOCK_STREAM, 0);
  if (fd_svc < 0)
  {
    sprintf(local_errmsg, "socket(): %s", strerror(errno));
    return(-1);
  }

  // initializing struct
  bzero ((char *) &server_address, sizeof (server_address));
  server_address.sin_family = AF_INET;
  server_address.sin_addr.s_addr = inet_addr(host_ip);
  server_address.sin_port = htons(svc_port);
  errno = 0;

  // establish connection; if error --> retry max. CONNECT_MAX times
  for(nr_connects = 0; nr_connects < CONNECT_MAX; nr_connects++)
  {
    printf("connection attempt nr. %d\n",nr_connects+1);
    retval = connect (fd_svc,
                     (struct sockaddr *) &server_address,
                     sizeof (server_address));
    if (retval < 0)
    {
      sprintf(local_errmsg, "connect(): %s", strerror(errno));
      if(nr_connects < CONNECT_MAX)
      {
        fprintf(stderr, "%s\n", local_errmsg);
        sleep(CONNECT_WAITTIME);
      }
      continue;
    }
    else
      break;
  } // end for()

  // error handling (no success)
  if (retval < 0)
  {
    close(fd_svc);
    return(retval); 
  }
  else
    return(fd_svc);
}


int SVC_Close(int fd_svc)
{
int retval = 0;

  if(fd_svc > 0)
  {
    errno = 0;
    retval = close(fd_svc);
    if(retval < 0)
      sprintf(local_errmsg, "close(): %s", strerror(errno));
  }
 
  return(retval); 
}



-----Ursprüngliche Nachricht-----
Von: cygwin-ow...@cygwin.com [mailto:cygwin-ow...@cygwin.com] Im Auftrag von 
Mark Geisert
Gesendet: Sonntag, 24. September 2017 11:49
An: cygwin@cygwin.com
Betreff: Re: RPC clnt_create() adress already in use

PAULUS, Raimund, TI-ABN wrote:
> In our environment we have a Linux-Server and several Windows-PCs (Windows XP 
> SP3, in the past Windows NT too). On the Linux-Server RPC-Services (Remote 
> Procedure Call) are running, one service for one Windows-PC each. To build 
> the RPC-clients on the Windows-boxes, I used Cygwin 1.5.18 and actually 
> Cygwin 2.5.1 (because we now have Windows 7 too).
>
> The RPC-Client (*.exe) on the Windows-box is started at any time by hand, 
> establishes a connection to the server (clnt_create), executes a few calls to 
> the server (clnt_call), closes the connection (clnt_destroy) and exits. The 
> time-interval between the program starts can be 10 seconds up to 2 minutes.
>
> This worked over many years without any error (Cygwin 1.5.18).
> Now I upgraded to Cygwin 2_5_1 (libtirpc instead librpc) and there are 
> problems. Sometimes the RPC-Client cannot establish a connection to the 
> server. The error message from clnt_spcreateerror():
>
> Remote system error - Address already in use
>
> I think it is "EADDRINUSE".

I can only answer generally as I haven't tried your testcase and don't know 
anything about either RPC library on Cygwin.  If EADDRINUSE is the error you're 
getting, it might be due to a difference between libtirpc and the older librpc. 
When a program binds a specific address and port to a socket, uses the socket 
then later closes it, the system keeps the <address, port> tuple in a "locked" 
state until enough time has passed for the other end of the connection to 
notice the connection's been closed.  During that time, attempting to bind() 
with the same address and port will result in EADDRINUSE.  It's a TCP/IP safety 
mechanism.

If you wish to override that behavior, you set a specific option SO_REUSEADDR 
on the socket with setsockopt() before you issue the bind().  Perhaps libtirpc 
is not doing that, though librpc was doing that.  Only way to know is to 
examine the source to both libraries.  It's possible an strace of a broken 
session compared to an strace of a working session might shed some light.

..mark


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

Reply via email to