Allow user to explicitly specify local (source) port

See https://github.com/miniupnp/miniupnp/issues/119

- Replace the sameport parameter to the upnpDiscover* functions
- Added constants UPNP_LOCAL_PORT_ANY(0) & UPNP_LOCAL_PORT_SAME(1).  The
  value "1" was chosen for presumed backwards compatability with the
  previous "sameport" parameter (assuming usesr would have set to 1 if
  they wanted same port)
- Can be specified with "-z" to the test programs "upnpc" & "pymoduletest.py"
This commit is contained in:
Nevo Hed 2015-05-12 19:05:48 -04:00
parent f11b8b2a0d
commit 94a5af0c15
6 changed files with 67 additions and 24 deletions

View File

@ -25,13 +25,16 @@ through the miniupnpc API. The name of the C functions are matching
the UPnP methods names. ie: GetGenericPortMappingEntry is
UPNP_GetGenericPortMappingEntry.
.SH "API FUNCTIONS"
.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error);"
.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int localport, int ipv6, int * error);"
execute the discovery process.
delay (in millisecond) is the maximum time for waiting any device response.
If available, device list will be obtained from MiniSSDPd.
Default path for minissdpd socket will be used if minissdpdsock argument is NULL.
If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets.
If sameport is not null, SSDP packets will be sent from the source port 1900 (same as destination port) otherwise system assign a source port.
If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
from the source port 1900 (same as destination port), if set to
UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
be attempted as the source port.
If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process.
.IP "void freeUPNPDevlist(struct UPNPDev * devlist);"
free the list returned by upnpDiscover().

View File

@ -344,7 +344,7 @@ parseMSEARCHReply(const char * reply, int size,
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error)
{
@ -376,6 +376,8 @@ upnpDiscoverDevices(const char * const deviceTypes[],
#endif
int linklocal = 1;
if(localport==UPNP_LOCAL_PORT_SAME)
localport = PORT;
if(error)
*error = UPNPDISCOVER_UNKNOWN_ERROR;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
@ -411,14 +413,14 @@ upnpDiscoverDevices(const char * const deviceTypes[],
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
p->sin6_family = AF_INET6;
if(sameport)
p->sin6_port = htons(PORT);
if(localport)
p->sin6_port = htons(localport);
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
p->sin_family = AF_INET;
if(sameport)
p->sin_port = htons(PORT);
if(localport)
p->sin_port = htons(localport);
p->sin_addr.s_addr = INADDR_ANY;
}
#ifdef _WIN32
@ -715,7 +717,7 @@ error:
/* upnpDiscover() Discover IGD device */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error)
{
@ -732,14 +734,14 @@ upnpDiscover(int delay, const char * multicastif,
0
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, sameport,
delay, multicastif, minissdpdsock, localport,
ipv6, error);
}
/* upnpDiscoverAll() Discover all UPnP devices */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error)
{
@ -749,14 +751,14 @@ upnpDiscoverAll(int delay, const char * multicastif,
0
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, sameport,
delay, multicastif, minissdpdsock, localport,
ipv6, error);
}
/* upnpDiscoverDevice() Discover a specific device */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error)
{
@ -765,7 +767,7 @@ upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
0
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, sameport,
delay, multicastif, minissdpdsock, localport,
ipv6, error);
}

View File

@ -21,6 +21,12 @@
#define MINIUPNPC_VERSION "1.9"
#define MINIUPNPC_API_VERSION 12
/* Source port:
Using "1" as an alias for 1900 for backwards compatability
(presuming one would have used that for the "sameport" parameter) */
#define UPNP_LOCAL_PORT_ANY 0
#define UPNP_LOCAL_PORT_SAME 1
#ifdef __cplusplus
extern "C" {
#endif
@ -52,30 +58,32 @@ struct UPNPDev {
* is NULL.
* If multicastif is not NULL, it will be used instead of the default
* multicast interface for sending SSDP discover packets.
* If sameport is not null, SSDP packets will be sent from the source port
* 1900 (same as destination port) otherwise system assign a source port. */
* If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
* from the source port 1900 (same as destination port), if set to
* UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
* be attempted as the source port */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
const char * minissdpdsock, int localport,
int ipv6,
int * error);

View File

@ -42,6 +42,7 @@ typedef struct {
struct UPNPUrls urls;
struct IGDdatas data;
unsigned int discoverdelay; /* value passed to upnpDiscover() */
unsigned int localport; /* value passed to upnpDiscover() */
char lanaddr[40]; /* our ip address on the LAN */
char * multicastif;
char * minissdpdsocket;
@ -54,6 +55,15 @@ static PyMemberDef UPnP_members[] = {
{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
0/*READWRITE*/, "value in ms used to wait for SSDP responses"
},
{"localport", T_UINT, offsetof(UPnPObject, localport),
0/*READWRITE*/,
"If localport is set to UPNP_LOCAL_PORT_SAME(1) "
"SSDP packets will be sent from the source port "
"1900 (same as destination port), if set to "
"UPNP_LOCAL_PORT_ANY(0) system assign a source "
"port, any other value will be attempted as the "
"source port"
},
/* T_STRING is allways readonly :( */
{"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
0, "IP of the network interface to be used for multicast operations"
@ -70,15 +80,22 @@ static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
char* multicastif = NULL;
char* minissdpdsocket = NULL;
static char *kwlist[] = {
"multicastif", "minissdpdsocket", "discoverdelay", NULL
"multicastif", "minissdpdsocket", "discoverdelay",
"localport", NULL
};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzI", kwlist,
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
&multicastif,
&minissdpdsocket,
&self->discoverdelay))
&self->discoverdelay,
&self->localport))
return -1;
if(self->localport>1 &&
(self->localport>65534||self->localport<1024)) {
PyErr_SetString(PyExc_Exception, "Invalid localport value");
return -1;
}
if(multicastif)
self->multicastif = strdup(multicastif);
if(minissdpdsocket)
@ -112,7 +129,7 @@ UPnP_discover(UPnPObject *self)
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
self->multicastif,
self->minissdpdsocket,
0/*sameport flag*/,
(int)self->localport,
0/*ip v6*/,
0/*error */);
Py_END_ALLOW_THREADS

View File

@ -14,6 +14,7 @@ parser = argparse.ArgumentParser()
parser.add_argument('-m', '--multicastif')
parser.add_argument('-p', '--minissdpdsocket')
parser.add_argument('-d', '--discoverdelay', type=int, default=200)
parser.add_argument('-z', '--localport', type=int, default=0)
# create the object
u = miniupnpc.UPnP(**vars(parser.parse_args()))

View File

@ -543,6 +543,7 @@ int main(int argc, char ** argv)
const char * rootdescurl = 0;
const char * multicastif = 0;
const char * minissdpdpath = 0;
int localport = UPNP_LOCAL_PORT_ANY;
int retcode = 0;
int error = 0;
int ipv6 = 0;
@ -575,6 +576,16 @@ int main(int argc, char ** argv)
rootdescurl = argv[++i];
else if(argv[i][1] == 'm')
multicastif = argv[++i];
else if(argv[i][1] == 'z'){
char junk;
if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
localport<0 || localport>65535 ||
(localport >1 && localport < 1024)){
fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
localport = UPNP_LOCAL_PORT_ANY;
break;
}
}
else if(argv[i][1] == 'p')
minissdpdpath = argv[++i];
else if(argv[i][1] == '6')
@ -626,13 +637,14 @@ int main(int argc, char ** argv)
fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
return 1;
}
if( rootdescurl
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
0/*sameport*/, ipv6, &error)))
localport, ipv6, &error)))
{
struct UPNPDev * device;
struct UPNPUrls urls;