public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: "PAULUS, Raimund, TI-ABN" <Raimund.Paulus@dillinger.biz>
To: "cygwin@cygwin.com" <cygwin@cygwin.com>
Subject: Re: RPC clnt_create() adress already in use
Date: Tue, 30 Jan 2018 10:07:00 -0000	[thread overview]
Message-ID: <59D90AF8D70E9740907BACDE2BCB520836E01220@RESW102.resdom01.local> (raw)

[-- Attachment #1: Type: text/plain, Size: 3510 bytes --]

Hi Mark,

in my email (https://sourceware.org/ml/cygwin/2017-12/msg00194.html) i described 2 approaches. I prefer  nr 1.
Here the part of the source in bindresvport.c:
------------------------------------------------------------------------------------------------------------------
        if (port == 0) {
                port = (getpid() % NPORTS) + STARTPORT;
        }
        res = -1;
        errno = EADDRINUSE;

/* fix for bind() */
port = 0;
                again:
        for (i = 0; i < nports; ++i) {
                *portp = htons(port++);
                 if (port > endport)
                        port = startport;
                res = bind(sd, sa, salen);
                if (res >= 0 || errno != EADDRINUSE)
                        break;
        }
        if (i == nports && startport != LOWPORT) {
            startport = LOWPORT;
            endport = STARTPORT - 1;
            nports = STARTPORT - LOWPORT;
            port = LOWPORT + port % (STARTPORT - LOWPORT);
            goto again;
        }
        mutex_unlock(&port_lock);

        return (res);
}
-------------------------------------------------------------------------------------------------------

This causes bind() to search an unused port. I use libtirpc with this fix since several weeks and it works for me. I don't know an other way (fixing Cygwin) to success.
The RPC-client on my pc is started every few minutes and has to connect to the RPC-server.  Without the fix libtirpc is not usable and I have to use Cygwin 1.5.18 with the old librpc.

Raimund


-----Ursprüngliche Nachricht-----
Von: cygwin-owner@cygwin.com [mailto:cygwin-owner@cygwin.com] Im Auftrag von Mark Geisert
Gesendet: Dienstag, 30. Januar 2018 10:05
An: cygwin@cygwin.com
Betreff: Re: RPC clnt_create() adress already in use

PAULUS, Raimund, TI-ABN wrote:
> Hi Mark,
> as Corinna wrote in the thread " Cygwin socket option SO_REUSEADDR operates unlike Linux", the cause for the problem in libtirpc is Microsofts implementation of socket handling. If i implement a simple socket client, that is not so much of an issue, because I call the functions separately and can handle the error. Moreover in this case bind() is not necessary.
> But in the case of libtirpc the implementation of clnttcp_create() determines the sequence of bind() and connect() for the local port and you cannot correct the error of bind() after the call of connect(). Therefore I think best is to set the port number to zero (port = 0) before the call to bind().
>
> Raimund
>
>
> -----Ursprüngliche Nachricht-----
> Von: cygwin-owner@cygwin.com [mailto:cygwin-owner@cygwin.com] Im 
> Auftrag von PAULUS, Raimund, TI-ABN
> Gesendet: Dienstag, 9. Januar 2018 09:14
> An: cygwin@cygwin.com
> Betreff: WG: AW: RPC clnt_create() adress already in use
[...]

Hi Raimund,
Where, exactly, would you set the port number to zero?  I can imagine how this would solve the problem you're seeing but I'm concerned about other use cases.

It also seems a little odd to me we'd be making a Cygwin-specific patch rather than "fixing" Cygwin itself so the patch would not be necessary.  But I don't feel strongly either way here.  libtirpc already has Cygwin-specific patches.

..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


[-- Attachment #2: bindresvport.c --]
[-- Type: text/plain, Size: 6301 bytes --]

/*
 * Copyright (c) 2009, Sun Microsystems, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * - Neither the name of Sun Microsystems, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


/*
 * Copyright (c) 1987 by Sun Microsystems, Inc.
 *
 * Portions Copyright(C) 1996, Jason Downs.  All rights reserved.
 */

#include <sys/types.h>
#include <sys/socket.h>

#include <netdb.h>
#include <netinet/in.h>

#include <errno.h>
#include <string.h>
#include <unistd.h>

#include <rpc/rpc.h>

#include <string.h>
#include <reentrant.h>

extern pthread_mutex_t port_lock;

/*
 * Bind a socket to a privileged IP port
 */
int
bindresvport(sd, sin)
        int sd;
        struct sockaddr_in *sin;
{
        return bindresvport_sa(sd, (struct sockaddr *)sin);
}

#if defined(__linux__) || defined(__CYGWIN__)

#define STARTPORT 600
#define LOWPORT 512
#define ENDPORT (IPPORT_RESERVED - 1)
#define NPORTS  (ENDPORT - STARTPORT + 1)

int
bindresvport_sa(sd, sa)
        int sd;
        struct sockaddr *sa;
{
        int res, af;
        struct sockaddr_storage myaddr;
	struct sockaddr_in *sin;
#ifdef INET6
	struct sockaddr_in6 *sin6;
#endif
	u_int16_t *portp;
	static u_int16_t port;
	static short startport = STARTPORT;
	socklen_t salen;
	int nports;
	int endport = ENDPORT;
	int i;

	mutex_lock(&port_lock);
	nports = ENDPORT - startport + 1;

        if (sa == NULL) {
                salen = sizeof(myaddr);
                sa = (struct sockaddr *)&myaddr;

                if (getsockname(sd, (struct sockaddr *)&myaddr, &salen) == -1) {
                    mutex_unlock(&port_lock);
                    return -1;      /* errno is correctly set */
                }

                af = myaddr.ss_family;
        } else
                af = sa->sa_family;

        switch (af) {
        case AF_INET:
		sin = (struct sockaddr_in *)sa;
                salen = sizeof(struct sockaddr_in);
                port = ntohs(sin->sin_port);
		portp = &sin->sin_port;
		break;
#ifdef INET6
        case AF_INET6:
		sin6 = (struct sockaddr_in6 *)sa;
                salen = sizeof(struct sockaddr_in6);
                port = ntohs(sin6->sin6_port);
                portp = &sin6->sin6_port;
                break;
#endif
        default:
                errno = EPFNOSUPPORT;
                mutex_unlock(&port_lock);
                return (-1);
        }
        sa->sa_family = af;

        if (port == 0) {
                port = (getpid() % NPORTS) + STARTPORT;
        }
        res = -1;
        errno = EADDRINUSE;
/* fix for bind() */
port = 0;
		again:
        for (i = 0; i < nports; ++i) {
                *portp = htons(port++);
                 if (port > endport) 
                        port = startport;
                res = bind(sd, sa, salen);
		if (res >= 0 || errno != EADDRINUSE)
	                break;
        }
	if (i == nports && startport != LOWPORT) {
	    startport = LOWPORT;
	    endport = STARTPORT - 1;
	    nports = STARTPORT - LOWPORT;
	    port = LOWPORT + port % (STARTPORT - LOWPORT);
	    goto again;
	}
	mutex_unlock(&port_lock);

        return (res);
}
#else

#define IP_PORTRANGE 19
#define IP_PORTRANGE_LOW 2

/*
 * Bind a socket to a privileged IP port
 */
int
bindresvport_sa(sd, sa)
	int sd;
	struct sockaddr *sa;
{
	int old, error, af;
	struct sockaddr_storage myaddr;
	struct sockaddr_in *sin;
#ifdef INET6
	struct sockaddr_in6 *sin6;
#endif
	int proto, portrange, portlow;
	u_int16_t *portp;
	socklen_t salen;

	if (sa == NULL) {
		salen = sizeof(myaddr);
		sa = (struct sockaddr *)&myaddr;

		if (getsockname(sd, sa, &salen) == -1)
			return -1;	/* errno is correctly set */

		af = sa->sa_family;
		memset(sa, 0, salen);
	} else
		af = sa->sa_family;

	switch (af) {
	case AF_INET:
		proto = IPPROTO_IP;
		portrange = IP_PORTRANGE;
		portlow = IP_PORTRANGE_LOW;
		sin = (struct sockaddr_in *)sa;
		salen = sizeof(struct sockaddr_in);
		portp = &sin->sin_port;
		break;
#ifdef INET6
	case AF_INET6:
		proto = IPPROTO_IPV6;
		portrange = IPV6_PORTRANGE;
		portlow = IPV6_PORTRANGE_LOW;
		sin6 = (struct sockaddr_in6 *)sa;
		salen = sizeof(struct sockaddr_in6);
		portp = &sin6->sin6_port;
		break;
#endif
	default:
		errno = EPFNOSUPPORT;
		return (-1);
	}
	sa->sa_family = af;

	if (*portp == 0) {
		socklen_t oldlen = sizeof(old);

		error = getsockopt(sd, proto, portrange, &old, &oldlen);
		if (error < 0)
			return (error);

		error = setsockopt(sd, proto, portrange, &portlow,
		    sizeof(portlow));
		if (error < 0)
			return (error);
	}

	error = bind(sd, sa, salen);

	if (*portp == 0) {
		int saved_errno = errno;

		if (error < 0) {
			if (setsockopt(sd, proto, portrange, &old,
			    sizeof(old)) < 0)
				errno = saved_errno;
			return (error);
		}

		if (sa != (struct sockaddr *)&myaddr) {
			/* Hmm, what did the kernel assign? */
			if (getsockname(sd, sa, &salen) < 0)
				errno = saved_errno;
			return (error);
		}
	}
	return (error);
}
#endif

[-- Attachment #3: Type: text/plain, Size: 219 bytes --]


--
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	other threads:[~2018-01-30 10:07 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-30 10:07 PAULUS, Raimund, TI-ABN [this message]
2018-01-31  8:15 ` Mark Geisert
2018-01-31  9:11   ` Corinna Vinschen
2018-01-31  9:35     ` Mark Geisert
2018-02-02  8:11       ` Mark Geisert
  -- strict thread matches above, loose matches on Subject: below --
2018-03-08 11:44 PAULUS, Raimund, TI-ABN
2018-03-08 15:24 ` Corinna Vinschen
2018-03-08 23:00 ` Mark Geisert
2018-03-02 10:39 PAULUS, Raimund, TI-ABN
2018-02-27  9:54 PAULUS, Raimund, TI-ABN
2018-02-27 10:37 ` Corinna Vinschen
2018-02-28  6:00   ` Mark Geisert
2018-02-06 11:29 PAULUS, Raimund, TI-ABN
2018-02-06 14:20 ` Corinna Vinschen
2018-02-07  6:54   ` Mark Geisert
2018-02-05 14:58 PAULUS, Raimund, TI-ABN
2018-02-05  8:19 PAULUS, Raimund, TI-ABN
2018-02-05 10:29 ` Mark Geisert
2018-02-05 11:26   ` Corinna Vinschen
2018-02-05 13:34     ` Corinna Vinschen
2018-02-05 14:06       ` Corinna Vinschen
2018-02-05 20:15         ` Corinna Vinschen
2018-02-02 12:58 PAULUS, Raimund, TI-ABN
2018-01-30  7:01 PAULUS, Raimund, TI-ABN
2018-01-30  9:05 ` Mark Geisert
2017-12-19 16:13 PAULUS, Raimund, TI-ABN
2017-12-28  0:03 ` Mark Geisert
2017-09-29  9:52 PAULUS, Raimund, TI-ABN
2017-09-29 17:36 ` Mark Geisert
2017-09-27 12:51 PAULUS, Raimund, TI-ABN
2017-09-25  6:44 PAULUS, Raimund, TI-ABN
2017-09-27  9:50 ` Mark Geisert
2017-09-22  7:22 PAULUS, Raimund, TI-ABN
2017-09-24  9:49 ` Mark Geisert

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=59D90AF8D70E9740907BACDE2BCB520836E01220@RESW102.resdom01.local \
    --to=raimund.paulus@dillinger.biz \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).