diff --git a/miniupnpc/man3/miniupnpc.3 b/miniupnpc/man3/miniupnpc.3 index 1b16647..7b997d4 100644 --- a/miniupnpc/man3/miniupnpc.3 +++ b/miniupnpc/man3/miniupnpc.3 @@ -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(). diff --git a/miniupnpc/miniupnpc.c b/miniupnpc/miniupnpc.c index a7ea226..3b3ab85 100644 --- a/miniupnpc/miniupnpc.c +++ b/miniupnpc/miniupnpc.c @@ -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); } diff --git a/miniupnpc/miniupnpc.h b/miniupnpc/miniupnpc.h index b56d239..dc8fd61 100644 --- a/miniupnpc/miniupnpc.h +++ b/miniupnpc/miniupnpc.h @@ -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); diff --git a/miniupnpc/miniupnpcmodule.c b/miniupnpc/miniupnpcmodule.c index 5f46d5f..3783864 100644 --- a/miniupnpc/miniupnpcmodule.c +++ b/miniupnpc/miniupnpcmodule.c @@ -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 diff --git a/miniupnpc/pymoduletest.py b/miniupnpc/pymoduletest.py index 6387364..73e8b87 100755 --- a/miniupnpc/pymoduletest.py +++ b/miniupnpc/pymoduletest.py @@ -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())) diff --git a/miniupnpc/upnpc.c b/miniupnpc/upnpc.c index 57ca34e..df73f56 100644 --- a/miniupnpc/upnpc.c +++ b/miniupnpc/upnpc.c @@ -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;