X-Recipient: archive-cygwin AT delorie DOT com DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:content-type :content-transfer-encoding:mime-version; q=dns; s=default; b=GEV G8Ep5B7Aa2AktrDweT9QTp10DGajMatZ9ri+JocwUG4rDvjnDsvTgGeIFYmEzfx2 D/3MmWBPz+8b/OqwJV6uZcGCcl7JwSRIg+asJcwOoz7+yuZAZtXKK7/JBbHvpGmK KkSxIXUsW+wJjdD0cjp+taXrvA68tNc1Nsdf8C40= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:content-type :content-transfer-encoding:mime-version; s=default; bh=BRiqw8FHL 69VykoR4x6FfPIcwfA=; b=UJYn89CsOIHoWEREplx2yDTqQqAety0rZFm37laYI BVkHYquaR5ucSOvaZhEpF/pMhBH1T2ybpb6BI4ekXjqFxvi3dqFcsgI22TdG1xSk ANaytukLLPllk9Wj3csGfYSobWn8kPFyBjOrqq/n4Sf3ie8yX8OtscALY9TpQAHu vY= Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.8 required=5.0 tests=AWL,BAYES_00,CYGWIN_OWNER_BODY,GIT_PATCH_2,KAM_INFOUSMEBIZ,KAM_LAZY_DOMAIN_SECURITY,KAM_SHORT,RCVD_IN_DNSWL_NONE autolearn=no version=3.3.2 spammy=compliment, H*MI:local, firewall, connections X-HELO: mailrelay.dillinger.de From: "PAULUS, Raimund, TI-ABN" To: "cygwin AT cygwin DOT com" Subject: Re: AW: RPC clnt_create() adress already in use Date: Fri, 29 Dec 2017 13:30:33 +0000 Message-ID: <59D90AF8D70E9740907BACDE2BCB520836CCDAED@RESW102.resdom01.local> Content-Type: text/plain; charset="iso-8859-1" MIME-Version: 1.0 X-IsSubscribed: yes Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by delorie.com id vBTDUpNi003085 Hello Mark, you wrote: "Just so I understand more fully: you are compiling with those options on Cygwin?" Answer: yes you wrote: "The idea there is to use a different port on each run of the program. If you're looping around and reaching that code again with port==0, then yes you'll get the same port number each time because getpid() is not changing." Answer: That's correct. But you can see, the following bind() is embedded in a loop: if the bind() would work correctly, it would deliver res < 0 because errno = EADDRINUSE. In this case the port would be incremented and the next loop pass is made. This would happen till an unused port is found or all ports are used. I think, the problem here is, bind() does not deliver the correct return value. Therefore my two approaches. you wrote: "I don't know enough to set up an RPC test bed to try your client program locally. *Unless* it's sufficient to run your client program and aim at the local machine even though it has no RPC server listening. If that would demonstrate your issue, let me know and I'll have another look. Otherwise, I would need to set up an RPC server on my Cygwin machine. If you've done that on your Cygwin machine, what are the steps? I think I can follow Unix-style instructions but will have to allow for Windows Firewall so if you've done this already on Cygwin your procedure would help a lot." Answer: To make a connection the RPC server must be running. My RPC server is running on a linux machine since several years. I know, it is reliable and i would not have an additional possible error source. I didn't do anything with the Windows firewall. I found a simple RPC example here: https://www.unf.edu/~sahuja/cnt5505/rpcexample.html. I did some minimal changes to better show the problem (client uses tcp instead udp, connection establishment in a loop). I could reproduce the problem in this example. Here the sources and the compile directives: date.h ================================ /* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _DATE_H_RPCGEN #define _DATE_H_RPCGEN #include #ifdef __cplusplus extern "C" { #endif #define DATEPROG 0x3012225 #define DATEVERS 1 #if defined(__STDC__) || defined(__cplusplus) #define BINDATE 1 extern long * bindate_1(void *, CLIENT *); extern long * bindate_1_svc(void *, struct svc_req *); extern int dateprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); #else /* K&R C */ #define BINDATE 1 extern long * bindate_1(); extern long * bindate_1_svc(); extern int dateprog_1_freeresult (); #endif /* K&R C */ #ifdef __cplusplus } #endif #endif /* !_DATE_H_RPCGEN */ date_client.c =================== /* * Please do not edit this file. * It was generated using rpcgen. */ #include /* for memset */ #include "date.h" /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 25, 0 }; long * bindate_1(void *argp, CLIENT *clnt) { static long clnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call (clnt, BINDATE, (xdrproc_t) xdr_void, (caddr_t) argp, (xdrproc_t) xdr_long, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } date_svc.c ================== /* * Please do not edit this file. * It was generated using rpcgen. */ #include "date.h" #include #include #include #include #include #include #include #ifndef SIG_PF #define SIG_PF void(*)(int) #endif static void dateprog_1(struct svc_req *rqstp, register SVCXPRT *transp) { union { int fill; } argument; char *result; xdrproc_t _xdr_argument, _xdr_result; char *(*local)(char *, struct svc_req *); switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); return; case BINDATE: _xdr_argument = (xdrproc_t) xdr_void; _xdr_result = (xdrproc_t) xdr_long; local = (char *(*)(char *, struct svc_req *)) bindate_1_svc; break; default: svcerr_noproc (transp); return; } memset ((char *)&argument, 0, sizeof (argument)); if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { svcerr_decode (transp); return; } result = (*local)((char *)&argument, rqstp); if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) { svcerr_systemerr (transp); } if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { fprintf (stderr, "%s", "unable to free arguments"); exit (1); } return; } int main (int argc, char **argv) { register SVCXPRT *transp; pmap_unset (DATEPROG, DATEVERS); transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf (stderr, "%s", "cannot create tcp service."); exit(1); } if (!svc_register(transp, DATEPROG, DATEVERS, dateprog_1, IPPROTO_UDP)) { fprintf (stderr, "%s", "unable to register (DATEPROG, DATEVERS, udp)."); exit(1); } transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf (stderr, "%s", "cannot create tcp service."); exit(1); } if (!svc_register(transp, DATEPROG, DATEVERS, dateprog_1, IPPROTO_TCP)) { fprintf (stderr, "%s", "unable to register (DATEPROG, DATEVERS, tcp)."); exit(1); } svc_run (); fprintf (stderr, "%s", "svc_run returned"); exit (1); /* NOTREACHED */ } dateproc.c ======================= /*********************************************************************/ /* dateproc.c - remote procedures; called by server stub */ #include #include #include #include "date.h" /* return the binary date and time */ /* In Linux: long * bindate_1_svc(void* arg1, struct svc_req *arg2) { */ /* In Dec Unix: long * bindate_1() { */ long * bindate_1_svc(void* arg1, struct svc_req *arg2) { static long timeval; /* must be static */ timeval = time((long *) 0); return (&timeval); } rdate.c ================================= /****************************************************************/ /* rdate.c - client program for remote date service */ #include #include #include #include #include #include "date.h" int main(int argc, char *argv[]) { CLIENT *cl; char *server; long *lres; if (argc != 2) { fprintf(stderr, "usage: %s hostname\n", argv[0]); exit(1); } server = argv[1]; int i; for(i=0; i< 100; i++) { /* create client handle */ if ((cl = clnt_create(server, DATEPROG, DATEVERS, "tcp")) == NULL) { /* couldn't establish connection with server */ printf("can't establish connection with host %s\n", server); exit(2); } /* first call the remote procedure bindate() */ if (( lres = bindate_1(NULL, cl)) == NULL){ printf(" remote procedure bindate() failure\n"); exit(3); } printf("Loop %d: time on host %s = %ld == %s", i, server, *lres, ctime(lres)); clnt_destroy(cl); /* done with handle */ sleep(1); } return 0; } **************************************************** Commands: gcc -c date_clnt.c gcc -c date_svc.c gcc -c dateproc.c gcc -c rdate.c gcc -o client date_clnt.o rdate.o gcc -o server date_svc.o dateproc.o for Cygwin gcc -I/usr/include/tirpc -c date_clnt.c gcc -I/usr/include/tirpc -c date_svc.c gcc -I/usr/include/tirpc -c dateproc.c gcc -I/usr/include/tirpc -c rdate.c gcc -o client date_clnt.o rdate.o -ltirpc gcc -o server date_svc.o dateproc.o -ltirpc I hope this will help Raimund -----Ursprüngliche Nachricht----- Von: cygwin-owner AT cygwin DOT com [mailto:cygwin-owner AT cygwin DOT com] Im Auftrag von Mark Geisert Gesendet: Mittwoch, 27. Dezember 2017 10:39 An: cygwin AT cygwin DOT com Betreff: Re: RPC clnt_create() adress already in use Hi Raimund, Comments embedded below... PAULUS, Raimund, TI-ABN wrote: > Hello Mark, > > in my earlier tests the lib and header files for tirpc was still there from the Cygwin-installation. I think, this could influence the results of the tests. > Therefore i removed these files. From now on i used only the downloaded files from sourceforge (https://sourceforge.net/projects/libtirpc/files/libtirpc/). I tested libtirpc-0.3.2, libtirpc-1.0.1 and libtirpc-1.0.2. The results for all releases are the same. > > I needed the following sources: > > auth_none.c, auth_unix.c, authunix_prot.c, bindresvport.c, clnt_bcast.c, clnt_dg.c, clnt_generic.c, clnt_perror.c, clnt_vc.c, debug.c, getnetconfig.c, getnetpath.c, mt_misc.c, rpc_callmsg.c, rpc_commondata.c, rpc_generic.c, rpc_prot.c, rpcb_clnt.c, rpcb_prot.c, xdr.c, xdr_array.c, xdr_float.c, xdr_reference.c, xdr_rec.c, xdr_mem.c > > I had to change the following (already mentioned earlier): > > clnt_bcast.c > (because POLLRDNORM, POLLRDBAND are already defined in /usr/include/sys/poll.h) : > > --> #ifndef POLLRDNORM > # define POLLRDNORM 0x040 /* Normal data may be read. */ > # define POLLRDBAND 0x080 /* Priority data may be read. */ > --> #endif Not only does /usr/include/sys/poll.h already define them, they're defined with different values. Could be a red flag or a red herring; don't know yet. > xdr.h (typedefs where missed): > > #include > > --> typedef __uint64_t u_quad_t; > --> typedef __int64_t quad_t; > > > My compile-flags: -D_GNU_SOURCE -D__GLIBC__ -D__linux__ Just so I understand more fully: you are compiling with those options on Cygwin? > If i build my test program with the sources above, the behavior is the same as with the Cygwin-libtirpc: the first RPC-connection is ok, the next call to clnt_create() delivers the error EADDRINUSE. > > The test program on a Linux-box works perfectly. With "netstat -n" you can see each connection from the client to the server creates a new pair of ports. On the server-side the pair is always the same (ports 111, 907). On the client-side however the ports differ from one connection to the other. When the connections are closed the ports remain in state TIME_WAIT. After a while they disappear. > > If the RPC-client (Cygwin) is running on a Windows-box, "netstat -n" shows the pair of ports for the first connection. The next connection attempt (clnt_create()) delivers: EADDRINUSE. > > In the sources you can see the following: > > clnt_create() calls the function bindresvport_sa() (in bindresvport.c). Here the port for the connection is determined: > > if (port == 0) { > port = (getpid() % NPORTS) + STARTPORT; } The idea there is to use a different port on each run of the program. If you're looping around and reaching that code again with port==0, then yes you'll get the same port number each time because getpid() is not changing. > > and the socket is bound to the port: > > res = bind(sd, sa, salen); > > If this part is executed multiple times (loop) the port is always the same. The function bind() doesn't deliver an error (res = 0, maybe bind() doesn't work correctly?). Therefore the error is not detected until the call of connect() in function clnt_vc_create() (in clnt_vc.c). But here you can not correct the port. > > I tried the following: > > The call of setsockopt(., SO_REUSEADDR, .) before bind() doesn't change anything. The error still occurs. > > I found 2 approaches to avoid the error: > > 1. Before the call to bind() set the port to 0 (port = 0). The following bind() searches an unused port. > > 2. Set the port to 0 (port = 0). Do not call bind(). Later the call to connect() searches an unused port. > > I tested the two methods and the behavior was the same as the Linux-client. It obviously works correctly. But i'm not a network specialist and i don't know, if it's the best solution for the problem. > > > Subsequently I downloaded the Cygwin-sources for libtirpc-0.3.2 and libtirpc-1.0.1. And here again, with the changes mentioned in the two approaches the RPC-connection works perfectly. The only difference her is: a connection does not create a pair of ports but only a single port (netstat -n). I must compliment you; you are being very specific and detailed about what you're doing on the client end of the RPC connection. But as I said in my last email, I don't know specifics about RPC implementation; I sort of know generally what RPC can do. I don't know enough to set up an RPC test bed to try your client program locally. *Unless* it's sufficient to run your client program and aim at the local machine even though it has no RPC server listening. If that would demonstrate your issue, let me know and I'll have another look. Otherwise, I would need to set up an RPC server on my Cygwin machine. If you've done that on your Cygwin machine, what are the steps? I think I can follow Unix-style instructions but will have to allow for Windows Firewall so if you've done this already on Cygwin your procedure would help a lot. Thanks, ..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