diff --git a/third-party/dht/CHANGES b/third-party/dht/CHANGES deleted file mode 100644 index 6904abd60..000000000 --- a/third-party/dht/CHANGES +++ /dev/null @@ -1,133 +0,0 @@ -3 May 2014: dht-0.22 - - * INCOMPATIBLE CHANGE: the callback now takes const arguments. - * Consult the local storage when performing a search, which should - make bootstrapping of tiny DHTs easier. Note that we're still not - performing local stores, since that would require knowing our IP - address. - * Don't attempt to flush the debug stream if debugging is disabled. - This appears to work around a bug in Transmission. - -25 July 2011: dht-0.21 - - * Blacklisting support. - -7 July 2011: dht-0.20 - - * Fix compilation on systems that have memmem but don't define HAVE_MEMMEM. - -30 April 2011: dht-0.19 - - * Fix incorrect parsing of announces. Thanks to cjdelisle. - * Relax rate limiting slightly. - -20 January 2011: dht-0.18 - - * Fix a bug that could cause parse_message to enter an infinite loop - on overflow. Thanks to Jordan Lee. - -9 January 2011: dht-0.17: - - * Fix a bug that prevented calling dht_init after dht_uninit. - * Remove the "dofree" parameter to dht_uninit. - -23 December 2010: dht-0.16: - - * Change the interface to allow sharing of the UDP socket e.g. with uTP. - -1 July 2010: dht-0.15 - - * Port to Windows, for the needs of Transmission. - -25 March 2010: dht-0.14 - - * Fixed ordering of entries in parameter dictionaries. - -15 December 2009: dht-0.13 - - * Implemented protection against incorrect addresses in the DHT. - * Tweaked neighborhood maintenance to wake up less often. - -11 December 2009: dht-0.12 - * Fixed slightly incorrect formatting of DHT messages. - * Fixed incorrect debugging message. - -22 November 2009: dht-0.11 - - * Implemented IPv6 support (BEP-32). - * Fixed a bug which could cause us to never mark a search as finished. - * Fixed a bug that could cause us to send incomplete lists in response to - find_nodes. - * Limit the number of hashes that we're willing to track. - * Made bucket maintenance slightly more aggressive. - * Produce on-the-wire error messages to give a hint to the other side. - * Added a bunch of options to dht-example to make it useful as - a bootstrap node. - * Send version "JC\0\0" when using dht-example. - -18 October 2009: dht-0.10 - - * Send nodes even when sending values. This is a violation of the - protocol, but I have been assured that it doesn't break any deployed - implementation. This is also what both libtorrent and uTorrent do. - * Give up immediately on a search peer when no token was provided. This - is a very reasonable extension to the protocol, and certainly doesn't - break anything. - * Parse heterogeneous values lists correctly. This is mandated by BEP 32. - -20 September 2009: dht-0.9 - - * Fixed incorrect computation of number of nodes. - * Made the initial bucket split eagerly (speeds up bootstrapping). - * Fixed initial filling of search buckets (speeds up searches). - -28 July 2009: dht-0.8 - - * Fixed a crash when expiring the first search on the list. - * Fixed freeing of the search list when uniniting with dofree = 1. - -24 June 2009: dht-0.7 - - * Removed the fixed limit on the number of concurrent searches, we now - use a linked list. - * Fixed build on FreeBSD (thanks to Humihara and Charles Kerr). - -22 May 2009: dht-0.6 - - * Fixed a buffer overflow (when reading) in parse_message. - * Fixed slightly inacurrate metric computation when searching. - * Removed a slightly inaccurate shortcut when responding to find_nodes. - * Relaxed the rate-limiting parameters to 4 requests per second. - -19 May 2009: dht-0.5 - - * Made reading of /dev/urandom a function provided by the user. - * Implemented the ``v'' extension that identifies node implementations. - -18 May 2009: dht-0.4 - - * Fixed the handling of tokens in announce_peer messages. - * Implemented backtracking during search when nodes turn out to be dead. - -17 May 2009: dht-0.3 - - * Fixed a number of incorrectly formatted messages. - * Changed reply to find_peers to spread the load more uniformly. - * Fixed a bug that could cause premature splitting. - * Implemented rate limiting. - * Changed some time constants to be less chatty. - * When determining if a bucket is fresh enough, we now only take replies - into account. - * dht_get_nodes now returns nodes starting with our own bucket. - * Tweaked the memory allocation strategy for stored peers. - -17 May 2009: dht-0.2 - - * Fixed a crash in dht_uninit. - * Added support for saving the list of known-good nodes. - * Changed the interface of dht_nodes to provide the number of nodes that - recently sent incoming requests. - -13 May 2009: dht-0.1 - - * Initial public release. diff --git a/third-party/dht/LICENCE b/third-party/dht/LICENCE deleted file mode 100644 index cf2d39000..000000000 --- a/third-party/dht/LICENCE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2009, 2010 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/third-party/dht/Makefile.am b/third-party/dht/Makefile.am deleted file mode 100644 index 869284c88..000000000 --- a/third-party/dht/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -AM_CFLAGS = @PTHREAD_CFLAGS@ - -noinst_LIBRARIES = libdht.a -libdht_a_SOURCES = dht.c -noinst_HEADERS = dht.h -EXTRA_DIST = CHANGES dht-example.c LICENCE README diff --git a/third-party/dht/README b/third-party/dht/README deleted file mode 100644 index 5252a9453..000000000 --- a/third-party/dht/README +++ /dev/null @@ -1,198 +0,0 @@ -The files dht.c and dht.h implement the variant of the Kademlia Distributed -Hash Table (DHT) used in the Bittorrent network (``mainline'' variant). - -The file dht-example.c is a stand-alone program that participates in the -DHT. Another example is a patch against Transmission, which you might or -might not be able to find somewhere. - -The code is designed to work well in both event-driven and threaded code. -The caller, which is either an event-loop or a dedicated thread, must -periodically call the function dht_periodic. In addition, it must call -dht_periodic whenever any data has arrived from the network. - -All functions return -1 in case of failure, in which case errno is set, or -a positive value in case of success. - -Initialisation -************** - -* dht_init - -This must be called before using the library. You pass it a bound IPv4 -datagram socket, a bound IPv6 datagram socket, and your node id, a 20-octet -array that should be globally unique. - -If you're on a multi-homed host, you should bind the sockets to one of your -addresses. - -Node ids must be well distributed, so you cannot just use your Bittorrent -id; you should either generate a truly random value (using plenty of -entropy), or at least take the SHA-1 of something. However, it is a good -idea to keep the id stable, so you may want to store it in stable storage -at client shutdown. - - -* dht_uninit - -This may be called at the end of the session. - -Bootstrapping -************* - -The DHT needs to be taught a small number of contacts to begin functioning. -You can hard-wire a small number of stable nodes in your application, but -this obviously fails to scale. You may save the list of known good nodes -at shutdown, and restore it at restart. You may also grab nodes from -torrent files (the nodes field), and you may exchange contacts with other -Bittorrent peers using the PORT extension. - -* dht_ping - -This is the main bootstrapping primitive. You pass it an address at which -you believe that a DHT node may be living, and a query will be sent. If -a node replies, and if there is space in the routing table, it will be -inserted. - -* dht_insert_node - -This is a softer bootstrapping method, which doesn't actually send -a query -- it only stores the node in the routing table for later use. It -is a good idea to use that when e.g. restoring your routing table from -disk. - -Note that dht_insert_node requires that you supply a node id. If the id -turns out to be wrong, the DHT will eventually recover; still, inserting -massive amounts of incorrect information into your routing table is -certainly not a good idea. - -An additionaly difficulty with dht_insert_node is that, for various -reasons, a Kademlia routing table cannot absorb nodes faster than a certain -rate. Dumping a large number of nodes into a table using dht_insert_node -will probably cause most of these nodes to be discarded straight away. -(The tolerable rate is difficult to estimate; it is probably on the order -of one node every few seconds per node already in the table divided by 8, -for some suitable value of 8.) - -Doing some work -*************** - -* dht_periodic - -This function should be called by your main loop periodically, and also -whenever data is available on the socket. The time after which -dht_periodic should be called if no data is available is returned in the -parameter tosleep. (You do not need to be particularly accurate; actually, -it is a good idea to be late by a random value.) - -The parameters buf, buflen, from and fromlen optionally carry a received -message. If buflen is 0, then no message was received. - -Dht_periodic also takes a callback, which will be called whenever something -interesting happens (see below). - -* dht_search - -This schedules a search for information about the info-hash specified in -id. If port is not 0, it specifies the TCP port on which the current peer -is listening; in that case, when the search is complete it will be announced -to the network. The port is in host order, beware if you got it from -a struct sockaddr_in. - -In either case, data is passed to the callback function as soon as it is -available, possibly in multiple pieces. The callback function will -additionally be called when the search is complete. - -Up to DHT_MAX_SEARCHES (1024) searches can be in progress at a given time; -any more, and dht_search will return -1. If you specify a new search for -the same info hash as a search still in progress, the previous search is -combined with the new one -- you will only receive a completion indication -once. - -Information queries -******************* - -* dht_nodes - -This returns the number of known good, dubious and cached nodes in our -routing table. This can be used to decide whether it's reasonable to start -a search; a search is likely to be successful as long as we have a few good -nodes; however, in order to avoid overloading your bootstrap nodes, you may -want to wait until good is at least 4 and good + doubtful is at least 30 or -so. - -It also includes the number of nodes that recently send us an unsolicited -request; this can be used to determine if the UDP port used for the DHT is -firewalled. - -If you want to display a single figure to the user, you should display -good + doubtful, which is the total number of nodes in your routing table. -Some clients try to estimate the total number of nodes, but this doesn't -make much sense -- since the result is exponential in the number of nodes -in the routing table, small variations in the latter cause huge jumps in -the former. - -* dht_get_nodes - -This retrieves the list of known good nodes, starting with the nodes in our -own bucket. It is a good idea to save the list of known good nodes at -shutdown, and ping them at startup. - -* dht_dump_tables -* dht_debug - -These are debugging aids. - -Functions provided by you -************************* - -* The callback function - -The callback function is called with 5 arguments. Closure is simply the -value that you passed to dht_periodic. Event is one of DHT_EVENT_VALUES or -DHT_EVENT_VALUES6, which indicates that we have new values, or -DHT_EVENT_SEARCH_DONE or DHT_EVENT_SEARCH_DONE6, which indicates that -a search has completed. In either case, info_hash is set to the info-hash -of the search. - -In the case of DHT_EVENT_VALUES, data is a list of nodes in ``compact'' -format -- 6 or 18 bytes per node. Its length in bytes is in data_len. - -* dht_blacklisted - -This is a function that takes an IP address and returns true if this -address should be silently ignored. Do not use this feature unless you -really must -- Kademlia supposes transitive reachability. - -* dht_hash - -This should compute a reasonably strong cryptographic hash of the passed -values. It should map cleanly to your favourite crypto toolkit's MD5 or -SHA-1 function. - -* dht_random_bytes - -This should fill the supplied buffer with true random bytes. - -Final notes -*********** - -* NAT - -Nothing works well across NATs, but Kademlia is somewhat less impacted than -many other protocols. The implementation takes care to distinguish between -unidirectional and bidirectional reachability, and NATed nodes will -eventually fall out from other nodes' routing tables. - -While there is no periodic pinging in this implementation, maintaining -a full routing table requires slightly more than one packet exchange per -minute, even in a completely idle network; this should be sufficient to -make most full cone NATs happy. - -* Missing functionality - -Some of the code has had very little testing. If it breaks, you get to -keep both pieces. - - - Juliusz Chroboczek - diff --git a/third-party/dht/dht-example.c b/third-party/dht/dht-example.c deleted file mode 100644 index 7ab08b6c2..000000000 --- a/third-party/dht/dht-example.c +++ /dev/null @@ -1,480 +0,0 @@ -/* This example code was written by Juliusz Chroboczek. - You are free to cut'n'paste from it to your heart's content. */ - -/* For crypt */ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dht.h" - -#define MAX_BOOTSTRAP_NODES 20 -static struct sockaddr_storage bootstrap_nodes[MAX_BOOTSTRAP_NODES]; -static int num_bootstrap_nodes = 0; - -static volatile sig_atomic_t dumping = 0, searching = 0, exiting = 0; - -static void -sigdump(int signo) -{ - dumping = 1; -} - -static void -sigtest(int signo) -{ - searching = 1; -} - -static void -sigexit(int signo) -{ - exiting = 1; -} - -static void -init_signals(void) -{ - struct sigaction sa; - sigset_t ss; - - sigemptyset(&ss); - sa.sa_handler = sigdump; - sa.sa_mask = ss; - sa.sa_flags = 0; - sigaction(SIGUSR1, &sa, NULL); - - sigemptyset(&ss); - sa.sa_handler = sigtest; - sa.sa_mask = ss; - sa.sa_flags = 0; - sigaction(SIGUSR2, &sa, NULL); - - sigemptyset(&ss); - sa.sa_handler = sigexit; - sa.sa_mask = ss; - sa.sa_flags = 0; - sigaction(SIGINT, &sa, NULL); -} - -const unsigned char hash[20] = { - 0x54, 0x57, 0x87, 0x89, 0xdf, 0xc4, 0x23, 0xee, 0xf6, 0x03, - 0x1f, 0x81, 0x94, 0xa9, 0x3a, 0x16, 0x98, 0x8b, 0x72, 0x7b -}; - -/* The call-back function is called by the DHT whenever something - interesting happens. Right now, it only happens when we get a new value or - when a search completes, but this may be extended in future versions. */ -static void -callback(void *closure, - int event, - const unsigned char *info_hash, - const void *data, size_t data_len) -{ - if(event == DHT_EVENT_SEARCH_DONE) - printf("Search done.\n"); - else if(event == DHT_EVENT_VALUES) - printf("Received %d values.\n", (int)(data_len / 6)); -} - -static unsigned char buf[4096]; - -int -main(int argc, char **argv) -{ - int i, rc, fd; - int s = -1, s6 = -1, port; - int have_id = 0; - unsigned char myid[20]; - time_t tosleep = 0; - char *id_file = "dht-example.id"; - int opt; - int quiet = 0, ipv4 = 1, ipv6 = 1; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - struct sockaddr_storage from; - socklen_t fromlen; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - - - - while(1) { - opt = getopt(argc, argv, "q46b:i:"); - if(opt < 0) - break; - - switch(opt) { - case 'q': quiet = 1; break; - case '4': ipv6 = 0; break; - case '6': ipv4 = 0; break; - case 'b': { - char buf[16]; - int rc; - rc = inet_pton(AF_INET, optarg, buf); - if(rc == 1) { - memcpy(&sin.sin_addr, buf, 4); - break; - } - rc = inet_pton(AF_INET6, optarg, buf); - if(rc == 1) { - memcpy(&sin6.sin6_addr, buf, 16); - break; - } - goto usage; - } - break; - case 'i': - id_file = optarg; - break; - default: - goto usage; - } - } - - /* Ids need to be distributed evenly, so you cannot just use your - bittorrent id. Either generate it randomly, or take the SHA-1 of - something. */ - fd = open(id_file, O_RDONLY); - if(fd >= 0) { - rc = read(fd, myid, 20); - if(rc == 20) - have_id = 1; - close(fd); - } - - fd = open("/dev/urandom", O_RDONLY); - if(fd < 0) { - perror("open(random)"); - exit(1); - } - - if(!have_id) { - int ofd; - - rc = read(fd, myid, 20); - if(rc < 0) { - perror("read(random)"); - exit(1); - } - have_id = 1; - close(fd); - - ofd = open(id_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if(ofd >= 0) { - rc = write(ofd, myid, 20); - if(rc < 20) - unlink(id_file); - close(ofd); - } - } - - { - unsigned seed; - read(fd, &seed, sizeof(seed)); - srandom(seed); - } - - close(fd); - - if(argc < 2) - goto usage; - - i = optind; - - if(argc < i + 1) - goto usage; - - port = atoi(argv[i++]); - if(port <= 0 || port >= 0x10000) - goto usage; - - while(i < argc) { - struct addrinfo hints, *info, *infop; - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; - if(!ipv6) - hints.ai_family = AF_INET; - else if(!ipv4) - hints.ai_family = AF_INET6; - else - hints.ai_family = 0; - rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info); - if(rc != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc)); - exit(1); - } - - i++; - if(i >= argc) - goto usage; - - infop = info; - while(infop) { - memcpy(&bootstrap_nodes[num_bootstrap_nodes], - infop->ai_addr, infop->ai_addrlen); - infop = infop->ai_next; - num_bootstrap_nodes++; - } - freeaddrinfo(info); - - i++; - } - - /* If you set dht_debug to a stream, every action taken by the DHT will - be logged. */ - if(!quiet) - dht_debug = stdout; - - /* We need an IPv4 and an IPv6 socket, bound to a stable port. Rumour - has it that uTorrent works better when it is the same as your - Bittorrent port. */ - if(ipv4) { - s = socket(PF_INET, SOCK_DGRAM, 0); - if(s < 0) { - perror("socket(IPv4)"); - } - } - - if(ipv6) { - s6 = socket(PF_INET6, SOCK_DGRAM, 0); - if(s6 < 0) { - perror("socket(IPv6)"); - } - } - - if(s < 0 && s6 < 0) { - fprintf(stderr, "Eek!"); - exit(1); - } - - - if(s >= 0) { - sin.sin_port = htons(port); - rc = bind(s, (struct sockaddr*)&sin, sizeof(sin)); - if(rc < 0) { - perror("bind(IPv4)"); - exit(1); - } - } - - if(s6 >= 0) { - int rc; - int val = 1; - - rc = setsockopt(s6, IPPROTO_IPV6, IPV6_V6ONLY, - (char *)&val, sizeof(val)); - if(rc < 0) { - perror("setsockopt(IPV6_V6ONLY)"); - exit(1); - } - - /* BEP-32 mandates that we should bind this socket to one of our - global IPv6 addresses. In this simple example, this only - happens if the user used the -b flag. */ - - sin6.sin6_port = htons(port); - rc = bind(s6, (struct sockaddr*)&sin6, sizeof(sin6)); - if(rc < 0) { - perror("bind(IPv6)"); - exit(1); - } - } - - /* Init the dht. This sets the socket into non-blocking mode. */ - rc = dht_init(s, s6, myid, (unsigned char*)"JC\0\0"); - if(rc < 0) { - perror("dht_init"); - exit(1); - } - - init_signals(); - - /* For bootstrapping, we need an initial list of nodes. This could be - hard-wired, but can also be obtained from the nodes key of a torrent - file, or from the PORT bittorrent message. - - Dht_ping_node is the brutal way of bootstrapping -- it actually - sends a message to the peer. If you're going to bootstrap from - a massive number of nodes (for example because you're restoring from - a dump) and you already know their ids, it's better to use - dht_insert_node. If the ids are incorrect, the DHT will recover. */ - for(i = 0; i < num_bootstrap_nodes; i++) { - dht_ping_node((struct sockaddr*)&bootstrap_nodes[i], - sizeof(bootstrap_nodes[i])); - usleep(random() % 100000); - } - - while(1) { - struct timeval tv; - fd_set readfds; - tv.tv_sec = tosleep; - tv.tv_usec = random() % 1000000; - - FD_ZERO(&readfds); - if(s >= 0) - FD_SET(s, &readfds); - if(s6 >= 0) - FD_SET(s6, &readfds); - rc = select(s > s6 ? s + 1 : s6 + 1, &readfds, NULL, NULL, &tv); - if(rc < 0) { - if(errno != EINTR) { - perror("select"); - sleep(1); - } - } - - if(exiting) - break; - - if(rc > 0) { - fromlen = sizeof(from); - if(s >= 0 && FD_ISSET(s, &readfds)) - rc = recvfrom(s, buf, sizeof(buf) - 1, 0, - (struct sockaddr*)&from, &fromlen); - else if(s6 >= 0 && FD_ISSET(s6, &readfds)) - rc = recvfrom(s6, buf, sizeof(buf) - 1, 0, - (struct sockaddr*)&from, &fromlen); - else - abort(); - } - - if(rc > 0) { - buf[rc] = '\0'; - rc = dht_periodic(buf, rc, (struct sockaddr*)&from, fromlen, - &tosleep, callback, NULL); - } else { - rc = dht_periodic(NULL, 0, NULL, 0, &tosleep, callback, NULL); - } - if(rc < 0) { - if(errno == EINTR) { - continue; - } else { - perror("dht_periodic"); - if(rc == EINVAL || rc == EFAULT) - abort(); - tosleep = 1; - } - } - - /* This is how you trigger a search for a torrent hash. If port - (the second argument) is non-zero, it also performs an announce. - Since peers expire announced data after 30 minutes, it's a good - idea to reannounce every 28 minutes or so. */ - if(searching) { - if(s >= 0) - dht_search(hash, 0, AF_INET, callback, NULL); - if(s6 >= 0) - dht_search(hash, 0, AF_INET6, callback, NULL); - searching = 0; - } - - /* For debugging, or idle curiosity. */ - if(dumping) { - dht_dump_tables(stdout); - dumping = 0; - } - } - - { - struct sockaddr_in sin[500]; - struct sockaddr_in6 sin6[500]; - int num = 500, num6 = 500; - int i; - i = dht_get_nodes(sin, &num, sin6, &num6); - printf("Found %d (%d + %d) good nodes.\n", i, num, num6); - } - - dht_uninit(); - return 0; - - usage: - printf("Usage: dht-example [-q] [-4] [-6] [-i filename] [-b address]...\n" - " port [address port]...\n"); - exit(1); -} - -/* Functions called by the DHT. */ - -int -dht_blacklisted(const struct sockaddr *sa, int salen) -{ - return 0; -} - -/* We need to provide a reasonably strong cryptographic hashing function. - Here's how we'd do it if we had RSA's MD5 code. */ -#if 0 -void -dht_hash(void *hash_return, int hash_size, - const void *v1, int len1, - const void *v2, int len2, - const void *v3, int len3) -{ - static MD5_CTX ctx; - MD5Init(&ctx); - MD5Update(&ctx, v1, len1); - MD5Update(&ctx, v2, len2); - MD5Update(&ctx, v3, len3); - MD5Final(&ctx); - if(hash_size > 16) - memset((char*)hash_return + 16, 0, hash_size - 16); - memcpy(hash_return, ctx.digest, hash_size > 16 ? 16 : hash_size); -} -#else -/* But for this example, we might as well use something weaker. */ -void -dht_hash(void *hash_return, int hash_size, - const void *v1, int len1, - const void *v2, int len2, - const void *v3, int len3) -{ - const char *c1 = v1, *c2 = v2, *c3 = v3; - char key[9]; /* crypt is limited to 8 characters */ - int i; - - memset(key, 0, 9); -#define CRYPT_HAPPY(c) ((c % 0x60) + 0x20) - - for(i = 0; i < 2 && i < len1; i++) - key[i] = CRYPT_HAPPY(c1[i]); - for(i = 0; i < 4 && i < len1; i++) - key[2 + i] = CRYPT_HAPPY(c2[i]); - for(i = 0; i < 2 && i < len1; i++) - key[6 + i] = CRYPT_HAPPY(c3[i]); - strncpy(hash_return, crypt(key, "jc"), hash_size); -} -#endif - -int -dht_random_bytes(void *buf, size_t size) -{ - int fd, rc, save; - - fd = open("/dev/urandom", O_RDONLY); - if(fd < 0) - return -1; - - rc = read(fd, buf, size); - - save = errno; - close(fd); - errno = save; - - return rc; -} diff --git a/third-party/dht/dht.c b/third-party/dht/dht.c deleted file mode 100644 index 61522bff8..000000000 --- a/third-party/dht/dht.c +++ /dev/null @@ -1,2969 +0,0 @@ -/* -Copyright (c) 2009-2011 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* Please, please, please. - - You are welcome to integrate this code in your favourite Bittorrent - client. Please remember, however, that it is meant to be usable by - others, including myself. This means no C++, no relicensing, and no - gratuitious changes to the coding style. And please send back any - improvements to the author. */ - -/* For memmem. */ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef WIN32 -#include -#include -#include -#include -#else -#include -#define WINVER WindowsXP -#include -#endif - -#include "dht.h" - -#ifndef HAVE_MEMMEM -#ifdef __GLIBC__ -#define HAVE_MEMMEM -#endif -#endif - -#ifndef MSG_CONFIRM -#define MSG_CONFIRM 0 -#endif - -#ifdef WIN32 - -#define EAFNOSUPPORT WSAEAFNOSUPPORT -static int -set_nonblocking(int fd, int nonblocking) -{ - int rc; - - unsigned long mode = !!nonblocking; - rc = ioctlsocket(fd, FIONBIO, &mode); - if(rc != 0) - errno = WSAGetLastError(); - return (rc == 0 ? 0 : -1); -} - -static int -random(void) -{ - return rand(); -} -extern const char *inet_ntop(int, const void *, char *, socklen_t); - -#else - -static int -set_nonblocking(int fd, int nonblocking) -{ - int rc; - rc = fcntl(fd, F_GETFL, 0); - if(rc < 0) - return -1; - - rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK)); - if(rc < 0) - return -1; - - return 0; -} - -#endif - -/* We set sin_family to 0 to mark unused slots. */ -#if AF_INET == 0 || AF_INET6 == 0 -#error You lose -#endif - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -/* nothing */ -#elif defined(__GNUC__) -#define inline __inline -#if (__GNUC__ >= 3) -#define restrict __restrict -#else -#define restrict /**/ -#endif -#else -#define inline /**/ -#define restrict /**/ -#endif - -#define MAX(x, y) ((x) >= (y) ? (x) : (y)) -#define MIN(x, y) ((x) <= (y) ? (x) : (y)) - -struct node { - unsigned char id[20]; - struct sockaddr_storage ss; - int sslen; - time_t time; /* time of last message received */ - time_t reply_time; /* time of last correct reply received */ - time_t pinged_time; /* time of last request */ - int pinged; /* how many requests we sent since last reply */ - struct node *next; -}; - -struct bucket { - int af; - unsigned char first[20]; - int count; /* number of nodes */ - int time; /* time of last reply in this bucket */ - struct node *nodes; - struct sockaddr_storage cached; /* the address of a likely candidate */ - int cachedlen; - struct bucket *next; -}; - -struct search_node { - unsigned char id[20]; - struct sockaddr_storage ss; - int sslen; - time_t request_time; /* the time of the last unanswered request */ - time_t reply_time; /* the time of the last reply */ - int pinged; - unsigned char token[40]; - int token_len; - int replied; /* whether we have received a reply */ - int acked; /* whether they acked our announcement */ -}; - -/* When performing a search, we search for up to SEARCH_NODES closest nodes - to the destination, and use the additional ones to backtrack if any of - the target 8 turn out to be dead. */ -#define SEARCH_NODES 14 - -struct search { - unsigned short tid; - int af; - time_t step_time; /* the time of the last search_step */ - unsigned char id[20]; - unsigned short port; /* 0 for pure searches */ - int done; - struct search_node nodes[SEARCH_NODES]; - int numnodes; - struct search *next; -}; - -struct peer { - time_t time; - unsigned char ip[16]; - unsigned short len; - unsigned short port; -}; - -/* The maximum number of peers we store for a given hash. */ -#ifndef DHT_MAX_PEERS -#define DHT_MAX_PEERS 2048 -#endif - -/* The maximum number of hashes we're willing to track. */ -#ifndef DHT_MAX_HASHES -#define DHT_MAX_HASHES 16384 -#endif - -/* The maximum number of searches we keep data about. */ -#ifndef DHT_MAX_SEARCHES -#define DHT_MAX_SEARCHES 1024 -#endif - -/* The time after which we consider a search to be expirable. */ -#ifndef DHT_SEARCH_EXPIRE_TIME -#define DHT_SEARCH_EXPIRE_TIME (62 * 60) -#endif - -struct storage { - unsigned char id[20]; - int numpeers, maxpeers; - struct peer *peers; - struct storage *next; -}; - -static struct storage * find_storage(const unsigned char *id); -static void flush_search_node(struct search_node *n, struct search *sr); - -static int send_ping(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len); -static int send_pong(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len); -static int send_find_node(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len, - const unsigned char *target, int want, int confirm); -static int send_nodes_peers(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len, - const unsigned char *nodes, int nodes_len, - const unsigned char *nodes6, int nodes6_len, - int af, struct storage *st, - const unsigned char *token, int token_len); -static int send_closest_nodes(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len, - const unsigned char *id, int want, - int af, struct storage *st, - const unsigned char *token, int token_len); -static int send_get_peers(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len, - unsigned char *infohash, int want, int confirm); -static int send_announce_peer(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len, - unsigned char *infohas, unsigned short port, - unsigned char *token, int token_len, int confirm); -static int send_peer_announced(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len); -static int send_error(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len, - int code, const char *message); - -#define ERROR 0 -#define REPLY 1 -#define PING 2 -#define FIND_NODE 3 -#define GET_PEERS 4 -#define ANNOUNCE_PEER 5 - -#define WANT4 1 -#define WANT6 2 - -static int parse_message(const unsigned char *buf, int buflen, - unsigned char *tid_return, int *tid_len, - unsigned char *id_return, - unsigned char *info_hash_return, - unsigned char *target_return, - unsigned short *port_return, - unsigned char *token_return, int *token_len, - unsigned char *nodes_return, int *nodes_len, - unsigned char *nodes6_return, int *nodes6_len, - unsigned char *values_return, int *values_len, - unsigned char *values6_return, int *values6_len, - int *want_return); - -static const unsigned char zeroes[20] = {0}; -static const unsigned char ones[20] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF -}; -static const unsigned char v4prefix[16] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 -}; - -static int dht_socket = -1; -static int dht_socket6 = -1; - -static time_t search_time; -static time_t confirm_nodes_time; -static time_t rotate_secrets_time; - -static unsigned char myid[20]; -static int have_v = 0; -static unsigned char my_v[9]; -static unsigned char secret[8]; -static unsigned char oldsecret[8]; - -static struct bucket *buckets = NULL; -static struct bucket *buckets6 = NULL; -static struct storage *storage; -static int numstorage; - -static struct search *searches = NULL; -static int numsearches; -static unsigned short search_id; - -/* The maximum number of nodes that we snub. There is probably little - reason to increase this value. */ -#ifndef DHT_MAX_BLACKLISTED -#define DHT_MAX_BLACKLISTED 10 -#endif -static struct sockaddr_storage blacklist[DHT_MAX_BLACKLISTED]; -int next_blacklisted; - -static struct timeval now; -static time_t mybucket_grow_time, mybucket6_grow_time; -static time_t expire_stuff_time; - -#define MAX_TOKEN_BUCKET_TOKENS 400 -static time_t token_bucket_time; -static int token_bucket_tokens; - -FILE *dht_debug = NULL; - -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif -static void -debugf(const char *format, ...) -{ - va_list args; - va_start(args, format); - if(dht_debug) - vfprintf(dht_debug, format, args); - va_end(args); - if(dht_debug) - fflush(dht_debug); -} - -static void -debug_printable(const unsigned char *buf, int buflen) -{ - int i; - if(dht_debug) { - for(i = 0; i < buflen; i++) - putc(buf[i] >= 32 && buf[i] <= 126 ? buf[i] : '.', dht_debug); - } -} - -static void -print_hex(FILE *f, const unsigned char *buf, int buflen) -{ - int i; - for(i = 0; i < buflen; i++) - fprintf(f, "%02x", buf[i]); -} - -static int -is_martian(const struct sockaddr *sa) -{ - switch(sa->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in*)sa; - const unsigned char *address = (const unsigned char*)&sin->sin_addr; - return sin->sin_port == 0 || - (address[0] == 0) || - (address[0] == 127) || - ((address[0] & 0xE0) == 0xE0); - } - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; - const unsigned char *address = (const unsigned char*)&sin6->sin6_addr; - return sin6->sin6_port == 0 || - (address[0] == 0xFF) || - (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) || - (memcmp(address, zeroes, 15) == 0 && - (address[15] == 0 || address[15] == 1)) || - (memcmp(address, v4prefix, 12) == 0); - } - - default: - return 0; - } -} - -/* Forget about the ``XOR-metric''. An id is just a path from the - root of the tree, so bits are numbered from the start. */ - -static int -id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2) -{ - /* Memcmp is guaranteed to perform an unsigned comparison. */ - return memcmp(id1, id2, 20); -} - -/* Find the lowest 1 bit in an id. */ -static int -lowbit(const unsigned char *id) -{ - int i, j; - for(i = 19; i >= 0; i--) - if(id[i] != 0) - break; - - if(i < 0) - return -1; - - for(j = 7; j >= 0; j--) - if((id[i] & (0x80 >> j)) != 0) - break; - - return 8 * i + j; -} - -/* Find how many bits two ids have in common. */ -static int -common_bits(const unsigned char *id1, const unsigned char *id2) -{ - int i, j; - unsigned char xor; - for(i = 0; i < 20; i++) { - if(id1[i] != id2[i]) - break; - } - - if(i == 20) - return 160; - - xor = id1[i] ^ id2[i]; - - j = 0; - while((xor & 0x80) == 0) { - xor <<= 1; - j++; - } - - return 8 * i + j; -} - -/* Determine whether id1 or id2 is closer to ref */ -static int -xorcmp(const unsigned char *id1, const unsigned char *id2, - const unsigned char *ref) -{ - int i; - for(i = 0; i < 20; i++) { - unsigned char xor1, xor2; - if(id1[i] == id2[i]) - continue; - xor1 = id1[i] ^ ref[i]; - xor2 = id2[i] ^ ref[i]; - if(xor1 < xor2) - return -1; - else - return 1; - } - return 0; -} - -/* We keep buckets in a sorted linked list. A bucket b ranges from - b->first inclusive up to b->next->first exclusive. */ -static int -in_bucket(const unsigned char *id, struct bucket *b) -{ - return id_cmp(b->first, id) <= 0 && - (b->next == NULL || id_cmp(id, b->next->first) < 0); -} - -static struct bucket * -find_bucket(unsigned const char *id, int af) -{ - struct bucket *b = af == AF_INET ? buckets : buckets6; - - if(b == NULL) - return NULL; - - while(1) { - if(b->next == NULL) - return b; - if(id_cmp(id, b->next->first) < 0) - return b; - b = b->next; - } -} - -static struct bucket * -previous_bucket(struct bucket *b) -{ - struct bucket *p = b->af == AF_INET ? buckets : buckets6; - - if(b == p) - return NULL; - - while(1) { - if(p->next == NULL) - return NULL; - if(p->next == b) - return p; - p = p->next; - } -} - -/* Every bucket contains an unordered list of nodes. */ -static struct node * -find_node(const unsigned char *id, int af) -{ - struct bucket *b = find_bucket(id, af); - struct node *n; - - if(b == NULL) - return NULL; - - n = b->nodes; - while(n) { - if(id_cmp(n->id, id) == 0) - return n; - n = n->next; - } - return NULL; -} - -/* Return a random node in a bucket. */ -static struct node * -random_node(struct bucket *b) -{ - struct node *n; - int nn; - - if(b->count == 0) - return NULL; - - nn = random() % b->count; - n = b->nodes; - while(nn > 0 && n) { - n = n->next; - nn--; - } - return n; -} - -/* Return the middle id of a bucket. */ -static int -bucket_middle(struct bucket *b, unsigned char *id_return) -{ - int bit1 = lowbit(b->first); - int bit2 = b->next ? lowbit(b->next->first) : -1; - int bit = MAX(bit1, bit2) + 1; - - if(bit >= 160) - return -1; - - memcpy(id_return, b->first, 20); - id_return[bit / 8] |= (0x80 >> (bit % 8)); - return 1; -} - -/* Return a random id within a bucket. */ -static int -bucket_random(struct bucket *b, unsigned char *id_return) -{ - int bit1 = lowbit(b->first); - int bit2 = b->next ? lowbit(b->next->first) : -1; - int bit = MAX(bit1, bit2) + 1; - int i; - - if(bit >= 160) { - memcpy(id_return, b->first, 20); - return 1; - } - - memcpy(id_return, b->first, bit / 8); - id_return[bit / 8] = b->first[bit / 8] & (0xFF00 >> (bit % 8)); - id_return[bit / 8] |= random() & 0xFF >> (bit % 8); - for(i = bit / 8 + 1; i < 20; i++) - id_return[i] = random() & 0xFF; - return 1; -} - -/* Insert a new node into a bucket. */ -static struct node * -insert_node(struct node *node) -{ - struct bucket *b = find_bucket(node->id, node->ss.ss_family); - - if(b == NULL) - return NULL; - - node->next = b->nodes; - b->nodes = node; - b->count++; - return node; -} - -/* This is our definition of a known-good node. */ -static int -node_good(struct node *node) -{ - return - node->pinged <= 2 && - node->reply_time >= now.tv_sec - 7200 && - node->time >= now.tv_sec - 900; -} - -/* Our transaction-ids are 4-bytes long, with the first two bytes identi- - fying the kind of request, and the remaining two a sequence number in - host order. */ - -static void -make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno) -{ - tid_return[0] = prefix[0] & 0xFF; - tid_return[1] = prefix[1] & 0xFF; - memcpy(tid_return + 2, &seqno, 2); -} - -static int -tid_match(const unsigned char *tid, const char *prefix, - unsigned short *seqno_return) -{ - if(tid[0] == (prefix[0] & 0xFF) && tid[1] == (prefix[1] & 0xFF)) { - if(seqno_return) - memcpy(seqno_return, tid + 2, 2); - return 1; - } else - return 0; -} - -/* Every bucket caches the address of a likely node. Ping it. */ -static int -send_cached_ping(struct bucket *b) -{ - unsigned char tid[4]; - int rc; - /* We set family to 0 when there's no cached node. */ - if(b->cached.ss_family == 0) - return 0; - - debugf("Sending ping to cached node.\n"); - make_tid(tid, "pn", 0); - rc = send_ping((struct sockaddr*)&b->cached, b->cachedlen, tid, 4); - b->cached.ss_family = 0; - b->cachedlen = 0; - return rc; -} - -/* Called whenever we send a request to a node, increases the ping count - and, if that reaches 3, sends a ping to a new candidate. */ -static void -pinged(struct node *n, struct bucket *b) -{ - n->pinged++; - n->pinged_time = now.tv_sec; - if(n->pinged >= 3) - send_cached_ping(b ? b : find_bucket(n->id, n->ss.ss_family)); -} - -/* The internal blacklist is an LRU cache of nodes that have sent - incorrect messages. */ -static void -blacklist_node(const unsigned char *id, const struct sockaddr *sa, int salen) -{ - int i; - - debugf("Blacklisting broken node.\n"); - - if(id) { - struct node *n; - struct search *sr; - /* Make the node easy to discard. */ - n = find_node(id, sa->sa_family); - if(n) { - n->pinged = 3; - pinged(n, NULL); - } - /* Discard it from any searches in progress. */ - sr = searches; - while(sr) { - for(i = 0; i < sr->numnodes; i++) - if(id_cmp(sr->nodes[i].id, id) == 0) - flush_search_node(&sr->nodes[i], sr); - sr = sr->next; - } - } - /* And make sure we don't hear from it again. */ - memcpy(&blacklist[next_blacklisted], sa, salen); - next_blacklisted = (next_blacklisted + 1) % DHT_MAX_BLACKLISTED; -} - -static int -node_blacklisted(const struct sockaddr *sa, int salen) -{ - int i; - - if((unsigned)salen > sizeof(struct sockaddr_storage)) - abort(); - - if(dht_blacklisted(sa, salen)) - return 1; - - for(i = 0; i < DHT_MAX_BLACKLISTED; i++) { - if(memcmp(&blacklist[i], sa, salen) == 0) - return 1; - } - - return 0; -} - -/* Split a bucket into two equal parts. */ -static struct bucket * -split_bucket(struct bucket *b) -{ - struct bucket *new; - struct node *nodes; - int rc; - unsigned char new_id[20]; - - rc = bucket_middle(b, new_id); - if(rc < 0) - return NULL; - - new = calloc(1, sizeof(struct bucket)); - if(new == NULL) - return NULL; - - new->af = b->af; - - send_cached_ping(b); - - memcpy(new->first, new_id, 20); - new->time = b->time; - - nodes = b->nodes; - b->nodes = NULL; - b->count = 0; - new->next = b->next; - b->next = new; - while(nodes) { - struct node *n; - n = nodes; - nodes = nodes->next; - insert_node(n); - } - return b; -} - -/* We just learnt about a node, not necessarily a new one. Confirm is 1 if - the node sent a message, 2 if it sent us a reply. */ -static struct node * -new_node(const unsigned char *id, const struct sockaddr *sa, int salen, - int confirm) -{ - struct bucket *b = find_bucket(id, sa->sa_family); - struct node *n; - int mybucket, split; - - if(b == NULL) - return NULL; - - if(id_cmp(id, myid) == 0) - return NULL; - - if(is_martian(sa) || node_blacklisted(sa, salen)) - return NULL; - - mybucket = in_bucket(myid, b); - - if(confirm == 2) - b->time = now.tv_sec; - - n = b->nodes; - while(n) { - if(id_cmp(n->id, id) == 0) { - if(confirm || n->time < now.tv_sec - 15 * 60) { - /* Known node. Update stuff. */ - memcpy((struct sockaddr*)&n->ss, sa, salen); - if(confirm) - n->time = now.tv_sec; - if(confirm >= 2) { - n->reply_time = now.tv_sec; - n->pinged = 0; - n->pinged_time = 0; - } - } - return n; - } - n = n->next; - } - - /* New node. */ - - if(mybucket) { - if(sa->sa_family == AF_INET) - mybucket_grow_time = now.tv_sec; - else - mybucket6_grow_time = now.tv_sec; - } - - /* First, try to get rid of a known-bad node. */ - n = b->nodes; - while(n) { - if(n->pinged >= 3 && n->pinged_time < now.tv_sec - 15) { - memcpy(n->id, id, 20); - memcpy((struct sockaddr*)&n->ss, sa, salen); - n->time = confirm ? now.tv_sec : 0; - n->reply_time = confirm >= 2 ? now.tv_sec : 0; - n->pinged_time = 0; - n->pinged = 0; - return n; - } - n = n->next; - } - - if(b->count >= 8) { - /* Bucket full. Ping a dubious node */ - int dubious = 0; - n = b->nodes; - while(n) { - /* Pick the first dubious node that we haven't pinged in the - last 15 seconds. This gives nodes the time to reply, but - tends to concentrate on the same nodes, so that we get rid - of bad nodes fast. */ - if(!node_good(n)) { - dubious = 1; - if(n->pinged_time < now.tv_sec - 15) { - unsigned char tid[4]; - debugf("Sending ping to dubious node.\n"); - make_tid(tid, "pn", 0); - send_ping((struct sockaddr*)&n->ss, n->sslen, - tid, 4); - n->pinged++; - n->pinged_time = now.tv_sec; - break; - } - } - n = n->next; - } - - split = 0; - if(mybucket) { - if(!dubious) - split = 1; - /* If there's only one bucket, split eagerly. This is - incorrect unless there's more than 8 nodes in the DHT. */ - else if(b->af == AF_INET && buckets->next == NULL) - split = 1; - else if(b->af == AF_INET6 && buckets6->next == NULL) - split = 1; - } - - if(split) { - debugf("Splitting.\n"); - b = split_bucket(b); - return new_node(id, sa, salen, confirm); - } - - /* No space for this node. Cache it away for later. */ - if(confirm || b->cached.ss_family == 0) { - memcpy(&b->cached, sa, salen); - b->cachedlen = salen; - } - - return NULL; - } - - /* Create a new node. */ - n = calloc(1, sizeof(struct node)); - if(n == NULL) - return NULL; - memcpy(n->id, id, 20); - memcpy(&n->ss, sa, salen); - n->sslen = salen; - n->time = confirm ? now.tv_sec : 0; - n->reply_time = confirm >= 2 ? now.tv_sec : 0; - n->next = b->nodes; - b->nodes = n; - b->count++; - return n; -} - -/* Called periodically to purge known-bad nodes. Note that we're very - conservative here: broken nodes in the table don't do much harm, we'll - recover as soon as we find better ones. */ -static int -expire_buckets(struct bucket *b) -{ - while(b) { - struct node *n, *p; - int changed = 0; - - while(b->nodes && b->nodes->pinged >= 4) { - n = b->nodes; - b->nodes = n->next; - b->count--; - changed = 1; - free(n); - } - - p = b->nodes; - while(p) { - while(p->next && p->next->pinged >= 4) { - n = p->next; - p->next = n->next; - b->count--; - changed = 1; - free(n); - } - p = p->next; - } - - if(changed) - send_cached_ping(b); - - b = b->next; - } - expire_stuff_time = now.tv_sec + 120 + random() % 240; - return 1; -} - -/* While a search is in progress, we don't necessarily keep the nodes being - walked in the main bucket table. A search in progress is identified by - a unique transaction id, a short (and hence small enough to fit in the - transaction id of the protocol packets). */ - -static struct search * -find_search(unsigned short tid, int af) -{ - struct search *sr = searches; - while(sr) { - if(sr->tid == tid && sr->af == af) - return sr; - sr = sr->next; - } - return NULL; -} - -/* A search contains a list of nodes, sorted by decreasing distance to the - target. We just got a new candidate, insert it at the right spot or - discard it. */ - -static int -insert_search_node(unsigned char *id, - const struct sockaddr *sa, int salen, - struct search *sr, int replied, - unsigned char *token, int token_len) -{ - struct search_node *n; - int i, j; - - if(sa->sa_family != sr->af) { - debugf("Attempted to insert node in the wrong family.\n"); - return 0; - } - - for(i = 0; i < sr->numnodes; i++) { - if(id_cmp(id, sr->nodes[i].id) == 0) { - n = &sr->nodes[i]; - goto found; - } - if(xorcmp(id, sr->nodes[i].id, sr->id) < 0) - break; - } - - if(i == SEARCH_NODES) - return 0; - - if(sr->numnodes < SEARCH_NODES) - sr->numnodes++; - - for(j = sr->numnodes - 1; j > i; j--) { - sr->nodes[j] = sr->nodes[j - 1]; - } - - n = &sr->nodes[i]; - - memset(n, 0, sizeof(struct search_node)); - memcpy(n->id, id, 20); - -found: - memcpy(&n->ss, sa, salen); - n->sslen = salen; - - if(replied) { - n->replied = 1; - n->reply_time = now.tv_sec; - n->request_time = 0; - n->pinged = 0; - } - if(token) { - if(token_len >= 40) { - debugf("Eek! Overlong token.\n"); - } else { - memcpy(n->token, token, token_len); - n->token_len = token_len; - } - } - - return 1; -} - -static void -flush_search_node(struct search_node *n, struct search *sr) -{ - int i = n - sr->nodes, j; - for(j = i; j < sr->numnodes - 1; j++) - sr->nodes[j] = sr->nodes[j + 1]; - sr->numnodes--; -} - -static void -expire_searches(void) -{ - struct search *sr = searches, *previous = NULL; - - while(sr) { - struct search *next = sr->next; - if(sr->step_time < now.tv_sec - DHT_SEARCH_EXPIRE_TIME) { - if(previous) - previous->next = next; - else - searches = next; - free(sr); - numsearches--; - } else { - previous = sr; - } - sr = next; - } -} - -/* This must always return 0 or 1, never -1, not even on failure (see below). */ -static int -search_send_get_peers(struct search *sr, struct search_node *n) -{ - struct node *node; - unsigned char tid[4]; - - if(n == NULL) { - int i; - for(i = 0; i < sr->numnodes; i++) { - if(sr->nodes[i].pinged < 3 && !sr->nodes[i].replied && - sr->nodes[i].request_time < now.tv_sec - 15) - n = &sr->nodes[i]; - } - } - - if(!n || n->pinged >= 3 || n->replied || - n->request_time >= now.tv_sec - 15) - return 0; - - debugf("Sending get_peers.\n"); - make_tid(tid, "gp", sr->tid); - send_get_peers((struct sockaddr*)&n->ss, n->sslen, tid, 4, sr->id, -1, - n->reply_time >= now.tv_sec - 15); - n->pinged++; - n->request_time = now.tv_sec; - /* If the node happens to be in our main routing table, mark it - as pinged. */ - node = find_node(n->id, n->ss.ss_family); - if(node) pinged(node, NULL); - return 1; -} - -/* When a search is in progress, we periodically call search_step to send - further requests. */ -static void -search_step(struct search *sr, dht_callback *callback, void *closure) -{ - int i, j; - int all_done = 1; - - /* Check if the first 8 live nodes have replied. */ - j = 0; - for(i = 0; i < sr->numnodes && j < 8; i++) { - struct search_node *n = &sr->nodes[i]; - if(n->pinged >= 3) - continue; - if(!n->replied) { - all_done = 0; - break; - } - j++; - } - - if(all_done) { - if(sr->port == 0) { - goto done; - } else { - int all_acked = 1; - j = 0; - for(i = 0; i < sr->numnodes && j < 8; i++) { - struct search_node *n = &sr->nodes[i]; - struct node *node; - unsigned char tid[4]; - if(n->pinged >= 3) - continue; - /* A proposed extension to the protocol consists in - omitting the token when storage tables are full. While - I don't think this makes a lot of sense -- just sending - a positive reply is just as good --, let's deal with it. */ - if(n->token_len == 0) - n->acked = 1; - if(!n->acked) { - all_acked = 0; - debugf("Sending announce_peer.\n"); - make_tid(tid, "ap", sr->tid); - send_announce_peer((struct sockaddr*)&n->ss, - sizeof(struct sockaddr_storage), - tid, 4, sr->id, sr->port, - n->token, n->token_len, - n->reply_time >= now.tv_sec - 15); - n->pinged++; - n->request_time = now.tv_sec; - node = find_node(n->id, n->ss.ss_family); - if(node) pinged(node, NULL); - } - j++; - } - if(all_acked) - goto done; - } - sr->step_time = now.tv_sec; - return; - } - - if(sr->step_time + 15 >= now.tv_sec) - return; - - j = 0; - for(i = 0; i < sr->numnodes; i++) { - j += search_send_get_peers(sr, &sr->nodes[i]); - if(j >= 3) - break; - } - sr->step_time = now.tv_sec; - return; - - done: - sr->done = 1; - if(callback) - (*callback)(closure, - sr->af == AF_INET ? - DHT_EVENT_SEARCH_DONE : DHT_EVENT_SEARCH_DONE6, - sr->id, NULL, 0); - sr->step_time = now.tv_sec; -} - -static struct search * -new_search(void) -{ - struct search *sr, *oldest = NULL; - - /* Find the oldest done search */ - sr = searches; - while(sr) { - if(sr->done && - (oldest == NULL || oldest->step_time > sr->step_time)) - oldest = sr; - sr = sr->next; - } - - /* The oldest slot is expired. */ - if(oldest && oldest->step_time < now.tv_sec - DHT_SEARCH_EXPIRE_TIME) - return oldest; - - /* Allocate a new slot. */ - if(numsearches < DHT_MAX_SEARCHES) { - sr = calloc(1, sizeof(struct search)); - if(sr != NULL) { - sr->next = searches; - searches = sr; - numsearches++; - return sr; - } - } - - /* Oh, well, never mind. Reuse the oldest slot. */ - return oldest; -} - -/* Insert the contents of a bucket into a search structure. */ -static void -insert_search_bucket(struct bucket *b, struct search *sr) -{ - struct node *n; - n = b->nodes; - while(n) { - insert_search_node(n->id, (struct sockaddr*)&n->ss, n->sslen, - sr, 0, NULL, 0); - n = n->next; - } -} - -/* Start a search. If port is non-zero, perform an announce when the - search is complete. */ -int -dht_search(const unsigned char *id, int port, int af, - dht_callback *callback, void *closure) -{ - struct search *sr; - struct storage *st; - struct bucket *b = find_bucket(id, af); - - if(b == NULL) { - errno = EAFNOSUPPORT; - return -1; - } - - /* Try to answer this search locally. In a fully grown DHT this - is very unlikely, but people are running modified versions of - this code in private DHTs with very few nodes. What's wrong - with flooding? */ - if(callback) { - st = find_storage(id); - if(st) { - unsigned short swapped; - unsigned char buf[18]; - int i; - - debugf("Found local data (%d peers).\n", st->numpeers); - - for(i = 0; i < st->numpeers; i++) { - swapped = htons(st->peers[i].port); - if(st->peers[i].len == 4) { - memcpy(buf, st->peers[i].ip, 4); - memcpy(buf + 4, &swapped, 2); - (*callback)(closure, DHT_EVENT_VALUES, id, - (void*)buf, 6); - } else if(st->peers[i].len == 16) { - memcpy(buf, st->peers[i].ip, 16); - memcpy(buf + 16, &swapped, 2); - (*callback)(closure, DHT_EVENT_VALUES6, id, - (void*)buf, 18); - } - } - } - } - - sr = searches; - while(sr) { - if(sr->af == af && id_cmp(sr->id, id) == 0) - break; - sr = sr->next; - } - - if(sr) { - /* We're reusing data from an old search. Reusing the same tid - means that we can merge replies for both searches. */ - int i; - sr->done = 0; - again: - for(i = 0; i < sr->numnodes; i++) { - struct search_node *n; - n = &sr->nodes[i]; - /* Discard any doubtful nodes. */ - if(n->pinged >= 3 || n->reply_time < now.tv_sec - 7200) { - flush_search_node(n, sr); - goto again; - } - n->pinged = 0; - n->token_len = 0; - n->replied = 0; - n->acked = 0; - } - } else { - sr = new_search(); - if(sr == NULL) { - errno = ENOSPC; - return -1; - } - sr->af = af; - sr->tid = search_id++; - sr->step_time = 0; - memcpy(sr->id, id, 20); - sr->done = 0; - sr->numnodes = 0; - } - - sr->port = port; - - insert_search_bucket(b, sr); - - if(sr->numnodes < SEARCH_NODES) { - struct bucket *p = previous_bucket(b); - if(b->next) - insert_search_bucket(b->next, sr); - if(p) - insert_search_bucket(p, sr); - } - if(sr->numnodes < SEARCH_NODES) - insert_search_bucket(find_bucket(myid, af), sr); - - search_step(sr, callback, closure); - search_time = now.tv_sec; - return 1; -} - -/* A struct storage stores all the stored peer addresses for a given info - hash. */ - -static struct storage * -find_storage(const unsigned char *id) -{ - struct storage *st = storage; - - while(st) { - if(id_cmp(id, st->id) == 0) - break; - st = st->next; - } - return st; -} - -static int -storage_store(const unsigned char *id, - const struct sockaddr *sa, unsigned short port) -{ - int i, len; - struct storage *st; - unsigned char *ip; - - if(sa->sa_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in*)sa; - ip = (unsigned char*)&sin->sin_addr; - len = 4; - } else if(sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; - ip = (unsigned char*)&sin6->sin6_addr; - len = 16; - } else { - return -1; - } - - st = find_storage(id); - - if(st == NULL) { - if(numstorage >= DHT_MAX_HASHES) - return -1; - st = calloc(1, sizeof(struct storage)); - if(st == NULL) return -1; - memcpy(st->id, id, 20); - st->next = storage; - storage = st; - numstorage++; - } - - for(i = 0; i < st->numpeers; i++) { - if(st->peers[i].port == port && st->peers[i].len == len && - memcmp(st->peers[i].ip, ip, len) == 0) - break; - } - - if(i < st->numpeers) { - /* Already there, only need to refresh */ - st->peers[i].time = now.tv_sec; - return 0; - } else { - struct peer *p; - if(i >= st->maxpeers) { - /* Need to expand the array. */ - struct peer *new_peers; - int n; - if(st->maxpeers >= DHT_MAX_PEERS) - return 0; - n = st->maxpeers == 0 ? 2 : 2 * st->maxpeers; - n = MIN(n, DHT_MAX_PEERS); - new_peers = realloc(st->peers, n * sizeof(struct peer)); - if(new_peers == NULL) - return -1; - st->peers = new_peers; - st->maxpeers = n; - } - p = &st->peers[st->numpeers++]; - p->time = now.tv_sec; - p->len = len; - memcpy(p->ip, ip, len); - p->port = port; - return 1; - } -} - -static int -expire_storage(void) -{ - struct storage *st = storage, *previous = NULL; - while(st) { - int i = 0; - while(i < st->numpeers) { - if(st->peers[i].time < now.tv_sec - 32 * 60) { - if(i != st->numpeers - 1) - st->peers[i] = st->peers[st->numpeers - 1]; - st->numpeers--; - } else { - i++; - } - } - - if(st->numpeers == 0) { - free(st->peers); - if(previous) - previous->next = st->next; - else - storage = st->next; - free(st); - if(previous) - st = previous->next; - else - st = storage; - numstorage--; - if(numstorage < 0) { - debugf("Eek... numstorage became negative.\n"); - numstorage = 0; - } - } else { - previous = st; - st = st->next; - } - } - return 1; -} - -static int -rotate_secrets(void) -{ - int rc; - - rotate_secrets_time = now.tv_sec + 900 + random() % 1800; - - memcpy(oldsecret, secret, sizeof(secret)); - rc = dht_random_bytes(secret, sizeof(secret)); - - if(rc < 0) - return -1; - - return 1; -} - -#ifndef TOKEN_SIZE -#define TOKEN_SIZE 8 -#endif - -static void -make_token(const struct sockaddr *sa, int old, unsigned char *token_return) -{ - void *ip; - int iplen; - unsigned short port; - - if(sa->sa_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in*)sa; - ip = &sin->sin_addr; - iplen = 4; - port = htons(sin->sin_port); - } else if(sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; - ip = &sin6->sin6_addr; - iplen = 16; - port = htons(sin6->sin6_port); - } else { - abort(); - } - - dht_hash(token_return, TOKEN_SIZE, - old ? oldsecret : secret, sizeof(secret), - ip, iplen, (unsigned char*)&port, 2); -} -static int -token_match(const unsigned char *token, int token_len, - const struct sockaddr *sa) -{ - unsigned char t[TOKEN_SIZE]; - if(token_len != TOKEN_SIZE) - return 0; - make_token(sa, 0, t); - if(memcmp(t, token, TOKEN_SIZE) == 0) - return 1; - make_token(sa, 1, t); - if(memcmp(t, token, TOKEN_SIZE) == 0) - return 1; - return 0; -} - -int -dht_nodes(int af, int *good_return, int *dubious_return, int *cached_return, - int *incoming_return) -{ - int good = 0, dubious = 0, cached = 0, incoming = 0; - struct bucket *b = af == AF_INET ? buckets : buckets6; - - while(b) { - struct node *n = b->nodes; - while(n) { - if(node_good(n)) { - good++; - if(n->time > n->reply_time) - incoming++; - } else { - dubious++; - } - n = n->next; - } - if(b->cached.ss_family > 0) - cached++; - b = b->next; - } - if(good_return) - *good_return = good; - if(dubious_return) - *dubious_return = dubious; - if(cached_return) - *cached_return = cached; - if(incoming_return) - *incoming_return = incoming; - return good + dubious; -} - -static void -dump_bucket(FILE *f, struct bucket *b) -{ - struct node *n = b->nodes; - fprintf(f, "Bucket "); - print_hex(f, b->first, 20); - fprintf(f, " count %d age %d%s%s:\n", - b->count, (int)(now.tv_sec - b->time), - in_bucket(myid, b) ? " (mine)" : "", - b->cached.ss_family ? " (cached)" : ""); - while(n) { - char buf[512]; - unsigned short port; - fprintf(f, " Node "); - print_hex(f, n->id, 20); - if(n->ss.ss_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in*)&n->ss; - inet_ntop(AF_INET, &sin->sin_addr, buf, 512); - port = ntohs(sin->sin_port); - } else if(n->ss.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&n->ss; - inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 512); - port = ntohs(sin6->sin6_port); - } else { - snprintf(buf, 512, "unknown(%d)", n->ss.ss_family); - port = 0; - } - - if(n->ss.ss_family == AF_INET6) - fprintf(f, " [%s]:%d ", buf, port); - else - fprintf(f, " %s:%d ", buf, port); - if(n->time != n->reply_time) - fprintf(f, "age %ld, %ld", - (long)(now.tv_sec - n->time), - (long)(now.tv_sec - n->reply_time)); - else - fprintf(f, "age %ld", (long)(now.tv_sec - n->time)); - if(n->pinged) - fprintf(f, " (%d)", n->pinged); - if(node_good(n)) - fprintf(f, " (good)"); - fprintf(f, "\n"); - n = n->next; - } - -} - -void -dht_dump_tables(FILE *f) -{ - int i; - struct bucket *b; - struct storage *st = storage; - struct search *sr = searches; - - fprintf(f, "My id "); - print_hex(f, myid, 20); - fprintf(f, "\n"); - - b = buckets; - while(b) { - dump_bucket(f, b); - b = b->next; - } - - fprintf(f, "\n"); - - b = buckets6; - while(b) { - dump_bucket(f, b); - b = b->next; - } - - while(sr) { - fprintf(f, "\nSearch%s id ", sr->af == AF_INET6 ? " (IPv6)" : ""); - print_hex(f, sr->id, 20); - fprintf(f, " age %d%s\n", (int)(now.tv_sec - sr->step_time), - sr->done ? " (done)" : ""); - for(i = 0; i < sr->numnodes; i++) { - struct search_node *n = &sr->nodes[i]; - fprintf(f, "Node %d id ", i); - print_hex(f, n->id, 20); - fprintf(f, " bits %d age ", common_bits(sr->id, n->id)); - if(n->request_time) - fprintf(f, "%d, ", (int)(now.tv_sec - n->request_time)); - fprintf(f, "%d", (int)(now.tv_sec - n->reply_time)); - if(n->pinged) - fprintf(f, " (%d)", n->pinged); - fprintf(f, "%s%s.\n", - find_node(n->id, AF_INET) ? " (known)" : "", - n->replied ? " (replied)" : ""); - } - sr = sr->next; - } - - while(st) { - fprintf(f, "\nStorage "); - print_hex(f, st->id, 20); - fprintf(f, " %d/%d nodes:", st->numpeers, st->maxpeers); - for(i = 0; i < st->numpeers; i++) { - char buf[100]; - if(st->peers[i].len == 4) { - inet_ntop(AF_INET, st->peers[i].ip, buf, 100); - } else if(st->peers[i].len == 16) { - buf[0] = '['; - inet_ntop(AF_INET6, st->peers[i].ip, buf + 1, 98); - strcat(buf, "]"); - } else { - strcpy(buf, "???"); - } - fprintf(f, " %s:%u (%ld)", - buf, st->peers[i].port, - (long)(now.tv_sec - st->peers[i].time)); - } - st = st->next; - } - - fprintf(f, "\n\n"); - fflush(f); -} - -int -dht_init(int s, int s6, const unsigned char *id, const unsigned char *v) -{ - int rc; - - if(dht_socket >= 0 || dht_socket6 >= 0 || buckets || buckets6) { - errno = EBUSY; - return -1; - } - - searches = NULL; - numsearches = 0; - - storage = NULL; - numstorage = 0; - - if(s >= 0) { - buckets = calloc(sizeof(struct bucket), 1); - if(buckets == NULL) - return -1; - buckets->af = AF_INET; - - rc = set_nonblocking(s, 1); - if(rc < 0) - goto fail; - } - - if(s6 >= 0) { - buckets6 = calloc(sizeof(struct bucket), 1); - if(buckets6 == NULL) - return -1; - buckets6->af = AF_INET6; - - rc = set_nonblocking(s6, 1); - if(rc < 0) - goto fail; - } - - memcpy(myid, id, 20); - if(v) { - memcpy(my_v, "1:v4:", 5); - memcpy(my_v + 5, v, 4); - have_v = 1; - } else { - have_v = 0; - } - - gettimeofday(&now, NULL); - - mybucket_grow_time = now.tv_sec; - mybucket6_grow_time = now.tv_sec; - confirm_nodes_time = now.tv_sec + random() % 3; - - search_id = random() & 0xFFFF; - search_time = 0; - - next_blacklisted = 0; - - token_bucket_time = now.tv_sec; - token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS; - - memset(secret, 0, sizeof(secret)); - rc = rotate_secrets(); - if(rc < 0) - goto fail; - - dht_socket = s; - dht_socket6 = s6; - - expire_buckets(buckets); - expire_buckets(buckets6); - - return 1; - - fail: - free(buckets); - buckets = NULL; - return -1; -} - -int -dht_uninit() -{ - if(dht_socket < 0 && dht_socket6 < 0) { - errno = EINVAL; - return -1; - } - - dht_socket = -1; - dht_socket6 = -1; - - while(buckets) { - struct bucket *b = buckets; - buckets = b->next; - while(b->nodes) { - struct node *n = b->nodes; - b->nodes = n->next; - free(n); - } - free(b); - } - - while(buckets6) { - struct bucket *b = buckets6; - buckets6 = b->next; - while(b->nodes) { - struct node *n = b->nodes; - b->nodes = n->next; - free(n); - } - free(b); - } - - while(storage) { - struct storage *st = storage; - storage = storage->next; - free(st->peers); - free(st); - } - - while(searches) { - struct search *sr = searches; - searches = searches->next; - free(sr); - } - - return 1; -} - -/* Rate control for requests we receive. */ - -static int -token_bucket(void) -{ - if(token_bucket_tokens == 0) { - token_bucket_tokens = MIN(MAX_TOKEN_BUCKET_TOKENS, - 100 * (now.tv_sec - token_bucket_time)); - token_bucket_time = now.tv_sec; - } - - if(token_bucket_tokens == 0) - return 0; - - token_bucket_tokens--; - return 1; -} - -static int -neighbourhood_maintenance(int af) -{ - unsigned char id[20]; - struct bucket *b = find_bucket(myid, af); - struct bucket *q; - struct node *n; - - if(b == NULL) - return 0; - - memcpy(id, myid, 20); - id[19] = random() & 0xFF; - q = b; - if(q->next && (q->count == 0 || (random() & 7) == 0)) - q = b->next; - if(q->count == 0 || (random() & 7) == 0) { - struct bucket *r; - r = previous_bucket(b); - if(r && r->count > 0) - q = r; - } - - if(q) { - /* Since our node-id is the same in both DHTs, it's probably - profitable to query both families. */ - int want = dht_socket >= 0 && dht_socket6 >= 0 ? (WANT4 | WANT6) : -1; - n = random_node(q); - if(n) { - unsigned char tid[4]; - debugf("Sending find_node for%s neighborhood maintenance.\n", - af == AF_INET6 ? " IPv6" : ""); - make_tid(tid, "fn", 0); - send_find_node((struct sockaddr*)&n->ss, n->sslen, - tid, 4, id, want, - n->reply_time >= now.tv_sec - 15); - pinged(n, q); - } - return 1; - } - return 0; -} - -static int -bucket_maintenance(int af) -{ - struct bucket *b; - - b = af == AF_INET ? buckets : buckets6; - - while(b) { - struct bucket *q; - if(b->time < now.tv_sec - 600) { - /* This bucket hasn't seen any positive confirmation for a long - time. Pick a random id in this bucket's range, and send - a request to a random node. */ - unsigned char id[20]; - struct node *n; - int rc; - - rc = bucket_random(b, id); - if(rc < 0) - memcpy(id, b->first, 20); - - q = b; - /* If the bucket is empty, we try to fill it from a neighbour. - We also sometimes do it gratuitiously to recover from - buckets full of broken nodes. */ - if(q->next && (q->count == 0 || (random() & 7) == 0)) - q = b->next; - if(q->count == 0 || (random() & 7) == 0) { - struct bucket *r; - r = previous_bucket(b); - if(r && r->count > 0) - q = r; - } - - if(q) { - n = random_node(q); - if(n) { - unsigned char tid[4]; - int want = -1; - - if(dht_socket >= 0 && dht_socket6 >= 0) { - struct bucket *otherbucket; - otherbucket = - find_bucket(id, af == AF_INET ? AF_INET6 : AF_INET); - if(otherbucket && otherbucket->count < 8) - /* The corresponding bucket in the other family - is emptyish -- querying both is useful. */ - want = WANT4 | WANT6; - else if(random() % 37 == 0) - /* Most of the time, this just adds overhead. - However, it might help stitch back one of - the DHTs after a network collapse, so query - both, but only very occasionally. */ - want = WANT4 | WANT6; - } - - debugf("Sending find_node for%s bucket maintenance.\n", - af == AF_INET6 ? " IPv6" : ""); - make_tid(tid, "fn", 0); - send_find_node((struct sockaddr*)&n->ss, n->sslen, - tid, 4, id, want, - n->reply_time >= now.tv_sec - 15); - pinged(n, q); - /* In order to avoid sending queries back-to-back, - give up for now and reschedule us soon. */ - return 1; - } - } - } - b = b->next; - } - return 0; -} - -int -dht_periodic(const void *buf, size_t buflen, - const struct sockaddr *from, int fromlen, - time_t *tosleep, - dht_callback *callback, void *closure) -{ - gettimeofday(&now, NULL); - - if(buflen > 0) { - int message; - unsigned char tid[16], id[20], info_hash[20], target[20]; - unsigned char nodes[256], nodes6[1024], token[128]; - int tid_len = 16, token_len = 128; - int nodes_len = 256, nodes6_len = 1024; - unsigned short port; - unsigned char values[2048], values6[2048]; - int values_len = 2048, values6_len = 2048; - int want; - unsigned short ttid; - - if(is_martian(from)) - goto dontread; - - if(node_blacklisted(from, fromlen)) { - debugf("Received packet from blacklisted node.\n"); - goto dontread; - } - - if(((char*)buf)[buflen] != '\0') { - debugf("Unterminated message.\n"); - errno = EINVAL; - return -1; - } - - message = parse_message(buf, buflen, tid, &tid_len, id, info_hash, - target, &port, token, &token_len, - nodes, &nodes_len, nodes6, &nodes6_len, - values, &values_len, values6, &values6_len, - &want); - - if(message < 0 || message == ERROR || id_cmp(id, zeroes) == 0) { - debugf("Unparseable message: "); - debug_printable(buf, buflen); - debugf("\n"); - goto dontread; - } - - if(id_cmp(id, myid) == 0) { - debugf("Received message from self.\n"); - goto dontread; - } - - if(message > REPLY) { - /* Rate limit requests. */ - if(!token_bucket()) { - debugf("Dropping request due to rate limiting.\n"); - goto dontread; - } - } - - switch(message) { - case REPLY: - if(tid_len != 4) { - debugf("Broken node truncates transaction ids: "); - debug_printable(buf, buflen); - debugf("\n"); - /* This is really annoying, as it means that we will - time-out all our searches that go through this node. - Kill it. */ - blacklist_node(id, from, fromlen); - goto dontread; - } - if(tid_match(tid, "pn", NULL)) { - debugf("Pong!\n"); - new_node(id, from, fromlen, 2); - } else if(tid_match(tid, "fn", NULL) || - tid_match(tid, "gp", NULL)) { - int gp = 0; - struct search *sr = NULL; - if(tid_match(tid, "gp", &ttid)) { - gp = 1; - sr = find_search(ttid, from->sa_family); - } - debugf("Nodes found (%d+%d)%s!\n", nodes_len/26, nodes6_len/38, - gp ? " for get_peers" : ""); - if(nodes_len % 26 != 0 || nodes6_len % 38 != 0) { - debugf("Unexpected length for node info!\n"); - blacklist_node(id, from, fromlen); - } else if(gp && sr == NULL) { - debugf("Unknown search!\n"); - new_node(id, from, fromlen, 1); - } else { - int i; - new_node(id, from, fromlen, 2); - for(i = 0; i < nodes_len / 26; i++) { - unsigned char *ni = nodes + i * 26; - struct sockaddr_in sin; - if(id_cmp(ni, myid) == 0) - continue; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - memcpy(&sin.sin_addr, ni + 20, 4); - memcpy(&sin.sin_port, ni + 24, 2); - new_node(ni, (struct sockaddr*)&sin, sizeof(sin), 0); - if(sr && sr->af == AF_INET) { - insert_search_node(ni, - (struct sockaddr*)&sin, - sizeof(sin), - sr, 0, NULL, 0); - } - } - for(i = 0; i < nodes6_len / 38; i++) { - unsigned char *ni = nodes6 + i * 38; - struct sockaddr_in6 sin6; - if(id_cmp(ni, myid) == 0) - continue; - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - memcpy(&sin6.sin6_addr, ni + 20, 16); - memcpy(&sin6.sin6_port, ni + 36, 2); - new_node(ni, (struct sockaddr*)&sin6, sizeof(sin6), 0); - if(sr && sr->af == AF_INET6) { - insert_search_node(ni, - (struct sockaddr*)&sin6, - sizeof(sin6), - sr, 0, NULL, 0); - } - } - if(sr) - /* Since we received a reply, the number of - requests in flight has decreased. Let's push - another request. */ - search_send_get_peers(sr, NULL); - } - if(sr) { - insert_search_node(id, from, fromlen, sr, - 1, token, token_len); - if(values_len > 0 || values6_len > 0) { - debugf("Got values (%d+%d)!\n", - values_len / 6, values6_len / 18); - if(callback) { - if(values_len > 0) - (*callback)(closure, DHT_EVENT_VALUES, sr->id, - (void*)values, values_len); - - if(values6_len > 0) - (*callback)(closure, DHT_EVENT_VALUES6, sr->id, - (void*)values6, values6_len); - } - } - } - } else if(tid_match(tid, "ap", &ttid)) { - struct search *sr; - debugf("Got reply to announce_peer.\n"); - sr = find_search(ttid, from->sa_family); - if(!sr) { - debugf("Unknown search!\n"); - new_node(id, from, fromlen, 1); - } else { - int i; - new_node(id, from, fromlen, 2); - for(i = 0; i < sr->numnodes; i++) - if(id_cmp(sr->nodes[i].id, id) == 0) { - sr->nodes[i].request_time = 0; - sr->nodes[i].reply_time = now.tv_sec; - sr->nodes[i].acked = 1; - sr->nodes[i].pinged = 0; - break; - } - /* See comment for gp above. */ - search_send_get_peers(sr, NULL); - } - } else { - debugf("Unexpected reply: "); - debug_printable(buf, buflen); - debugf("\n"); - } - break; - case PING: - debugf("Ping (%d)!\n", tid_len); - new_node(id, from, fromlen, 1); - debugf("Sending pong.\n"); - send_pong(from, fromlen, tid, tid_len); - break; - case FIND_NODE: - debugf("Find node!\n"); - new_node(id, from, fromlen, 1); - debugf("Sending closest nodes (%d).\n", want); - send_closest_nodes(from, fromlen, - tid, tid_len, target, want, - 0, NULL, NULL, 0); - break; - case GET_PEERS: - debugf("Get_peers!\n"); - new_node(id, from, fromlen, 1); - if(id_cmp(info_hash, zeroes) == 0) { - debugf("Eek! Got get_peers with no info_hash.\n"); - send_error(from, fromlen, tid, tid_len, - 203, "Get_peers with no info_hash"); - break; - } else { - struct storage *st = find_storage(info_hash); - unsigned char token[TOKEN_SIZE]; - make_token(from, 0, token); - if(st && st->numpeers > 0) { - debugf("Sending found%s peers.\n", - from->sa_family == AF_INET6 ? " IPv6" : ""); - send_closest_nodes(from, fromlen, - tid, tid_len, - info_hash, want, - from->sa_family, st, - token, TOKEN_SIZE); - } else { - debugf("Sending nodes for get_peers.\n"); - send_closest_nodes(from, fromlen, - tid, tid_len, info_hash, want, - 0, NULL, token, TOKEN_SIZE); - } - } - break; - case ANNOUNCE_PEER: - debugf("Announce peer!\n"); - new_node(id, from, fromlen, 1); - if(id_cmp(info_hash, zeroes) == 0) { - debugf("Announce_peer with no info_hash.\n"); - send_error(from, fromlen, tid, tid_len, - 203, "Announce_peer with no info_hash"); - break; - } - if(!token_match(token, token_len, from)) { - debugf("Incorrect token for announce_peer.\n"); - send_error(from, fromlen, tid, tid_len, - 203, "Announce_peer with wrong token"); - break; - } - if(port == 0) { - debugf("Announce_peer with forbidden port %d.\n", port); - send_error(from, fromlen, tid, tid_len, - 203, "Announce_peer with forbidden port number"); - break; - } - storage_store(info_hash, from, port); - /* Note that if storage_store failed, we lie to the requestor. - This is to prevent them from backtracking, and hence - polluting the DHT. */ - debugf("Sending peer announced.\n"); - send_peer_announced(from, fromlen, tid, tid_len); - } - } - - dontread: - if(now.tv_sec >= rotate_secrets_time) - rotate_secrets(); - - if(now.tv_sec >= expire_stuff_time) { - expire_buckets(buckets); - expire_buckets(buckets6); - expire_storage(); - expire_searches(); - } - - if(search_time > 0 && now.tv_sec >= search_time) { - struct search *sr; - sr = searches; - while(sr) { - if(!sr->done && sr->step_time + 5 <= now.tv_sec) { - search_step(sr, callback, closure); - } - sr = sr->next; - } - - search_time = 0; - - sr = searches; - while(sr) { - if(!sr->done) { - time_t tm = sr->step_time + 15 + random() % 10; - if(search_time == 0 || search_time > tm) - search_time = tm; - } - sr = sr->next; - } - } - - if(now.tv_sec >= confirm_nodes_time) { - int soon = 0; - - soon |= bucket_maintenance(AF_INET); - soon |= bucket_maintenance(AF_INET6); - - if(!soon) { - if(mybucket_grow_time >= now.tv_sec - 150) - soon |= neighbourhood_maintenance(AF_INET); - if(mybucket6_grow_time >= now.tv_sec - 150) - soon |= neighbourhood_maintenance(AF_INET6); - } - - /* In order to maintain all buckets' age within 600 seconds, worst - case is roughly 27 seconds, assuming the table is 22 bits deep. - We want to keep a margin for neighborhood maintenance, so keep - this within 25 seconds. */ - if(soon) - confirm_nodes_time = now.tv_sec + 5 + random() % 20; - else - confirm_nodes_time = now.tv_sec + 60 + random() % 120; - } - - if(confirm_nodes_time > now.tv_sec) - *tosleep = confirm_nodes_time - now.tv_sec; - else - *tosleep = 0; - - if(search_time > 0) { - if(search_time <= now.tv_sec) - *tosleep = 0; - else if(*tosleep > search_time - now.tv_sec) - *tosleep = search_time - now.tv_sec; - } - - return 1; -} - -int -dht_get_nodes(struct sockaddr_in *sin, int *num, - struct sockaddr_in6 *sin6, int *num6) -{ - int i, j; - struct bucket *b; - struct node *n; - - i = 0; - - /* For restoring to work without discarding too many nodes, the list - must start with the contents of our bucket. */ - b = find_bucket(myid, AF_INET); - if(b == NULL) - goto no_ipv4; - - n = b->nodes; - while(n && i < *num) { - if(node_good(n)) { - sin[i] = *(struct sockaddr_in*)&n->ss; - i++; - } - n = n->next; - } - - b = buckets; - while(b && i < *num) { - if(!in_bucket(myid, b)) { - n = b->nodes; - while(n && i < *num) { - if(node_good(n)) { - sin[i] = *(struct sockaddr_in*)&n->ss; - i++; - } - n = n->next; - } - } - b = b->next; - } - - no_ipv4: - - j = 0; - - b = find_bucket(myid, AF_INET6); - if(b == NULL) - goto no_ipv6; - - n = b->nodes; - while(n && j < *num6) { - if(node_good(n)) { - sin6[j] = *(struct sockaddr_in6*)&n->ss; - j++; - } - n = n->next; - } - - b = buckets6; - while(b && j < *num6) { - if(!in_bucket(myid, b)) { - n = b->nodes; - while(n && j < *num6) { - if(node_good(n)) { - sin6[j] = *(struct sockaddr_in6*)&n->ss; - j++; - } - n = n->next; - } - } - b = b->next; - } - - no_ipv6: - - *num = i; - *num6 = j; - return i + j; -} - -int -dht_insert_node(const unsigned char *id, struct sockaddr *sa, int salen) -{ - struct node *n; - - if(sa->sa_family != AF_INET) { - errno = EAFNOSUPPORT; - return -1; - } - - n = new_node(id, (struct sockaddr*)sa, salen, 0); - return !!n; -} - -int -dht_ping_node(struct sockaddr *sa, int salen) -{ - unsigned char tid[4]; - - debugf("Sending ping.\n"); - make_tid(tid, "pn", 0); - return send_ping(sa, salen, tid, 4); -} - -/* We could use a proper bencoding printer and parser, but the format of - DHT messages is fairly stylised, so this seemed simpler. */ - -#define CHECK(offset, delta, size) \ - if(delta < 0 || offset + delta > size) goto fail - -#define INC(offset, delta, size) \ - CHECK(offset, delta, size); \ - offset += delta - -#define COPY(buf, offset, src, delta, size) \ - CHECK(offset, delta, size); \ - memcpy(buf + offset, src, delta); \ - offset += delta; - -#define ADD_V(buf, offset, size) \ - if(have_v) { \ - COPY(buf, offset, my_v, sizeof(my_v), size); \ - } - -static int -dht_send(const void *buf, size_t len, int flags, - const struct sockaddr *sa, int salen) -{ - int s; - - if(salen == 0) - abort(); - - if(node_blacklisted(sa, salen)) { - debugf("Attempting to send to blacklisted node.\n"); - errno = EPERM; - return -1; - } - - if(sa->sa_family == AF_INET) - s = dht_socket; - else if(sa->sa_family == AF_INET6) - s = dht_socket6; - else - s = -1; - - if(s < 0) { - errno = EAFNOSUPPORT; - return -1; - } - - return sendto(s, buf, len, flags, sa, salen); -} - -int -send_ping(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len) -{ - char buf[512]; - int i = 0, rc; - rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); - COPY(buf, i, myid, 20, 512); - rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len); - INC(i, rc, 512); - COPY(buf, i, tid, tid_len, 512); - ADD_V(buf, i, 512); - rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); - return dht_send(buf, i, 0, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -int -send_pong(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len) -{ - char buf[512]; - int i = 0, rc; - rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512); - COPY(buf, i, myid, 20, 512); - rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512); - COPY(buf, i, tid, tid_len, 512); - ADD_V(buf, i, 512); - rc = snprintf(buf + i, 512 - i, "1:y1:re"); INC(i, rc, 512); - return dht_send(buf, i, 0, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -int -send_find_node(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len, - const unsigned char *target, int want, int confirm) -{ - char buf[512]; - int i = 0, rc; - rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); - COPY(buf, i, myid, 20, 512); - rc = snprintf(buf + i, 512 - i, "6:target20:"); INC(i, rc, 512); - COPY(buf, i, target, 20, 512); - if(want > 0) { - rc = snprintf(buf + i, 512 - i, "4:wantl%s%se", - (want & WANT4) ? "2:n4" : "", - (want & WANT6) ? "2:n6" : ""); - INC(i, rc, 512); - } - rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len); - INC(i, rc, 512); - COPY(buf, i, tid, tid_len, 512); - ADD_V(buf, i, 512); - rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); - return dht_send(buf, i, confirm ? MSG_CONFIRM : 0, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -int -send_nodes_peers(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len, - const unsigned char *nodes, int nodes_len, - const unsigned char *nodes6, int nodes6_len, - int af, struct storage *st, - const unsigned char *token, int token_len) -{ - char buf[2048]; - int i = 0, rc, j0, j, k, len; - - rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:"); INC(i, rc, 2048); - COPY(buf, i, myid, 20, 2048); - if(nodes_len > 0) { - rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len); - INC(i, rc, 2048); - COPY(buf, i, nodes, nodes_len, 2048); - } - if(nodes6_len > 0) { - rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len); - INC(i, rc, 2048); - COPY(buf, i, nodes6, nodes6_len, 2048); - } - if(token_len > 0) { - rc = snprintf(buf + i, 2048 - i, "5:token%d:", token_len); - INC(i, rc, 2048); - COPY(buf, i, token, token_len, 2048); - } - - if(st && st->numpeers > 0) { - /* We treat the storage as a circular list, and serve a randomly - chosen slice. In order to make sure we fit within 1024 octets, - we limit ourselves to 50 peers. */ - - len = af == AF_INET ? 4 : 16; - j0 = random() % st->numpeers; - j = j0; - k = 0; - - rc = snprintf(buf + i, 2048 - i, "6:valuesl"); INC(i, rc, 2048); - do { - if(st->peers[j].len == len) { - unsigned short swapped; - swapped = htons(st->peers[j].port); - rc = snprintf(buf + i, 2048 - i, "%d:", len + 2); - INC(i, rc, 2048); - COPY(buf, i, st->peers[j].ip, len, 2048); - COPY(buf, i, &swapped, 2, 2048); - k++; - } - j = (j + 1) % st->numpeers; - } while(j != j0 && k < 50); - rc = snprintf(buf + i, 2048 - i, "e"); INC(i, rc, 2048); - } - - rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len); INC(i, rc, 2048); - COPY(buf, i, tid, tid_len, 2048); - ADD_V(buf, i, 2048); - rc = snprintf(buf + i, 2048 - i, "1:y1:re"); INC(i, rc, 2048); - - return dht_send(buf, i, 0, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -static int -insert_closest_node(unsigned char *nodes, int numnodes, - const unsigned char *id, struct node *n) -{ - int i, size; - - if(n->ss.ss_family == AF_INET) - size = 26; - else if(n->ss.ss_family == AF_INET6) - size = 38; - else - abort(); - - for(i = 0; i< numnodes; i++) { - if(id_cmp(n->id, nodes + size * i) == 0) - return numnodes; - if(xorcmp(n->id, nodes + size * i, id) < 0) - break; - } - - if(i == 8) - return numnodes; - - if(numnodes < 8) - numnodes++; - - if(i < numnodes - 1) - memmove(nodes + size * (i + 1), nodes + size * i, - size * (numnodes - i - 1)); - - if(n->ss.ss_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in*)&n->ss; - memcpy(nodes + size * i, n->id, 20); - memcpy(nodes + size * i + 20, &sin->sin_addr, 4); - memcpy(nodes + size * i + 24, &sin->sin_port, 2); - } else if(n->ss.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&n->ss; - memcpy(nodes + size * i, n->id, 20); - memcpy(nodes + size * i + 20, &sin6->sin6_addr, 16); - memcpy(nodes + size * i + 36, &sin6->sin6_port, 2); - } else { - abort(); - } - - return numnodes; -} - -static int -buffer_closest_nodes(unsigned char *nodes, int numnodes, - const unsigned char *id, struct bucket *b) -{ - struct node *n = b->nodes; - while(n) { - if(node_good(n)) - numnodes = insert_closest_node(nodes, numnodes, id, n); - n = n->next; - } - return numnodes; -} - -int -send_closest_nodes(const struct sockaddr *sa, int salen, - const unsigned char *tid, int tid_len, - const unsigned char *id, int want, - int af, struct storage *st, - const unsigned char *token, int token_len) -{ - unsigned char nodes[8 * 26]; - unsigned char nodes6[8 * 38]; - int numnodes = 0, numnodes6 = 0; - struct bucket *b; - - if(want < 0) - want = sa->sa_family == AF_INET ? WANT4 : WANT6; - - if((want & WANT4)) { - b = find_bucket(id, AF_INET); - if(b) { - numnodes = buffer_closest_nodes(nodes, numnodes, id, b); - if(b->next) - numnodes = buffer_closest_nodes(nodes, numnodes, id, b->next); - b = previous_bucket(b); - if(b) - numnodes = buffer_closest_nodes(nodes, numnodes, id, b); - } - } - - if((want & WANT6)) { - b = find_bucket(id, AF_INET6); - if(b) { - numnodes6 = buffer_closest_nodes(nodes6, numnodes6, id, b); - if(b->next) - numnodes6 = - buffer_closest_nodes(nodes6, numnodes6, id, b->next); - b = previous_bucket(b); - if(b) - numnodes6 = buffer_closest_nodes(nodes6, numnodes6, id, b); - } - } - debugf(" (%d+%d nodes.)\n", numnodes, numnodes6); - - return send_nodes_peers(sa, salen, tid, tid_len, - nodes, numnodes * 26, - nodes6, numnodes6 * 38, - af, st, token, token_len); -} - -int -send_get_peers(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len, unsigned char *infohash, - int want, int confirm) -{ - char buf[512]; - int i = 0, rc; - - rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); - COPY(buf, i, myid, 20, 512); - rc = snprintf(buf + i, 512 - i, "9:info_hash20:"); INC(i, rc, 512); - COPY(buf, i, infohash, 20, 512); - if(want > 0) { - rc = snprintf(buf + i, 512 - i, "4:wantl%s%se", - (want & WANT4) ? "2:n4" : "", - (want & WANT6) ? "2:n6" : ""); - INC(i, rc, 512); - } - rc = snprintf(buf + i, 512 - i, "e1:q9:get_peers1:t%d:", tid_len); - INC(i, rc, 512); - COPY(buf, i, tid, tid_len, 512); - ADD_V(buf, i, 512); - rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); - return dht_send(buf, i, confirm ? MSG_CONFIRM : 0, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -int -send_announce_peer(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len, - unsigned char *infohash, unsigned short port, - unsigned char *token, int token_len, int confirm) -{ - char buf[512]; - int i = 0, rc; - - rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); - COPY(buf, i, myid, 20, 512); - rc = snprintf(buf + i, 512 - i, "9:info_hash20:"); INC(i, rc, 512); - COPY(buf, i, infohash, 20, 512); - rc = snprintf(buf + i, 512 - i, "4:porti%ue5:token%d:", (unsigned)port, - token_len); - INC(i, rc, 512); - COPY(buf, i, token, token_len, 512); - rc = snprintf(buf + i, 512 - i, "e1:q13:announce_peer1:t%d:", tid_len); - INC(i, rc, 512); - COPY(buf, i, tid, tid_len, 512); - ADD_V(buf, i, 512); - rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); - - return dht_send(buf, i, confirm ? 0 : MSG_CONFIRM, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -static int -send_peer_announced(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len) -{ - char buf[512]; - int i = 0, rc; - - rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512); - COPY(buf, i, myid, 20, 512); - rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); - INC(i, rc, 512); - COPY(buf, i, tid, tid_len, 512); - ADD_V(buf, i, 512); - rc = snprintf(buf + i, 512 - i, "1:y1:re"); INC(i, rc, 512); - return dht_send(buf, i, 0, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -static int -send_error(const struct sockaddr *sa, int salen, - unsigned char *tid, int tid_len, - int code, const char *message) -{ - char buf[512]; - int i = 0, rc; - - rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:", - code, (int)strlen(message)); - INC(i, rc, 512); - COPY(buf, i, message, (int)strlen(message), 512); - rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512); - COPY(buf, i, tid, tid_len, 512); - ADD_V(buf, i, 512); - rc = snprintf(buf + i, 512 - i, "1:y1:ee"); INC(i, rc, 512); - return dht_send(buf, i, 0, sa, salen); - - fail: - errno = ENOSPC; - return -1; -} - -#undef CHECK -#undef INC -#undef COPY -#undef ADD_V - -#ifdef HAVE_MEMMEM - -static void * -dht_memmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen) -{ - return memmem(haystack, haystacklen, needle, needlelen); -} - -#else - -static void * -dht_memmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen) -{ - const char *h = haystack; - const char *n = needle; - size_t i; - - /* size_t is unsigned */ - if(needlelen > haystacklen) - return NULL; - - for(i = 0; i <= haystacklen - needlelen; i++) { - if(memcmp(h + i, n, needlelen) == 0) - return (void*)(h + i); - } - return NULL; -} - -#endif - -static int -parse_message(const unsigned char *buf, int buflen, - unsigned char *tid_return, int *tid_len, - unsigned char *id_return, unsigned char *info_hash_return, - unsigned char *target_return, unsigned short *port_return, - unsigned char *token_return, int *token_len, - unsigned char *nodes_return, int *nodes_len, - unsigned char *nodes6_return, int *nodes6_len, - unsigned char *values_return, int *values_len, - unsigned char *values6_return, int *values6_len, - int *want_return) -{ - const unsigned char *p; - - /* This code will happily crash if the buffer is not NUL-terminated. */ - if(buf[buflen] != '\0') { - debugf("Eek! parse_message with unterminated buffer.\n"); - return -1; - } - -#define CHECK(ptr, len) \ - if(((unsigned char*)ptr) + (len) > (buf) + (buflen)) goto overflow; - - if(tid_return) { - p = dht_memmem(buf, buflen, "1:t", 3); - if(p) { - long l; - char *q; - l = strtol((char*)p + 3, &q, 10); - if(q && *q == ':' && l > 0 && l < *tid_len) { - CHECK(q + 1, l); - memcpy(tid_return, q + 1, l); - *tid_len = l; - } else - *tid_len = 0; - } - } - if(id_return) { - p = dht_memmem(buf, buflen, "2:id20:", 7); - if(p) { - CHECK(p + 7, 20); - memcpy(id_return, p + 7, 20); - } else { - memset(id_return, 0, 20); - } - } - if(info_hash_return) { - p = dht_memmem(buf, buflen, "9:info_hash20:", 14); - if(p) { - CHECK(p + 14, 20); - memcpy(info_hash_return, p + 14, 20); - } else { - memset(info_hash_return, 0, 20); - } - } - if(port_return) { - p = dht_memmem(buf, buflen, "porti", 5); - if(p) { - long l; - char *q; - l = strtol((char*)p + 5, &q, 10); - if(q && *q == 'e' && l > 0 && l < 0x10000) - *port_return = l; - else - *port_return = 0; - } else - *port_return = 0; - } - if(target_return) { - p = dht_memmem(buf, buflen, "6:target20:", 11); - if(p) { - CHECK(p + 11, 20); - memcpy(target_return, p + 11, 20); - } else { - memset(target_return, 0, 20); - } - } - if(token_return) { - p = dht_memmem(buf, buflen, "5:token", 7); - if(p) { - long l; - char *q; - l = strtol((char*)p + 7, &q, 10); - if(q && *q == ':' && l > 0 && l < *token_len) { - CHECK(q + 1, l); - memcpy(token_return, q + 1, l); - *token_len = l; - } else - *token_len = 0; - } else - *token_len = 0; - } - - if(nodes_len) { - p = dht_memmem(buf, buflen, "5:nodes", 7); - if(p) { - long l; - char *q; - l = strtol((char*)p + 7, &q, 10); - if(q && *q == ':' && l > 0 && l < *nodes_len) { - CHECK(q + 1, l); - memcpy(nodes_return, q + 1, l); - *nodes_len = l; - } else - *nodes_len = 0; - } else - *nodes_len = 0; - } - - if(nodes6_len) { - p = dht_memmem(buf, buflen, "6:nodes6", 8); - if(p) { - long l; - char *q; - l = strtol((char*)p + 8, &q, 10); - if(q && *q == ':' && l > 0 && l < *nodes6_len) { - CHECK(q + 1, l); - memcpy(nodes6_return, q + 1, l); - *nodes6_len = l; - } else - *nodes6_len = 0; - } else - *nodes6_len = 0; - } - - if(values_len || values6_len) { - p = dht_memmem(buf, buflen, "6:valuesl", 9); - if(p) { - int i = p - buf + 9; - int j = 0, j6 = 0; - while(1) { - long l; - char *q; - l = strtol((char*)buf + i, &q, 10); - if(q && *q == ':' && l > 0) { - CHECK(q + 1, l); - i = q + 1 + l - (char*)buf; - if(l == 6) { - if(j + l > *values_len) - continue; - memcpy((char*)values_return + j, q + 1, l); - j += l; - } else if(l == 18) { - if(j6 + l > *values6_len) - continue; - memcpy((char*)values6_return + j6, q + 1, l); - j6 += l; - } else { - debugf("Received weird value -- %d bytes.\n", (int)l); - } - } else { - break; - } - } - if(i >= buflen || buf[i] != 'e') - debugf("eek... unexpected end for values.\n"); - if(values_len) - *values_len = j; - if(values6_len) - *values6_len = j6; - } else { - if(values_len) - *values_len = 0; - if(values6_len) - *values6_len = 0; - } - } - - if(want_return) { - p = dht_memmem(buf, buflen, "4:wantl", 7); - if(p) { - int i = p - buf + 7; - *want_return = 0; - while(buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' && - i + 2 + buf[i] - '0' < buflen) { - CHECK(buf + i + 2, buf[i] - '0'); - if(buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0) - *want_return |= WANT4; - else if(buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0) - *want_return |= WANT6; - else - debugf("eek... unexpected want flag (%c)\n", buf[i]); - i += 2 + buf[i] - '0'; - } - if(i >= buflen || buf[i] != 'e') - debugf("eek... unexpected end for want.\n"); - } else { - *want_return = -1; - } - } - -#undef CHECK - - if(dht_memmem(buf, buflen, "1:y1:r", 6)) - return REPLY; - if(dht_memmem(buf, buflen, "1:y1:e", 6)) - return ERROR; - if(!dht_memmem(buf, buflen, "1:y1:q", 6)) - return -1; - if(dht_memmem(buf, buflen, "1:q4:ping", 9)) - return PING; - if(dht_memmem(buf, buflen, "1:q9:find_node", 14)) - return FIND_NODE; - if(dht_memmem(buf, buflen, "1:q9:get_peers", 14)) - return GET_PEERS; - if(dht_memmem(buf, buflen, "1:q13:announce_peer", 19)) - return ANNOUNCE_PEER; - return -1; - - overflow: - debugf("Truncated message.\n"); - return -1; -} diff --git a/third-party/dht/dht.h b/third-party/dht/dht.h deleted file mode 100644 index 2a0c63323..000000000 --- a/third-party/dht/dht.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright (c) 2009-2011 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -typedef void -dht_callback(void *closure, int event, - const unsigned char *info_hash, - const void *data, size_t data_len); - -#define DHT_EVENT_NONE 0 -#define DHT_EVENT_VALUES 1 -#define DHT_EVENT_VALUES6 2 -#define DHT_EVENT_SEARCH_DONE 3 -#define DHT_EVENT_SEARCH_DONE6 4 - -extern FILE *dht_debug; - -int dht_init(int s, int s6, const unsigned char *id, const unsigned char *v); -int dht_insert_node(const unsigned char *id, struct sockaddr *sa, int salen); -int dht_ping_node(struct sockaddr *sa, int salen); -int dht_periodic(const void *buf, size_t buflen, - const struct sockaddr *from, int fromlen, - time_t *tosleep, dht_callback *callback, void *closure); -int dht_search(const unsigned char *id, int port, int af, - dht_callback *callback, void *closure); -int dht_nodes(int af, - int *good_return, int *dubious_return, int *cached_return, - int *incoming_return); -void dht_dump_tables(FILE *f); -int dht_get_nodes(struct sockaddr_in *sin, int *num, - struct sockaddr_in6 *sin6, int *num6); -int dht_uninit(void); - -/* This must be provided by the user. */ -int dht_blacklisted(const struct sockaddr *sa, int salen); -void dht_hash(void *hash_return, int hash_size, - const void *v1, int len1, - const void *v2, int len2, - const void *v3, int len3); -int dht_random_bytes(void *buf, size_t size); diff --git a/third-party/libb64/AUTHORS b/third-party/libb64/AUTHORS deleted file mode 100644 index bf4a9f4e0..000000000 --- a/third-party/libb64/AUTHORS +++ /dev/null @@ -1,15 +0,0 @@ -libb64: Base64 Encoding/Decoding Routines -====================================== - -Authors: -------- - -Chris Venter chris.venter@gmail.com http://controlaltfire.com - -Contributors: ------------- - -Mario Rugiero -Shlok Datye -Peter K. Lee - diff --git a/third-party/libb64/CHANGELOG b/third-party/libb64/CHANGELOG deleted file mode 100644 index c1c0844ed..000000000 --- a/third-party/libb64/CHANGELOG +++ /dev/null @@ -1,33 +0,0 @@ -libb64: Base64 Encoding/Decoding Routines -====================================== - -## Changelog ## - -Version 1.2.1 Release ---------------------- -Fixed a long-standing bug in src/cdecode.c where value_in was not correctly -checked against the bounds [0..decoding_size) -Thanks to both Mario Rugiero and Shlok Datye for pointing this out. -Added some simple example code to answer some of the most common misconceptions -people have about the library usage. - -Version 1.2 Release -------------------- -Removed the b64dec, b64enc, encoder and decoder programs in favour of -a better example, called base64, which encodes and decodes -depending on its arguments. - -Created a solution for Microsoft Visual Studio C++ Express 2010 -edition, which simply builds the base64 example as a console application. - -Version 1.1 Release -------------------- -Modified encode.h to (correctly) read from the iostream argument, -instead of std::cin. -Thanks to Peter K. Lee for the heads-up. - -No API changes. - -Version 1.0 Release -------------------- -The current content is the changeset. diff --git a/third-party/libb64/INSTALL b/third-party/libb64/INSTALL deleted file mode 100644 index b05f5db69..000000000 --- a/third-party/libb64/INSTALL +++ /dev/null @@ -1,44 +0,0 @@ -libb64: Base64 Encoding/Decoding Routines -====================================== - -Requirements: ------------- -This piece of software has minimal requirements. - -I have tested it on the following systems: - -- a Linux machine, with the following specs: -(this was the original development machine) - * FedoraCore 4 - * kernel v. 2.6.11 (stock FC4 kernel) - * gcc version 4.0.1 20050727 (Red Hat 4.0.1-5) - * glibc-2.3.5-10 - * make v. 3.80 - * some arb version of makedepend - -- Windows XP machine - * MSYS 1.0 - * MinGW 5.1.4 - * gcc version 3.4.5 (mingw-vista special r3) - -- Windows XP machine (same as above) - * Microsoft Visual Studio 2010, Version 10.0.30319.1 RTMRel - -Barring any serious screwups on my part, this code should compile and run sweetly -under Cygwin and other systems too. If you DO get it running under some weird arch/os setup, -send me a mail, please. - -Compiling: ---------- -There is no configure. It would be overkill for something so simple... -Run make in the root directory. - -Installing: ----------- -Since the current targets are a standalone executable and a static library -(fancy name for archive) with some headers, an install script has not been implemented yet. -Simply copy the executable into your path, and use it. - --- -peace out -Chris diff --git a/third-party/libb64/LICENSE b/third-party/libb64/LICENSE deleted file mode 100644 index a6b56069e..000000000 --- a/third-party/libb64/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -Copyright-Only Dedication (based on United States law) -or Public Domain Certification - -The person or persons who have associated work with this document (the -"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of -his knowledge, the work of authorship identified is in the public domain of the -country from which the work is published, or (b) hereby dedicates whatever -copyright the dedicators holds in the work of authorship identified below (the -"Work") to the public domain. A certifier, moreover, dedicates any copyright -interest he may have in the associated work, and for these purposes, is -described as a "dedicator" below. - -A certifier has taken reasonable steps to verify the copyright status of this -work. Certifier recognizes that his good faith efforts may not shield him from -liability if in fact the work certified is not in the public domain. - -Dedicator makes this dedication for the benefit of the public at large and to -the detriment of the Dedicator's heirs and successors. Dedicator intends this -dedication to be an overt act of relinquishment in perpetuity of all present -and future rights under copyright law, whether vested or contingent, in the -Work. Dedicator understands that such relinquishment of all rights includes -the relinquishment of all rights to enforce (by lawsuit or otherwise) those -copyrights in the Work. - -Dedicator recognizes that, once placed in the public domain, the Work may be -freely reproduced, distributed, transmitted, used, modified, built upon, or -otherwise exploited by anyone for any purpose, commercial or non-commercial, -and in any way, including by methods that have not yet been invented or -conceived. \ No newline at end of file diff --git a/third-party/libb64/Makefile.am b/third-party/libb64/Makefile.am deleted file mode 100644 index 4d0cd4232..000000000 --- a/third-party/libb64/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -noinst_LIBRARIES = libb64.a -libb64_a_SOURCES = cdecode.c cencode.c -noinst_HEADERS = b64/cdecode.h b64/cencode.h -EXTRA_DIST = AUTHORS CHANGELOG INSTALL LICENSE README diff --git a/third-party/libb64/README b/third-party/libb64/README deleted file mode 100644 index 132f02f50..000000000 --- a/third-party/libb64/README +++ /dev/null @@ -1,143 +0,0 @@ -b64: Base64 Encoding/Decoding Routines -====================================== - -Overview: --------- -libb64 is a library of ANSI C routines for fast encoding/decoding data into and -from a base64-encoded format. C++ wrappers are included, as well as the source -code for standalone encoding and decoding executables. - -base64 consists of ASCII text, and is therefore a useful encoding for storing -binary data in a text file, such as xml, or sending binary data over text-only -email. - -References: ----------- -* Wikipedia article: - http://en.wikipedia.org/wiki/Base64 -* base64, another implementation of a commandline en/decoder: - http://www.fourmilab.ch/webtools/base64/ - -Why? ---- -I did this because I need an implementation of base64 encoding and decoding, -without any licensing problems. Most OS implementations are released under -either the GNU/GPL, or a BSD-variant, which is not what I require. - -Also, the chance to actually use the co-routine implementation in code is rare, -and its use here is fitting. I couldn't pass up the chance. -For more information on this technique, see "Coroutines in C", by Simon Tatham, -which can be found online here: -http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - -So then, under which license do I release this code? On to the next section... - -License: -------- -This work is released under into the Public Domain. -It basically boils down to this: I put this work in the public domain, and you -can take it and do whatever you want with it. - -An example of this "license" is the Creative Commons Public Domain License, a -copy of which can be found in the LICENSE file, and also online at -http://creativecommons.org/licenses/publicdomain/ - -Commandline Use: ---------------- -There is a new executable available, it is simply called base64. -It can encode and decode files, as instructed by the user. - -To encode a file: -$ ./base64 -e filea fileb -fileb will now be the base64-encoded version of filea. - -To decode a file: -$ ./base64 -d fileb filec -filec will now be identical to filea. - -Programming: ------------ -Some C++ wrappers are provided as well, so you don't have to get your hands -dirty. Encoding from standard input to standard output is as simple as - - #include - #include - int main() - { - base64::encoder E; - E.encode(std::cin, std::cout); - return 0; - } - -Both standalone executables and a static library is provided in the package, - -Example code: ------------- -The 'examples' directory contains some simple example C code, that demonstrates -how to use the C interface of the library. - -Implementation: --------------- -It is DAMN fast, if I may say so myself. The C code uses a little trick which -has been used to implement coroutines, of which one can say that this -implementation is an example. - -(To see how the libb64 codebase compares with some other BASE64 implementations -available, see the BENCHMARKS file) - -The trick involves the fact that a switch-statement may legally cross into -sub-blocks. A very thorough and enlightening essay on co-routines in C, using -this method, can be found in the above mentioned "Coroutines in C", by Simon -Tatham: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - -For example, an RLE decompressing routine, adapted from the article: -1 static int STATE = 0; -2 static int len, c; -3 switch (STATE) -4 { -5 while (1) -6 { -7 c = getchar(); -8 if (c == EOF) return EOF; -9 if (c == 0xFF) { -10 len = getchar(); -11 c = getchar(); -12 while (len--) -13 { -14 STATE = 0; -15 return c; -16 case 0: -17 } -18 } else -19 STATE = 1; -20 return c; -21 case 1: -22 } -23 } -24 } - -As can be seen from this example, a coroutine depends on a state variable, -which it sets directly before exiting (lines 14 and 119). The next time the -routine is entered, the switch moves control to the specific point directly -after the previous exit (lines 16 and 21).hands - -(As an aside, in the mentioned article the combination of the top-level switch, -the various setting of the state, the return of a value, and the labelling of -the exit point is wrapped in #define macros, making the structure of the -routine even clearer.) - -The obvious problem with any such routine is the static keyword. -Any static variables in a function spell doom for multithreaded applications. -Also, in situations where this coroutine is used by more than one other -coroutines, the consistency is disturbed. - -What is needed is a structure for storing these variabled, which is passed to -the routine seperately. This obviously breaks the modularity of the function, -since now the caller has to worry about and care for the internal state of the -routine (the callee). This allows for a fast, multithreading-enabled -implementation, which may (obviously) be wrapped in a C++ object for ease of -use. - -The base64 encoding and decoding functionality in this package is implemented -in exactly this way, providing both a high-speed high-maintanence C interface, -and a wrapped C++ which is low-maintanence and only slightly less performant. diff --git a/third-party/libb64/b64/cdecode.h b/third-party/libb64/b64/cdecode.h deleted file mode 100644 index 5729853d7..000000000 --- a/third-party/libb64/b64/cdecode.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -cdecode.h - c header for a base64 decoding algorithm - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#ifndef BASE64_CDECODE_H -#define BASE64_CDECODE_H - -typedef enum -{ - step_a, step_b, step_c, step_d -} base64_decodestep; - -typedef struct -{ - base64_decodestep step; - char plainchar; -} base64_decodestate; - -void base64_init_decodestate(base64_decodestate* state_in); - -int base64_decode_value(char value_in); - -int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); - -#endif /* BASE64_CDECODE_H */ - diff --git a/third-party/libb64/b64/cencode.h b/third-party/libb64/b64/cencode.h deleted file mode 100644 index cf3213126..000000000 --- a/third-party/libb64/b64/cencode.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -cencode.h - c header for a base64 encoding algorithm - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#ifndef BASE64_CENCODE_H -#define BASE64_CENCODE_H - -typedef enum -{ - step_A, step_B, step_C -} base64_encodestep; - -typedef struct -{ - base64_encodestep step; - char result; - int stepcount; -} base64_encodestate; - -void base64_init_encodestate(base64_encodestate* state_in); - -char base64_encode_value(char value_in); - -int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); - -int base64_encode_blockend(char* code_out, base64_encodestate* state_in); - -#endif /* BASE64_CENCODE_H */ - diff --git a/third-party/libb64/cdecode.c b/third-party/libb64/cdecode.c deleted file mode 100644 index d9ca8819f..000000000 --- a/third-party/libb64/cdecode.c +++ /dev/null @@ -1,88 +0,0 @@ -/* -cdecoder.c - c source to a base64 decoding algorithm implementation - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#include - -int base64_decode_value(char value_in) -{ - static const signed char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; - static const char decoding_size = sizeof(decoding); - value_in -= 43; - if (value_in < 0 || value_in >= decoding_size) return -1; - return decoding[(int)value_in]; -} - -void base64_init_decodestate(base64_decodestate* state_in) -{ - state_in->step = step_a; - state_in->plainchar = 0; -} - -int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) -{ - const char* codechar = code_in; - char* plainchar = plaintext_out; - int fragment; - - *plainchar = state_in->plainchar; - - switch (state_in->step) - { - while (1) - { - case step_a: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_a; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar = (fragment & 0x03f) << 2; - case step_b: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_b; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar++ |= (fragment & 0x030) >> 4; - *plainchar = (fragment & 0x00f) << 4; - case step_c: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_c; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar++ |= (fragment & 0x03c) >> 2; - *plainchar = (fragment & 0x003) << 6; - case step_d: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_d; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar++ |= (fragment & 0x03f); - } - } - /* control should not reach here */ - return plainchar - plaintext_out; -} - diff --git a/third-party/libb64/cencode.c b/third-party/libb64/cencode.c deleted file mode 100644 index de3902f1b..000000000 --- a/third-party/libb64/cencode.c +++ /dev/null @@ -1,115 +0,0 @@ -/* -cencoder.c - c source to a base64 encoding algorithm implementation - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#include - -/* -const int CHARS_PER_LINE = 72; -*/ - -void base64_init_encodestate(base64_encodestate* state_in) -{ - state_in->step = step_A; - state_in->result = 0; - state_in->stepcount = 0; -} - -char base64_encode_value(char value_in) -{ - static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - if (value_in > 63) return '='; - return encoding[(int)value_in]; -} - -int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) -{ - const char* plainchar = plaintext_in; - const char* const plaintextend = plaintext_in + length_in; - char* codechar = code_out; - char result; - char fragment; - - result = state_in->result; - - switch (state_in->step) - { - while (1) - { - case step_A: - if (plainchar == plaintextend) - { - state_in->result = result; - state_in->step = step_A; - return codechar - code_out; - } - fragment = *plainchar++; - result = (fragment & 0x0fc) >> 2; - *codechar++ = base64_encode_value(result); - result = (fragment & 0x003) << 4; - case step_B: - if (plainchar == plaintextend) - { - state_in->result = result; - state_in->step = step_B; - return codechar - code_out; - } - fragment = *plainchar++; - result |= (fragment & 0x0f0) >> 4; - *codechar++ = base64_encode_value(result); - result = (fragment & 0x00f) << 2; - case step_C: - if (plainchar == plaintextend) - { - state_in->result = result; - state_in->step = step_C; - return codechar - code_out; - } - fragment = *plainchar++; - result |= (fragment & 0x0c0) >> 6; - *codechar++ = base64_encode_value(result); - result = (fragment & 0x03f) >> 0; - *codechar++ = base64_encode_value(result); - - /* - ++(state_in->stepcount); - if (state_in->stepcount == CHARS_PER_LINE/4) - { - *codechar++ = '\n'; - state_in->stepcount = 0; - } - */ - } - } - /* control should not reach here */ - return codechar - code_out; -} - -int base64_encode_blockend(char* code_out, base64_encodestate* state_in) -{ - char* codechar = code_out; - - switch (state_in->step) - { - case step_B: - *codechar++ = base64_encode_value(state_in->result); - *codechar++ = '='; - *codechar++ = '='; - break; - case step_C: - *codechar++ = base64_encode_value(state_in->result); - *codechar++ = '='; - break; - case step_A: - break; - } - /* - *codechar++ = '\n'; - */ - - return codechar - code_out; -} - diff --git a/third-party/libnatpmp/Changelog.txt b/third-party/libnatpmp/Changelog.txt deleted file mode 100644 index 7558b1a9b..000000000 --- a/third-party/libnatpmp/Changelog.txt +++ /dev/null @@ -1,86 +0,0 @@ -$Id: Changelog.txt,v 1.29 2011/08/07 16:59:33 nanard Exp $ - -2011/08/07: - Patch to build on debian/kFreeBSD. - -2011/07/15: - Put 3 clauses BSD licence at the top of source files. - -2011/06/18: - --no-undefined => -Wl,--no-undefined - adding a natpmpc.1 man page - -2011/05/19: - Small fix in libnatpmpmodule.c thanks to Manuel Mausz - -2011/01/03: - Added an argument to initnatpmp() in order to force the gateway to be used - -2011/01/01: - fix in make install - -2010/05/21: - make install now working under MacOSX (and BSD) - -2010/04/12: - cplusplus stuff in natpmp.h - -2010/02/02: - Fixed compilation under Mac OS X - -2009/12/19: - improve and fix building under Windows. - Project files for MS Visual Studio 2008 - More simple (and working) code for Win32. - More checks in the /proc/net/route parsing. Add some comments. - -2009/08/04: - improving getgateway.c for windows - -2009/07/13: - Adding Haiku code in getgateway.c - -2009/06/04: - Adding Python module thanks to David Wu - -2009/03/10: - Trying to have windows get gateway working if not using DHCP - -2009/02/27: - dont include declspec.h if not under WIN32. - -2009/01/23: - Prefixed the libraries name with lib - -2008/10/06: - Fixed a memory leak in getdefaultgateway() (USE_SYSCTL_NET_ROUTE) - -2008/07/03: - Adding WIN32 code from Robbie Hanson - -2008/06/30: - added a Solaris implementation for getgateway(). - added a LICENCE file to the distribution - -2008/05/29: - Anonymous unions are forbidden in ANSI C. That was causing problems with - non-GCC compilers. - -2008/04/28: - introduced strnatpmperr() - improved natpmpc.c sample - make install now install the binary - -2007/12/13: - Fixed getgateway.c for working under OS X ;) - Fixed values for NATPMP_PROTOCOL_TCP and NATPMP_PROTOCOL_UDP - -2007/12/11: - Fixed getgateway.c for compilation under Mac OS X - -2007/12/01: - added some comments in .h - -2007/11/30: - implemented almost everything - diff --git a/third-party/libnatpmp/LICENSE b/third-party/libnatpmp/LICENSE deleted file mode 100644 index 5bae1be70..000000000 --- a/third-party/libnatpmp/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. - diff --git a/third-party/libnatpmp/Makefile.am b/third-party/libnatpmp/Makefile.am deleted file mode 100644 index de9fb7431..000000000 --- a/third-party/libnatpmp/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -noinst_LIBRARIES = libnatpmp.a - -AM_CFLAGS = @PTHREAD_CFLAGS@ -DENABLE_STRNATPMPERR - -libnatpmp_a_SOURCES = \ - getgateway.c \ - natpmp.c \ - wingettimeofday.c - -noinst_HEADERS = \ - declspec.h \ - getgateway.h \ - natpmp.h \ - wingettimeofday.h - -EXTRA_DIST = \ - README \ - LICENSE diff --git a/third-party/libnatpmp/README b/third-party/libnatpmp/README deleted file mode 100644 index 269392d2a..000000000 --- a/third-party/libnatpmp/README +++ /dev/null @@ -1,7 +0,0 @@ -libnatpmp (c) 2007-2009 Thomas Bernard -contact : miniupnp@free.fr - -see http://miniupnp.free.fr/libnatpmp.html -or http://miniupnp.tuxfamily.org/libnatpmp.html -for some documentation and code samples. - diff --git a/third-party/libnatpmp/declspec.h b/third-party/libnatpmp/declspec.h deleted file mode 100644 index ea479d1e6..000000000 --- a/third-party/libnatpmp/declspec.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __DECLSPEC_H__ -#define __DECLSPEC_H__ - -#if defined(WIN32) && !defined(STATICLIB) - #ifdef NATPMP_EXPORTS - #define LIBSPEC __declspec(dllexport) - #else - #define LIBSPEC __declspec(dllimport) - #endif -#else - #define LIBSPEC -#endif - -#endif - diff --git a/third-party/libnatpmp/getgateway.c b/third-party/libnatpmp/getgateway.c deleted file mode 100644 index cb84dee88..000000000 --- a/third-party/libnatpmp/getgateway.c +++ /dev/null @@ -1,568 +0,0 @@ -/* $Id: getgateway.c,v 1.22 2011/08/08 21:20:51 nanard Exp $ */ -/* libnatpmp - -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. -*/ -#include -#include -#ifndef WIN32 -#include -#endif -#if !defined(_MSC_VER) -#include -#endif -/* There is no portable method to get the default route gateway. - * So below are four (or five ?) differents functions implementing this. - * Parsing /proc/net/route is for linux. - * sysctl is the way to access such informations on BSD systems. - * Many systems should provide route information through raw PF_ROUTE - * sockets. - * In MS Windows, default gateway is found by looking into the registry - * or by using GetBestRoute(). */ -#ifdef __linux__ -#define USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#if defined(BSD) || defined(__FreeBSD_kernel__) -#undef USE_PROC_NET_ROUTE -#define USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#ifdef __APPLE__ -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#define USE_SYSCTL_NET_ROUTE -#endif - -#if (defined(sun) && defined(__SVR4)) -#undef USE_PROC_NET_ROUTE -#define USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#ifdef WIN32 -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -//#define USE_WIN32_CODE -#define USE_WIN32_CODE_2 -#endif - -#ifdef __CYGWIN__ -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#define USE_WIN32_CODE -#include -#include -#include -#include -#endif - -#ifdef __HAIKU__ -#include -#include -#include -#include -#define USE_HAIKU_CODE -#endif - -#ifdef USE_SYSCTL_NET_ROUTE -#include -#include -#include -#include -#endif -#ifdef USE_SOCKET_ROUTE -#include -#include -#include -#include -#include -#endif - -#ifdef USE_WIN32_CODE -#include -#include -#define MAX_KEY_LENGTH 255 -#define MAX_VALUE_LENGTH 16383 -#endif - -#ifdef USE_WIN32_CODE_2 -#include -#include -#endif - -#include "getgateway.h" - -#ifndef WIN32 -#define SUCCESS (0) -#define FAILED (-1) -#endif - -#ifdef USE_PROC_NET_ROUTE -/* - parse /proc/net/route which is as follow : - -Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -wlan0 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -eth0 0000FEA9 00000000 0001 0 0 0 0000FFFF 0 0 0 -wlan0 00000000 0101A8C0 0003 0 0 0 00000000 0 0 0 -eth0 00000000 00000000 0001 0 0 1000 00000000 0 0 0 - - One header line, and then one line by route by route table entry. -*/ -int getdefaultgateway(in_addr_t * addr) -{ - unsigned long d, g; - char buf[256]; - int line = 0; - FILE * f; - char * p; - f = fopen("/proc/net/route", "r"); - if(!f) - return FAILED; - while(fgets(buf, sizeof(buf), f)) { - if(line > 0) { /* skip the first line */ - p = buf; - /* skip the interface name */ - while(*p && !isspace(*p)) - p++; - while(*p && isspace(*p)) - p++; - if(sscanf(p, "%lx%lx", &d, &g)==2) { - if(d == 0 && g != 0) { /* default */ - *addr = g; - fclose(f); - return SUCCESS; - } - } - } - line++; - } - /* default route not found ! */ - if(f) - fclose(f); - return FAILED; -} -#endif /* #ifdef USE_PROC_NET_ROUTE */ - - -#ifdef USE_SYSCTL_NET_ROUTE - -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) - -int getdefaultgateway(in_addr_t * addr) -{ -#if 0 - /* net.route.0.inet.dump.0.0 ? */ - int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, - NET_RT_DUMP, 0, 0/*tableid*/}; -#endif - /* net.route.0.inet.flags.gateway */ - int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, - NET_RT_FLAGS, RTF_GATEWAY}; - size_t l; - char * buf, * p; - struct rt_msghdr * rt; - struct sockaddr * sa; - struct sockaddr * sa_tab[RTAX_MAX]; - int i; - int r = FAILED; - if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) { - return FAILED; - } - if(l>0) { - buf = malloc(l); - if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) { - free(buf); - return FAILED; - } - for(p=buf; prtm_msglen) { - rt = (struct rt_msghdr *)p; - sa = (struct sockaddr *)(rt + 1); - for(i=0; irtm_addrs & (1 << i)) { - sa_tab[i] = sa; - sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); - } else { - sa_tab[i] = NULL; - } - } - if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) - && sa_tab[RTAX_DST]->sa_family == AF_INET - && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { - if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { - *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; - r = SUCCESS; - } - } - } - free(buf); - } - return r; -} -#endif /* #ifdef USE_SYSCTL_NET_ROUTE */ - - -#ifdef USE_SOCKET_ROUTE -/* Thanks to Darren Kenny for this code */ -#define NEXTADDR(w, u) \ - if (rtm_addrs & (w)) {\ - l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\ - } - -#define rtm m_rtmsg.m_rtm - -struct { - struct rt_msghdr m_rtm; - char m_space[512]; -} m_rtmsg; - -int getdefaultgateway(in_addr_t *addr) -{ - int s, seq, l, rtm_addrs, i; - pid_t pid; - struct sockaddr so_dst, so_mask; - char *cp = m_rtmsg.m_space; - struct sockaddr *gate = NULL, *sa; - struct rt_msghdr *msg_hdr; - - pid = getpid(); - seq = 0; - rtm_addrs = RTA_DST | RTA_NETMASK; - - memset(&so_dst, 0, sizeof(so_dst)); - memset(&so_mask, 0, sizeof(so_mask)); - memset(&rtm, 0, sizeof(struct rt_msghdr)); - - rtm.rtm_type = RTM_GET; - rtm.rtm_flags = RTF_UP | RTF_GATEWAY; - rtm.rtm_version = RTM_VERSION; - rtm.rtm_seq = ++seq; - rtm.rtm_addrs = rtm_addrs; - - so_dst.sa_family = AF_INET; - so_mask.sa_family = AF_INET; - - NEXTADDR(RTA_DST, so_dst); - NEXTADDR(RTA_NETMASK, so_mask); - - rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; - - s = socket(PF_ROUTE, SOCK_RAW, 0); - - if (write(s, (char *)&m_rtmsg, l) < 0) { - close(s); - return FAILED; - } - - do { - l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); - } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); - - close(s); - - msg_hdr = &rtm; - - cp = ((char *)(msg_hdr + 1)); - if (msg_hdr->rtm_addrs) { - for (i = 1; i; i <<= 1) - if (i & msg_hdr->rtm_addrs) { - sa = (struct sockaddr *)cp; - if (i == RTA_GATEWAY ) - gate = sa; - - cp += sizeof(struct sockaddr); - } - } else { - return FAILED; - } - - - if (gate != NULL ) { - *addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr; - return SUCCESS; - } else { - return FAILED; - } -} -#endif /* #ifdef USE_SOCKET_ROUTE */ - -#ifdef USE_WIN32_CODE -LIBSPEC int getdefaultgateway(in_addr_t * addr) -{ - HKEY networkCardsKey; - HKEY networkCardKey; - HKEY interfacesKey; - HKEY interfaceKey; - DWORD i = 0; - DWORD numSubKeys = 0; - TCHAR keyName[MAX_KEY_LENGTH]; - DWORD keyNameLength = MAX_KEY_LENGTH; - TCHAR keyValue[MAX_VALUE_LENGTH]; - DWORD keyValueLength = MAX_VALUE_LENGTH; - DWORD keyValueType = REG_SZ; - TCHAR gatewayValue[MAX_VALUE_LENGTH]; - DWORD gatewayValueLength = MAX_VALUE_LENGTH; - DWORD gatewayValueType = REG_MULTI_SZ; - int done = 0; - - //const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - //const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#ifdef UNICODE - LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#define STR_SERVICENAME L"ServiceName" -#define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway" -#define STR_DEFAULTGATEWAY L"DefaultGateway" -#else - LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#define STR_SERVICENAME "ServiceName" -#define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway" -#define STR_DEFAULTGATEWAY "DefaultGateway" -#endif - // The windows registry lists its primary network devices in the following location: - // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards - // - // Each network device has its own subfolder, named with an index, with various properties: - // -NetworkCards - // -5 - // -Description = Broadcom 802.11n Network Adapter - // -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D} - // -8 - // -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller - // -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD} - // - // The above service name is the name of a subfolder within: - // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces - // - // There may be more subfolders in this interfaces path than listed in the network cards path above: - // -Interfaces - // -{3a539854-6a70-11db-887c-806e6f6e6963} - // -DhcpIPAddress = 0.0.0.0 - // -[more] - // -{E35A72F8-5065-4097-8DFE-C7790774EE4D} - // -DhcpIPAddress = 10.0.1.4 - // -DhcpDefaultGateway = 10.0.1.1 - // -[more] - // -{86226414-5545-4335-A9D1-5BD7120119AD} - // -DhcpIpAddress = 10.0.1.5 - // -DhcpDefaultGateay = 10.0.1.1 - // -[more] - // - // In order to extract this information, we enumerate each network card, and extract the ServiceName value. - // This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value. - // Once one is found, we're done. - // - // It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value. - // However, the technique used is the technique most cited on the web, and we assume it to be more correct. - - if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key - networkCardsPath, // Name of registry subkey to open - 0, // Reserved - must be zero - KEY_READ, // Mask - desired access rights - &networkCardsKey)) // Pointer to output key - { - // Unable to open network cards keys - return -1; - } - - if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key - interfacesPath, // Name of registry subkey to open - 0, // Reserved - must be zero - KEY_READ, // Mask - desired access rights - &interfacesKey)) // Pointer to output key - { - // Unable to open interfaces key - RegCloseKey(networkCardsKey); - return -1; - } - - // Figure out how many subfolders are within the NetworkCards folder - RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys); - - // Enumrate through each subfolder within the NetworkCards folder - for(i = 0; i < numSubKeys && !done; i++) - { - keyNameLength = MAX_KEY_LENGTH; - if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key - i, // Index of subkey to retrieve - keyName, // Buffer that receives the name of the subkey - &keyNameLength, // Variable that receives the size of the above buffer - NULL, // Reserved - must be NULL - NULL, // Buffer that receives the class string - NULL, // Variable that receives the size of the above buffer - NULL)) // Variable that receives the last write time of subkey - { - if(RegOpenKeyEx(networkCardsKey, keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS) - { - keyValueLength = MAX_VALUE_LENGTH; - if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey, // Open registry key - STR_SERVICENAME, // Name of key to query - NULL, // Reserved - must be NULL - &keyValueType, // Receives value type - (LPBYTE)keyValue, // Receives value - &keyValueLength)) // Receives value length in bytes - { -// printf("keyValue: %s\n", keyValue); - if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS) - { - gatewayValueLength = MAX_VALUE_LENGTH; - if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key - STR_DHCPDEFAULTGATEWAY, // Name of key to query - NULL, // Reserved - must be NULL - &gatewayValueType, // Receives value type - (LPBYTE)gatewayValue, // Receives value - &gatewayValueLength)) // Receives value length in bytes - { - // Check to make sure it's a string - if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) - { - //printf("gatewayValue: %s\n", gatewayValue); - done = 1; - } - } - else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key - STR_DEFAULTGATEWAY, // Name of key to query - NULL, // Reserved - must be NULL - &gatewayValueType, // Receives value type - (LPBYTE)gatewayValue,// Receives value - &gatewayValueLength)) // Receives value length in bytes - { - // Check to make sure it's a string - if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) - { - //printf("gatewayValue: %s\n", gatewayValue); - done = 1; - } - } - RegCloseKey(interfaceKey); - } - } - RegCloseKey(networkCardKey); - } - } - } - - RegCloseKey(interfacesKey); - RegCloseKey(networkCardsKey); - - if(done) - { -#if UNICODE - char tmp[32]; - for(i = 0; i < 32; i++) { - tmp[i] = (char)gatewayValue[i]; - if(!tmp[i]) - break; - } - tmp[31] = '\0'; - *addr = inet_addr(tmp); -#else - *addr = inet_addr(gatewayValue); -#endif - return 0; - } - - return -1; -} -#endif /* #ifdef USE_WIN32_CODE */ - -#ifdef USE_WIN32_CODE_2 -int getdefaultgateway(in_addr_t *addr) -{ - MIB_IPFORWARDROW ip_forward; - memset(&ip_forward, 0, sizeof(ip_forward)); - if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR) - return -1; - *addr = ip_forward.dwForwardNextHop; - return 0; -} -#endif /* #ifdef USE_WIN32_CODE_2 */ - -#ifdef USE_HAIKU_CODE -int getdefaultgateway(in_addr_t *addr) -{ - int fd, ret = -1; - struct ifconf config; - void *buffer = NULL; - struct ifreq *interface; - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - return -1; - } - if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) { - goto fail; - } - if (config.ifc_value < 1) { - goto fail; /* No routes */ - } - if ((buffer = malloc(config.ifc_value)) == NULL) { - goto fail; - } - config.ifc_len = config.ifc_value; - config.ifc_buf = buffer; - if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) { - goto fail; - } - for (interface = buffer; - (uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) { - struct route_entry route = interface->ifr_route; - int intfSize; - if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) { - *addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr; - ret = 0; - break; - } - intfSize = sizeof(route) + IF_NAMESIZE; - if (route.destination != NULL) { - intfSize += route.destination->sa_len; - } - if (route.mask != NULL) { - intfSize += route.mask->sa_len; - } - if (route.gateway != NULL) { - intfSize += route.gateway->sa_len; - } - interface = (struct ifreq *)((uint8_t *)interface + intfSize); - } -fail: - free(buffer); - close(fd); - return ret; -} -#endif /* #ifdef USE_HAIKU_CODE */ - - diff --git a/third-party/libnatpmp/getgateway.h b/third-party/libnatpmp/getgateway.h deleted file mode 100644 index 32af9096b..000000000 --- a/third-party/libnatpmp/getgateway.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: getgateway.h,v 1.5 2011/07/15 08:30:11 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. -*/ -#ifndef __GETGATEWAY_H__ -#define __GETGATEWAY_H__ - -#ifdef WIN32 -#if !defined(_MSC_VER) -#include -#else -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -#endif -#define in_addr_t uint32_t -#endif -#include "declspec.h" - -/* getdefaultgateway() : - * return value : - * 0 : success - * -1 : failure */ -LIBSPEC int getdefaultgateway(in_addr_t * addr); - -#endif diff --git a/third-party/libnatpmp/natpmp.c b/third-party/libnatpmp/natpmp.c deleted file mode 100644 index 6f3caf1a6..000000000 --- a/third-party/libnatpmp/natpmp.c +++ /dev/null @@ -1,362 +0,0 @@ -/* $Id: natpmp.c,v 1.14 2011/07/15 08:30:11 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. -*/ -#ifdef __linux__ -#define _BSD_SOURCE 1 -#endif -#include -#include -#if !defined(_MSC_VER) -#include -#endif -#ifdef WIN32 -#include -#include -#include -#include -#define EWOULDBLOCK WSAEWOULDBLOCK -#define ECONNREFUSED WSAECONNREFUSED -#include "wingettimeofday.h" -#else -#include -#include -#include -#include -#include -#define closesocket close -#endif -#include "natpmp.h" -#include "getgateway.h" - -LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw) -{ -#ifdef WIN32 - u_long ioctlArg = 1; -#else - int flags; -#endif - struct sockaddr_in addr; - if(!p) - return NATPMP_ERR_INVALIDARGS; - memset(p, 0, sizeof(natpmp_t)); - p->s = socket(PF_INET, SOCK_DGRAM, 0); - if(p->s < 0) - return NATPMP_ERR_SOCKETERROR; -#ifdef WIN32 - if(ioctlsocket(p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR) - return NATPMP_ERR_FCNTLERROR; -#else - if((flags = fcntl(p->s, F_GETFL, 0)) < 0) - return NATPMP_ERR_FCNTLERROR; - if(fcntl(p->s, F_SETFL, flags | O_NONBLOCK) < 0) - return NATPMP_ERR_FCNTLERROR; -#endif - - if(forcegw) { - p->gateway = forcedgw; - } else { - if(getdefaultgateway(&(p->gateway)) < 0) - return NATPMP_ERR_CANNOTGETGATEWAY; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(NATPMP_PORT); - addr.sin_addr.s_addr = p->gateway; - if(connect(p->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) - return NATPMP_ERR_CONNECTERR; - return 0; -} - -LIBSPEC int closenatpmp(natpmp_t * p) -{ - if(!p) - return NATPMP_ERR_INVALIDARGS; - if(closesocket(p->s) < 0) - return NATPMP_ERR_CLOSEERR; - return 0; -} - -int sendpendingrequest(natpmp_t * p) -{ - int r; -/* struct sockaddr_in addr;*/ - if(!p) - return NATPMP_ERR_INVALIDARGS; -/* memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(NATPMP_PORT); - addr.sin_addr.s_addr = p->gateway; - r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0, - (struct sockaddr *)&addr, sizeof(addr));*/ - r = (int)send(p->s, p->pending_request, p->pending_request_len, 0); - return (r<0) ? NATPMP_ERR_SENDERR : r; -} - -int sendnatpmprequest(natpmp_t * p) -{ - int n; - if(!p) - return NATPMP_ERR_INVALIDARGS; - /* TODO : check if no request is allready pending */ - p->has_pending_request = 1; - p->try_number = 1; - n = sendpendingrequest(p); - gettimeofday(&p->retry_time, NULL); // check errors ! - p->retry_time.tv_usec += 250000; /* add 250ms */ - if(p->retry_time.tv_usec >= 1000000) { - p->retry_time.tv_usec -= 1000000; - p->retry_time.tv_sec++; - } - return n; -} - -LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout) -{ - struct timeval now; - if(!p || !timeout) - return NATPMP_ERR_INVALIDARGS; - if(!p->has_pending_request) - return NATPMP_ERR_NOPENDINGREQ; - if(gettimeofday(&now, NULL) < 0) - return NATPMP_ERR_GETTIMEOFDAYERR; - timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec; - timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec; - if(timeout->tv_usec < 0) { - timeout->tv_usec += 1000000; - timeout->tv_sec--; - } - return 0; -} - -LIBSPEC int sendpublicaddressrequest(natpmp_t * p) -{ - if(!p) - return NATPMP_ERR_INVALIDARGS; - //static const unsigned char request[] = { 0, 0 }; - p->pending_request[0] = 0; - p->pending_request[1] = 0; - p->pending_request_len = 2; - // TODO: return 0 instead of sizeof(request) ?? - return sendnatpmprequest(p); -} - -LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, - uint16_t privateport, uint16_t publicport, - uint32_t lifetime) -{ - if(!p || (protocol!=NATPMP_PROTOCOL_TCP && protocol!=NATPMP_PROTOCOL_UDP)) - return NATPMP_ERR_INVALIDARGS; - p->pending_request[0] = 0; - p->pending_request[1] = protocol; - p->pending_request[2] = 0; - p->pending_request[3] = 0; - *((uint16_t *)(p->pending_request + 4)) = htons(privateport); - *((uint16_t *)(p->pending_request + 6)) = htons(publicport); - *((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); - p->pending_request_len = 12; - return sendnatpmprequest(p); -} - -LIBSPEC int readnatpmpresponse(natpmp_t * p, natpmpresp_t * response) -{ - unsigned char buf[16]; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int n; - if(!p) - return NATPMP_ERR_INVALIDARGS; - n = recvfrom(p->s, buf, sizeof(buf), 0, - (struct sockaddr *)&addr, &addrlen); - if(n<0) - switch(errno) { - /*case EAGAIN:*/ - case EWOULDBLOCK: - n = NATPMP_TRYAGAIN; - break; - case ECONNREFUSED: - n = NATPMP_ERR_NOGATEWAYSUPPORT; - break; - default: - n = NATPMP_ERR_RECVFROM; - } - /* check that addr is correct (= gateway) */ - else if(addr.sin_addr.s_addr != p->gateway) - n = NATPMP_ERR_WRONGPACKETSOURCE; - else { - response->resultcode = ntohs(*((uint16_t *)(buf + 2))); - response->epoch = ntohl(*((uint32_t *)(buf + 4))); - if(buf[0] != 0) - n = NATPMP_ERR_UNSUPPORTEDVERSION; - else if(buf[1] < 128 || buf[1] > 130) - n = NATPMP_ERR_UNSUPPORTEDOPCODE; - else if(response->resultcode != 0) { - switch(response->resultcode) { - case 1: - n = NATPMP_ERR_UNSUPPORTEDVERSION; - break; - case 2: - n = NATPMP_ERR_NOTAUTHORIZED; - break; - case 3: - n = NATPMP_ERR_NETWORKFAILURE; - break; - case 4: - n = NATPMP_ERR_OUTOFRESOURCES; - break; - case 5: - n = NATPMP_ERR_UNSUPPORTEDOPCODE; - break; - default: - n = NATPMP_ERR_UNDEFINEDERROR; - } - } else { - response->type = buf[1] & 0x7f; - if(buf[1] == 128) - //response->publicaddress.addr = *((uint32_t *)(buf + 8)); - response->pnu.publicaddress.addr.s_addr = *((uint32_t *)(buf + 8)); - else { - response->pnu.newportmapping.privateport = ntohs(*((uint16_t *)(buf + 8))); - response->pnu.newportmapping.mappedpublicport = ntohs(*((uint16_t *)(buf + 10))); - response->pnu.newportmapping.lifetime = ntohl(*((uint32_t *)(buf + 12))); - } - n = 0; - } - } - return n; -} - -int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response) -{ - int n; - if(!p || !response) - return NATPMP_ERR_INVALIDARGS; - if(!p->has_pending_request) - return NATPMP_ERR_NOPENDINGREQ; - n = readnatpmpresponse(p, response); - if(n<0) { - if(n==NATPMP_TRYAGAIN) { - struct timeval now; - gettimeofday(&now, NULL); // check errors ! - if(timercmp(&now, &p->retry_time, >=)) { - int delay, r; - if(p->try_number >= 9) { - return NATPMP_ERR_NOGATEWAYSUPPORT; - } - /*printf("retry! %d\n", p->try_number);*/ - delay = 250 * (1<try_number); // ms - /*for(i=0; itry_number; i++) - delay += delay;*/ - p->retry_time.tv_sec += (delay / 1000); - p->retry_time.tv_usec += (delay % 1000) * 1000; - if(p->retry_time.tv_usec >= 1000000) { - p->retry_time.tv_usec -= 1000000; - p->retry_time.tv_sec++; - } - p->try_number++; - r = sendpendingrequest(p); - if(r<0) - return r; - } - } - } else { - p->has_pending_request = 0; - } - return n; -} - -#ifdef ENABLE_STRNATPMPERR -LIBSPEC const char * strnatpmperr(int r) -{ - const char * s; - switch(r) { - case NATPMP_ERR_INVALIDARGS: - s = "invalid arguments"; - break; - case NATPMP_ERR_SOCKETERROR: - s = "socket() failed"; - break; - case NATPMP_ERR_CANNOTGETGATEWAY: - s = "cannot get default gateway ip address"; - break; - case NATPMP_ERR_CLOSEERR: -#ifdef WIN32 - s = "closesocket() failed"; -#else - s = "close() failed"; -#endif - break; - case NATPMP_ERR_RECVFROM: - s = "recvfrom() failed"; - break; - case NATPMP_ERR_NOPENDINGREQ: - s = "no pending request"; - break; - case NATPMP_ERR_NOGATEWAYSUPPORT: - s = "the gateway does not support nat-pmp"; - break; - case NATPMP_ERR_CONNECTERR: - s = "connect() failed"; - break; - case NATPMP_ERR_WRONGPACKETSOURCE: - s = "packet not received from the default gateway"; - break; - case NATPMP_ERR_SENDERR: - s = "send() failed"; - break; - case NATPMP_ERR_FCNTLERROR: - s = "fcntl() failed"; - break; - case NATPMP_ERR_GETTIMEOFDAYERR: - s = "gettimeofday() failed"; - break; - case NATPMP_ERR_UNSUPPORTEDVERSION: - s = "unsupported nat-pmp version error from server"; - break; - case NATPMP_ERR_UNSUPPORTEDOPCODE: - s = "unsupported nat-pmp opcode error from server"; - break; - case NATPMP_ERR_UNDEFINEDERROR: - s = "undefined nat-pmp server error"; - break; - case NATPMP_ERR_NOTAUTHORIZED: - s = "not authorized"; - break; - case NATPMP_ERR_NETWORKFAILURE: - s = "network failure"; - break; - case NATPMP_ERR_OUTOFRESOURCES: - s = "nat-pmp server out of resources"; - break; - default: - s = "Unknown libnatpmp error"; - } - return s; -} -#endif - diff --git a/third-party/libnatpmp/natpmp.h b/third-party/libnatpmp/natpmp.h deleted file mode 100644 index 369743cbe..000000000 --- a/third-party/libnatpmp/natpmp.h +++ /dev/null @@ -1,215 +0,0 @@ -/* $Id: natpmp.h,v 1.15 2011/07/15 08:30:11 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. -*/ -#ifndef __NATPMP_H__ -#define __NATPMP_H__ - -/* NAT-PMP Port as defined by the NAT-PMP draft */ -#define NATPMP_PORT (5351) - -#include -#if !defined(_MSC_VER) -#include -#endif -#ifdef WIN32 -#include -#if !defined(_MSC_VER) -#include -#else -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -#endif -#define in_addr_t uint32_t -#include "declspec.h" -#else -#define LIBSPEC -#include -#endif - -typedef struct { - int s; /* socket */ - in_addr_t gateway; /* default gateway (IPv4) */ - int has_pending_request; - unsigned char pending_request[12]; - int pending_request_len; - int try_number; - struct timeval retry_time; -} natpmp_t; - -typedef struct { - uint16_t type; /* NATPMP_RESPTYPE_* */ - uint16_t resultcode; /* NAT-PMP response code */ - uint32_t epoch; /* Seconds since start of epoch */ - union { - struct { - //in_addr_t addr; - struct in_addr addr; - } publicaddress; - struct { - uint16_t privateport; - uint16_t mappedpublicport; - uint32_t lifetime; - } newportmapping; - } pnu; -} natpmpresp_t; - -/* possible values for type field of natpmpresp_t */ -#define NATPMP_RESPTYPE_PUBLICADDRESS (0) -#define NATPMP_RESPTYPE_UDPPORTMAPPING (1) -#define NATPMP_RESPTYPE_TCPPORTMAPPING (2) - -/* Values to pass to sendnewportmappingrequest() */ -#define NATPMP_PROTOCOL_UDP (1) -#define NATPMP_PROTOCOL_TCP (2) - -/* return values */ -/* NATPMP_ERR_INVALIDARGS : invalid arguments passed to the function */ -#define NATPMP_ERR_INVALIDARGS (-1) -/* NATPMP_ERR_SOCKETERROR : socket() failed. check errno for details */ -#define NATPMP_ERR_SOCKETERROR (-2) -/* NATPMP_ERR_CANNOTGETGATEWAY : can't get default gateway IP */ -#define NATPMP_ERR_CANNOTGETGATEWAY (-3) -/* NATPMP_ERR_CLOSEERR : close() failed. check errno for details */ -#define NATPMP_ERR_CLOSEERR (-4) -/* NATPMP_ERR_RECVFROM : recvfrom() failed. check errno for details */ -#define NATPMP_ERR_RECVFROM (-5) -/* NATPMP_ERR_NOPENDINGREQ : readnatpmpresponseorretry() called while - * no NAT-PMP request was pending */ -#define NATPMP_ERR_NOPENDINGREQ (-6) -/* NATPMP_ERR_NOGATEWAYSUPPORT : the gateway does not support NAT-PMP */ -#define NATPMP_ERR_NOGATEWAYSUPPORT (-7) -/* NATPMP_ERR_CONNECTERR : connect() failed. check errno for details */ -#define NATPMP_ERR_CONNECTERR (-8) -/* NATPMP_ERR_WRONGPACKETSOURCE : packet not received from the network gateway */ -#define NATPMP_ERR_WRONGPACKETSOURCE (-9) -/* NATPMP_ERR_SENDERR : send() failed. check errno for details */ -#define NATPMP_ERR_SENDERR (-10) -/* NATPMP_ERR_FCNTLERROR : fcntl() failed. check errno for details */ -#define NATPMP_ERR_FCNTLERROR (-11) -/* NATPMP_ERR_GETTIMEOFDAYERR : gettimeofday() failed. check errno for details */ -#define NATPMP_ERR_GETTIMEOFDAYERR (-12) - -/* */ -#define NATPMP_ERR_UNSUPPORTEDVERSION (-14) -#define NATPMP_ERR_UNSUPPORTEDOPCODE (-15) - -/* Errors from the server : */ -#define NATPMP_ERR_UNDEFINEDERROR (-49) -#define NATPMP_ERR_NOTAUTHORIZED (-51) -#define NATPMP_ERR_NETWORKFAILURE (-52) -#define NATPMP_ERR_OUTOFRESOURCES (-53) - -/* NATPMP_TRYAGAIN : no data available for the moment. try again later */ -#define NATPMP_TRYAGAIN (-100) - -#ifdef __cplusplus -extern "C" { -#endif - -/* initnatpmp() - * initialize a natpmp_t object - * With forcegw=1 the gateway is not detected automaticaly. - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SOCKETERROR - * NATPMP_ERR_FCNTLERROR - * NATPMP_ERR_CANNOTGETGATEWAY - * NATPMP_ERR_CONNECTERR */ -LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw); - -/* closenatpmp() - * close resources associated with a natpmp_t object - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_CLOSEERR */ -LIBSPEC int closenatpmp(natpmp_t * p); - -/* sendpublicaddressrequest() - * send a public address NAT-PMP request to the network gateway - * Return values : - * 2 = OK (size of the request) - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SENDERR */ -LIBSPEC int sendpublicaddressrequest(natpmp_t * p); - -/* sendnewportmappingrequest() - * send a new port mapping NAT-PMP request to the network gateway - * Arguments : - * protocol is either NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP, - * lifetime is in seconds. - * To remove a port mapping, set lifetime to zero. - * To remove all port mappings to the host, set lifetime and both ports - * to zero. - * Return values : - * 12 = OK (size of the request) - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SENDERR */ -LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, - uint16_t privateport, uint16_t publicport, - uint32_t lifetime); - -/* getnatpmprequesttimeout() - * fills the timeval structure with the timeout duration of the - * currently pending NAT-PMP request. - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_GETTIMEOFDAYERR - * NATPMP_ERR_NOPENDINGREQ */ -LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout); - -/* readnatpmpresponseorretry() - * fills the natpmpresp_t structure if possible - * Return values : - * 0 = OK - * NATPMP_TRYAGAIN - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_NOPENDINGREQ - * NATPMP_ERR_NOGATEWAYSUPPORT - * NATPMP_ERR_RECVFROM - * NATPMP_ERR_WRONGPACKETSOURCE - * NATPMP_ERR_UNSUPPORTEDVERSION - * NATPMP_ERR_UNSUPPORTEDOPCODE - * NATPMP_ERR_NOTAUTHORIZED - * NATPMP_ERR_NETWORKFAILURE - * NATPMP_ERR_OUTOFRESOURCES - * NATPMP_ERR_UNSUPPORTEDOPCODE - * NATPMP_ERR_UNDEFINEDERROR */ -LIBSPEC int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response); - -#ifdef ENABLE_STRNATPMPERR -LIBSPEC const char * strnatpmperr(int t); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/third-party/libnatpmp/wingettimeofday.c b/third-party/libnatpmp/wingettimeofday.c deleted file mode 100644 index d71582bd3..000000000 --- a/third-party/libnatpmp/wingettimeofday.c +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id: wingettimeofday.c,v 1.4 2011/07/15 08:30:11 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. -*/ -#ifdef WIN32 -#if defined(_MSC_VER) -struct timeval { - long tv_sec; - long tv_usec; -}; -#else -#include -#endif - -typedef struct _FILETIME { - unsigned long dwLowDateTime; - unsigned long dwHighDateTime; -} FILETIME; - -void __stdcall GetSystemTimeAsFileTime(FILETIME*); - -int gettimeofday(struct timeval* p, void* tz /* IGNORED */) { - union { - long long ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; - - if(!p) - return -1; - GetSystemTimeAsFileTime( &(_now.ft) ); - p->tv_usec =(long)((_now.ns100 / 10LL) % 1000000LL ); - p->tv_sec = (long)((_now.ns100-(116444736000000000LL))/10000000LL); - return 0; -} -#endif - diff --git a/third-party/libnatpmp/wingettimeofday.h b/third-party/libnatpmp/wingettimeofday.h deleted file mode 100644 index db76b095d..000000000 --- a/third-party/libnatpmp/wingettimeofday.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $Id: wingettimeofday.h,v 1.2 2011/07/15 08:30:11 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. -*/ -#ifndef __WINGETTIMEOFDAY_H__ -#define __WINGETTIMEOFDAY_H__ -#ifdef WIN32 -#if defined(_MSC_VER) -#include -#else -#include -#endif -int gettimeofday(struct timeval* p, void* tz /* IGNORED */); -#endif -#endif diff --git a/third-party/libutp/LICENSE b/third-party/libutp/LICENSE deleted file mode 100644 index 73acb81ca..000000000 --- a/third-party/libutp/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2010 BitTorrent, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/third-party/libutp/Makefile.am b/third-party/libutp/Makefile.am deleted file mode 100644 index 847f596ed..000000000 --- a/third-party/libutp/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -AM_CPPFLAGS = -fno-exceptions -fno-rtti -ansi -DPOSIX - -noinst_LIBRARIES = libutp.a -libutp_a_SOURCES = utp.cpp utp_utils.cpp -noinst_HEADERS = StdAfx.h templates.h utp_config_example.h utp.h utp_config.h utp_utils.h utypes.h -EXTRA_DIST = LICENSE README.md diff --git a/third-party/libutp/README.md b/third-party/libutp/README.md deleted file mode 100644 index 83270e69e..000000000 --- a/third-party/libutp/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# libutp - The uTorrent Transport Protocol library. -Copyright (c) 2010 BitTorrent, Inc. - -uTP is a TCP-like implementation of [LEDBAT][ledbat] documented as a BitTorrent -extension in [BEP-29][bep29]. uTP provides provides reliable, ordered delivery -while maintaining minimum extra delay. It is implemented on top of UDP to be -cross-platform and functional today. As a result, uTP is the primary transport -for uTorrent peer-to-peer connections. - -uTP is written in C++, but the external interface is strictly C (ANSI C89). - -## The Interface - -The uTP socket interface is a bit different from the Berkeley socket API to -avoid the need for our own select() implementation, and to make it easier to -write event-based code with minimal buffering. - -When you create a uTP socket, you register a set of callbacks. Most notably, the -on_read callback is a reactive callback which occurs when bytes arrive off the -network. The write side of the socket is proactive, and you call UTP_Write to -indicate the number of bytes you wish to write. As packets are created, the -on_write callback is called for each packet, so you can fill the buffers with -data. - -The libutp interface is not thread-safe. It was designed for use in a -single-threaded asyncronous context, although with proper synchronization -it may be used from a multi-threaded environment as well. - -See utp.h for more details and other API documentation. - -## Examples - -See the utp_test and utp_file directories for examples. - -## Building - -uTP has been known to build on Windows with MSVC and on linux and OS X with gcc. -On Windows, use the MSVC project files (utp.sln, and friends). On other platforms, -building the shared library is as simple as: - - make - -To build one of the examples, which will statically link in everything it needs -from libutp: - - cd utp_test && make - -## Packaging and API - -The libutp API is considered unstable, and probably always will be. We encourage -you to test with the version of libutp you have, and be mindful when upgrading. -For this reason, it is probably also a good idea to bundle libutp with your -application. - -## License - -libutp is released under the [MIT][lic] license. - -## Related Work - -Research and analysis of congestion control mechanisms can be found [here.][survey] - -[ledbat]: http://datatracker.ietf.org/wg/ledbat/charter/ -[bep29]: http://www.bittorrent.org/beps/bep_0029.html -[lic]: http://www.opensource.org/licenses/mit-license.php -[survey]: http://datatracker.ietf.org/doc/draft-ietf-ledbat-survey/ diff --git a/third-party/libutp/StdAfx.h b/third-party/libutp/StdAfx.h deleted file mode 100644 index 400039513..000000000 --- a/third-party/libutp/StdAfx.h +++ /dev/null @@ -1,11 +0,0 @@ -#if !defined(AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_) -#define AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// I don't have anything to put here, but some projects use precompiled headers, -// so I include StdAfx.h anyway, so they don't have to edit the files to compile normally. - -#endif // !defined(AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_) diff --git a/third-party/libutp/templates.h b/third-party/libutp/templates.h deleted file mode 100644 index 9684b52b3..000000000 --- a/third-party/libutp/templates.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef __TEMPLATES_H__ -#define __TEMPLATES_H__ - -#include "utypes.h" -#include - -#if defined(POSIX) -/* Allow over-writing FORCEINLINE from makefile because gcc 3.4.4 for buffalo - doesn't seem to support __attribute__((always_inline)) in -O0 build - (strangely, it works in -Os build) */ -#ifndef FORCEINLINE -// The always_inline attribute asks gcc to inline the function even if no optimization is being requested. -// This macro should be used exclusive-or with the inline directive (use one or the other but not both) -// since Microsoft uses __forceinline to also mean inline, -// and this code is following a Microsoft compatibility model. -// Just setting the attribute without also specifying the inline directive apparently won't inline the function, -// as evidenced by multiply-defined symbols found at link time. -#define FORCEINLINE inline __attribute__((always_inline)) -#endif -#endif - -#ifdef __GNUC__ -// Used for gcc tool chains accepting but not supporting pragma pack -// See http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html -#define PACKED_ATTRIBUTE __attribute__((__packed__)) -#else -#define PACKED_ATTRIBUTE -#endif - -#ifdef __GNUC__ -#define ALIGNED_ATTRIBUTE(x) __attribute__((aligned (x))) -#else -#define ALIGNED_ATTRIBUTE(x) -#endif - -// Utility templates -#undef min -#undef max - -template static inline T min(T a, T b) { if (a < b) return a; return b; } -template static inline T max(T a, T b) { if (a > b) return a; return b; } - -template static inline T min(T a, T b, T c) { return min(min(a,b),c); } -template static inline T max(T a, T b, T c) { return max(max(a,b),c); } -template static inline T clamp(T v, T mi, T ma) -{ - if (v > ma) v = ma; - if (v < mi) v = mi; - return v; -} - -#if (defined(__SVR4) && defined(__sun)) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -namespace aux -{ - FORCEINLINE uint16 host_to_network(uint16 i) { return htons(i); } - FORCEINLINE uint32 host_to_network(uint32 i) { return htonl(i); } - FORCEINLINE int32 host_to_network(int32 i) { return htonl(i); } - FORCEINLINE uint16 network_to_host(uint16 i) { return ntohs(i); } - FORCEINLINE uint32 network_to_host(uint32 i) { return ntohl(i); } - FORCEINLINE int32 network_to_host(int32 i) { return ntohl(i); } -} - -template -struct PACKED_ATTRIBUTE big_endian -{ - T operator=(T i) { m_integer = aux::host_to_network(i); return i; } - operator T() const { return aux::network_to_host(m_integer); } -private: - T m_integer; -}; - -typedef big_endian int32_big; -typedef big_endian uint32_big; -typedef big_endian uint16_big; - -#if (defined(__SVR4) && defined(__sun)) -#pragma pack(0) -#else -#pragma pack(pop) -#endif - -template static inline void zeromem(T *a, size_t count = 1) { memset(a, 0, count * sizeof(T)); } - -typedef int SortCompareProc(const void *, const void *); - -template static FORCEINLINE void QuickSortT(T *base, size_t num, int (*comp)(const T *, const T *)) { qsort(base, num, sizeof(T), (SortCompareProc*)comp); } - - -// WARNING: The template parameter MUST be a POD type! -template class Array { -protected: - T *mem; - size_t alloc,count; - -public: - Array(size_t init) { Init(init); } - Array() { Init(); } - ~Array() { Free(); } - - void inline Init() { mem = NULL; alloc = count = 0; } - void inline Init(size_t init) { Init(); if (init) Resize(init); } - size_t inline GetCount() const { return count; } - size_t inline GetAlloc() const { return alloc; } - void inline SetCount(size_t c) { count = c; } - - inline T& operator[](size_t offset) { assert(offset ==0 || offset(minsize, alloc * 2)); } - - inline size_t Append(const T &t) { - if (count >= alloc) Grow(); - size_t r=count++; - mem[r] = t; - return r; - } - - T inline &Append() { - if (count >= alloc) Grow(); - return mem[count++]; - } - - void inline Compact() { - Resize(count); - } - - void inline Free() { - free(mem); - Init(); - } - - void inline Clear() { - count = 0; - } - - bool inline MoveUpLast(size_t index) { - assert(index < count); - size_t c = --count; - if (index != c) { - mem[index] = mem[c]; - return true; - } - return false; - } - - bool inline MoveUpLastExist(const T &v) { - return MoveUpLast(LookupElementExist(v)); - } - - size_t inline LookupElement(const T &v) const { - for(size_t i = 0; i != count; i++) - if (mem[i] == v) - return i; - return (size_t) -1; - } - - bool inline HasElement(const T &v) const { - return LookupElement(v) != -1; - } - - typedef int SortCompareProc(const T *a, const T *b); - - void Sort(SortCompareProc* proc, size_t start, size_t end) { - QuickSortT(&mem[start], end - start, proc); - } - - void Sort(SortCompareProc* proc, size_t start) { - Sort(proc, start, count); - } - - void Sort(SortCompareProc* proc) { - Sort(proc, 0, count); - } -}; - -#endif //__TEMPLATES_H__ diff --git a/third-party/libutp/utp.cpp b/third-party/libutp/utp.cpp deleted file mode 100644 index 3a4b2b21a..000000000 --- a/third-party/libutp/utp.cpp +++ /dev/null @@ -1,2867 +0,0 @@ -#include - -#include "utp.h" -#include "templates.h" - -#include -#include -#include -#include -#include -#include -#include // for UINT_MAX - -#ifdef WIN32 -#include "win32_inet_ntop.h" - -// newer versions of MSVC define these in errno.h -#ifndef ECONNRESET -#define ECONNRESET WSAECONNRESET -#define EMSGSIZE WSAEMSGSIZE -#define ECONNREFUSED WSAECONNREFUSED -#define ETIMEDOUT WSAETIMEDOUT -#endif -#endif - -#ifdef POSIX -typedef sockaddr_storage SOCKADDR_STORAGE; -#endif // POSIX - -// number of bytes to increase max window size by, per RTT. This is -// scaled down linearly proportional to off_target. i.e. if all packets -// in one window have 0 delay, window size will increase by this number. -// Typically it's less. TCP increases one MSS per RTT, which is 1500 -#define MAX_CWND_INCREASE_BYTES_PER_RTT 3000 -#define CUR_DELAY_SIZE 3 -// experiments suggest that a clock skew of 10 ms per 325 seconds -// is not impossible. Reset delay_base every 13 minutes. The clock -// skew is dealt with by observing the delay base in the other -// direction, and adjusting our own upwards if the opposite direction -// delay base keeps going down -#define DELAY_BASE_HISTORY 13 -#define MAX_WINDOW_DECAY 100 // ms - -#define REORDER_BUFFER_SIZE 32 -#define REORDER_BUFFER_MAX_SIZE 511 -#define OUTGOING_BUFFER_MAX_SIZE 511 - -#define PACKET_SIZE 350 - -// this is the minimum max_window value. It can never drop below this -#define MIN_WINDOW_SIZE 10 - -// when window sizes are smaller than one packet_size, this -// will pace the packets to average at the given window size -// if it's not set, it will simply not send anything until -// there's a timeout -#define USE_PACKET_PACING 1 - -// if we receive 4 or more duplicate acks, we resend the packet -// that hasn't been acked yet -#define DUPLICATE_ACKS_BEFORE_RESEND 3 - -#define DELAYED_ACK_BYTE_THRESHOLD 2400 // bytes -#define DELAYED_ACK_TIME_THRESHOLD 100 // milliseconds - -#define RST_INFO_TIMEOUT 10000 -#define RST_INFO_LIMIT 1000 -// 29 seconds determined from measuring many home NAT devices -#define KEEPALIVE_INTERVAL 29000 - - -#define SEQ_NR_MASK 0xFFFF -#define ACK_NR_MASK 0xFFFF - -#define DIV_ROUND_UP(num, denom) ((num + denom - 1) / denom) - -#include "utp_utils.h" -#include "utp_config.h" - -#define LOG_UTP if (g_log_utp) utp_log -#define LOG_UTPV if (g_log_utp_verbose) utp_log - -uint32 g_current_ms; - -// The totals are derived from the following data: -// 45: IPv6 address including embedded IPv4 address -// 11: Scope Id -// 2: Brackets around IPv6 address when port is present -// 6: Port (including colon) -// 1: Terminating null byte -char addrbuf[65]; -char addrbuf2[65]; -#define addrfmt(x, s) x.fmt(s, sizeof(s)) - -#if (defined(__SVR4) && defined(__sun)) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -struct PACKED_ATTRIBUTE PackedSockAddr { - - // The values are always stored here in network byte order - union { - byte _in6[16]; // IPv6 - uint16 _in6w[8]; // IPv6, word based (for convenience) - uint32 _in6d[4]; // Dword access - in6_addr _in6addr; // For convenience - } _in; - - // Host byte order - uint16 _port; - -#define _sin4 _in._in6d[3] // IPv4 is stored where it goes if mapped - -#define _sin6 _in._in6 -#define _sin6w _in._in6w -#define _sin6d _in._in6d - - byte get_family() const - { - return (IN6_IS_ADDR_V4MAPPED(&_in._in6addr) != 0) ? AF_INET : AF_INET6; - } - - bool operator==(const PackedSockAddr& rhs) const - { - if (&rhs == this) - return true; - if (_port != rhs._port) - return false; - return memcmp(_sin6, rhs._sin6, sizeof(_sin6)) == 0; - } - bool operator!=(const PackedSockAddr& rhs) const { return !(*this == rhs); } - - PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len) - { - if (sa->ss_family == AF_INET) { - assert(len >= sizeof(sockaddr_in)); - const sockaddr_in *sin = (sockaddr_in*)sa; - _sin6w[0] = 0; - _sin6w[1] = 0; - _sin6w[2] = 0; - _sin6w[3] = 0; - _sin6w[4] = 0; - _sin6w[5] = 0xffff; - _sin4 = sin->sin_addr.s_addr; - _port = ntohs(sin->sin_port); - } else { - assert(len >= sizeof(sockaddr_in6)); - const sockaddr_in6 *sin6 = (sockaddr_in6*)sa; - _in._in6addr = sin6->sin6_addr; - _port = ntohs(sin6->sin6_port); - } - } - - SOCKADDR_STORAGE get_sockaddr_storage(socklen_t *len = NULL) const - { - SOCKADDR_STORAGE sa; - const byte family = get_family(); - if (family == AF_INET) { - sockaddr_in *sin = (sockaddr_in*)&sa; - if (len) *len = sizeof(sockaddr_in); - memset(sin, 0, sizeof(sockaddr_in)); - sin->sin_family = family; - sin->sin_port = htons(_port); - sin->sin_addr.s_addr = _sin4; - } else { - sockaddr_in6 *sin6 = (sockaddr_in6*)&sa; - memset(sin6, 0, sizeof(sockaddr_in6)); - if (len) *len = sizeof(sockaddr_in6); - sin6->sin6_family = family; - sin6->sin6_addr = _in._in6addr; - sin6->sin6_port = htons(_port); - } - return sa; - } - - cstr fmt(str s, size_t len) const - { - memset(s, 0, len); - const byte family = get_family(); - str i; - if (family == AF_INET) { - inet_ntop(family, (uint32*)&_sin4, s, len); - i = s; - while (*++i) {} - } else { - i = s; - *i++ = '['; - inet_ntop(family, (in6_addr*)&_in._in6addr, i, len-1); - while (*++i) {} - *i++ = ']'; - } - snprintf(i, len - (i-s), ":%u", _port); - return s; - } -} ALIGNED_ATTRIBUTE(4); - -struct PACKED_ATTRIBUTE RST_Info { - PackedSockAddr addr; - uint32 connid; - uint32 timestamp; - uint16 ack_nr; -}; - -// these packet sizes are including the uTP header wich -// is either 20 or 23 bytes depending on version -#define PACKET_SIZE_EMPTY_BUCKET 0 -#define PACKET_SIZE_EMPTY 23 -#define PACKET_SIZE_SMALL_BUCKET 1 -#define PACKET_SIZE_SMALL 373 -#define PACKET_SIZE_MID_BUCKET 2 -#define PACKET_SIZE_MID 723 -#define PACKET_SIZE_BIG_BUCKET 3 -#define PACKET_SIZE_BIG 1400 -#define PACKET_SIZE_HUGE_BUCKET 4 - -struct PACKED_ATTRIBUTE PacketFormat { - // connection ID - uint32_big connid; - uint32_big tv_sec; - uint32_big tv_usec; - uint32_big reply_micro; - // receive window size in PACKET_SIZE chunks - byte windowsize; - // Type of the first extension header - byte ext; - // Flags - byte flags; - // Sequence number - uint16_big seq_nr; - // Acknowledgment number - uint16_big ack_nr; -}; - -struct PACKED_ATTRIBUTE PacketFormatAck { - PacketFormat pf; - byte ext_next; - byte ext_len; - byte acks[4]; -}; - -struct PACKED_ATTRIBUTE PacketFormatExtensions { - PacketFormat pf; - byte ext_next; - byte ext_len; - byte extensions[8]; -}; - -struct PACKED_ATTRIBUTE PacketFormatV1 { - // packet_type (4 high bits) - // protocol version (4 low bits) - byte ver_type; - byte version() const { return ver_type & 0xf; } - byte type() const { return ver_type >> 4; } - void set_version(byte v) { ver_type = (ver_type & 0xf0) | (v & 0xf); } - void set_type(byte t) { ver_type = (ver_type & 0xf) | (t << 4); } - - // Type of the first extension header - byte ext; - // connection ID - uint16_big connid; - uint32_big tv_usec; - uint32_big reply_micro; - // receive window size in bytes - uint32_big windowsize; - // Sequence number - uint16_big seq_nr; - // Acknowledgment number - uint16_big ack_nr; -}; - -struct PACKED_ATTRIBUTE PacketFormatAckV1 { - PacketFormatV1 pf; - byte ext_next; - byte ext_len; - byte acks[4]; -}; - -struct PACKED_ATTRIBUTE PacketFormatExtensionsV1 { - PacketFormatV1 pf; - byte ext_next; - byte ext_len; - byte extensions[8]; -}; - -#if (defined(__SVR4) && defined(__sun)) -#pragma pack(0) -#else -#pragma pack(pop) -#endif - -enum { - ST_DATA = 0, // Data packet. - ST_FIN = 1, // Finalize the connection. This is the last packet. - ST_STATE = 2, // State packet. Used to transmit an ACK with no data. - ST_RESET = 3, // Terminate connection forcefully. - ST_SYN = 4, // Connect SYN - ST_NUM_STATES, // used for bounds checking -}; - -static const cstr flagnames[] = { - "ST_DATA","ST_FIN","ST_STATE","ST_RESET","ST_SYN" -}; - -enum CONN_STATE { - CS_IDLE = 0, - CS_SYN_SENT = 1, - CS_CONNECTED = 2, - CS_CONNECTED_FULL = 3, - CS_GOT_FIN = 4, - CS_DESTROY_DELAY = 5, - CS_FIN_SENT = 6, - CS_RESET = 7, - CS_DESTROY = 8, -}; - -static const cstr statenames[] = { - "IDLE","SYN_SENT","CONNECTED","CONNECTED_FULL","GOT_FIN","DESTROY_DELAY","FIN_SENT","RESET","DESTROY" -}; - -struct OutgoingPacket { - size_t length; - size_t payload; - uint64 time_sent; // microseconds - uint transmissions:31; - bool need_resend:1; - byte data[1]; -}; - -void no_read(void *socket, const byte *bytes, size_t count) {} -void no_write(void *socket, byte *bytes, size_t count) {} -size_t no_rb_size(void *socket) { return 0; } -void no_state(void *socket, int state) {} -void no_error(void *socket, int errcode) {} -void no_overhead(void *socket, bool send, size_t count, int type) {} - -UTPFunctionTable zero_funcs = { - &no_read, - &no_write, - &no_rb_size, - &no_state, - &no_error, - &no_overhead, -}; - -struct SizableCircularBuffer { - // This is the mask. Since it's always a power of 2, adding 1 to this value will return the size. - size_t mask; - // This is the elements that the circular buffer points to - void **elements; - - void *get(size_t i) { assert(elements); return elements ? elements[i & mask] : NULL; } - void put(size_t i, void *data) { assert(elements); elements[i&mask] = data; } - - void grow(size_t item, size_t index); - void ensure_size(size_t item, size_t index) { if (index > mask) grow(item, index); } - size_t size() { return mask + 1; } -}; - -static struct UTPGlobalStats _global_stats; - -// Item contains the element we want to make space for -// index is the index in the list. -void SizableCircularBuffer::grow(size_t item, size_t index) -{ - // Figure out the new size. - size_t size = mask + 1; - do size *= 2; while (index >= size); - - // Allocate the new buffer - void **buf = (void**)calloc(size, sizeof(void*)); - - size--; - - // Copy elements from the old buffer to the new buffer - for (size_t i = 0; i <= mask; i++) { - buf[(item - index + i) & size] = get(item - index + i); - } - - // Swap to the newly allocated buffer - mask = size; - free(elements); - elements = buf; -} - -// compare if lhs is less than rhs, taking wrapping -// into account. if lhs is close to UINT_MAX and rhs -// is close to 0, lhs is assumed to have wrapped and -// considered smaller -bool wrapping_compare_less(uint32 lhs, uint32 rhs) -{ - // distance walking from lhs to rhs, downwards - const uint32 dist_down = lhs - rhs; - // distance walking from lhs to rhs, upwards - const uint32 dist_up = rhs - lhs; - - // if the distance walking up is shorter, lhs - // is less than rhs. If the distance walking down - // is shorter, then rhs is less than lhs - return dist_up < dist_down; -} - -struct DelayHist { - uint32 delay_base; - - // this is the history of delay samples, - // normalized by using the delay_base. These - // values are always greater than 0 and measures - // the queuing delay in microseconds - uint32 cur_delay_hist[CUR_DELAY_SIZE]; - size_t cur_delay_idx; - - // this is the history of delay_base. It's - // a number that doesn't have an absolute meaning - // only relative. It doesn't make sense to initialize - // it to anything other than values relative to - // what's been seen in the real world. - uint32 delay_base_hist[DELAY_BASE_HISTORY]; - size_t delay_base_idx; - // the time when we last stepped the delay_base_idx - uint32 delay_base_time; - - bool delay_base_initialized; - - void clear() - { - delay_base_initialized = false; - delay_base = 0; - cur_delay_idx = 0; - delay_base_idx = 0; - delay_base_time = g_current_ms; - for (size_t i = 0; i < CUR_DELAY_SIZE; i++) { - cur_delay_hist[i] = 0; - } - for (size_t i = 0; i < DELAY_BASE_HISTORY; i++) { - delay_base_hist[i] = 0; - } - } - - void shift(const uint32 offset) - { - // the offset should never be "negative" - // assert(offset < 0x10000000); - - // increase all of our base delays by this amount - // this is used to take clock skew into account - // by observing the other side's changes in its base_delay - for (size_t i = 0; i < DELAY_BASE_HISTORY; i++) { - delay_base_hist[i] += offset; - } - delay_base += offset; - } - - void add_sample(const uint32 sample) - { - // The two clocks (in the two peers) are assumed not to - // progress at the exact same rate. They are assumed to be - // drifting, which causes the delay samples to contain - // a systematic error, either they are under- - // estimated or over-estimated. This is why we update the - // delay_base every two minutes, to adjust for this. - - // This means the values will keep drifting and eventually wrap. - // We can cross the wrapping boundry in two directions, either - // going up, crossing the highest value, or going down, crossing 0. - - // if the delay_base is close to the max value and sample actually - // wrapped on the other end we would see something like this: - // delay_base = 0xffffff00, sample = 0x00000400 - // sample - delay_base = 0x500 which is the correct difference - - // if the delay_base is instead close to 0, and we got an even lower - // sample (that will eventually update the delay_base), we may see - // something like this: - // delay_base = 0x00000400, sample = 0xffffff00 - // sample - delay_base = 0xfffffb00 - // this needs to be interpreted as a negative number and the actual - // recorded delay should be 0. - - // It is important that all arithmetic that assume wrapping - // is done with unsigned intergers. Signed integers are not guaranteed - // to wrap the way unsigned integers do. At least GCC takes advantage - // of this relaxed rule and won't necessarily wrap signed ints. - - // remove the clock offset and propagation delay. - // delay base is min of the sample and the current - // delay base. This min-operation is subject to wrapping - // and care needs to be taken to correctly choose the - // true minimum. - - // specifically the problem case is when delay_base is very small - // and sample is very large (because it wrapped past zero), sample - // needs to be considered the smaller - - if (!delay_base_initialized) { - // delay_base being 0 suggests that we haven't initialized - // it or its history with any real measurements yet. Initialize - // everything with this sample. - for (size_t i = 0; i < DELAY_BASE_HISTORY; i++) { - // if we don't have a value, set it to the current sample - delay_base_hist[i] = sample; - continue; - } - delay_base = sample; - delay_base_initialized = true; - } - - if (wrapping_compare_less(sample, delay_base_hist[delay_base_idx])) { - // sample is smaller than the current delay_base_hist entry - // update it - delay_base_hist[delay_base_idx] = sample; - } - - // is sample lower than delay_base? If so, update delay_base - if (wrapping_compare_less(sample, delay_base)) { - // sample is smaller than the current delay_base - // update it - delay_base = sample; - } - - // this operation may wrap, and is supposed to - const uint32 delay = sample - delay_base; - // sanity check. If this is triggered, something fishy is going on - // it means the measured sample was greater than 32 seconds! -// assert(delay < 0x2000000); - - cur_delay_hist[cur_delay_idx] = delay; - cur_delay_idx = (cur_delay_idx + 1) % CUR_DELAY_SIZE; - - // once every minute - if (g_current_ms - delay_base_time > 60 * 1000) { - delay_base_time = g_current_ms; - delay_base_idx = (delay_base_idx + 1) % DELAY_BASE_HISTORY; - // clear up the new delay base history spot by initializing - // it to the current sample, then update it - delay_base_hist[delay_base_idx] = sample; - delay_base = delay_base_hist[0]; - // Assign the lowest delay in the last 2 minutes to delay_base - for (size_t i = 0; i < DELAY_BASE_HISTORY; i++) { - if (wrapping_compare_less(delay_base_hist[i], delay_base)) - delay_base = delay_base_hist[i]; - } - } - } - - uint32 get_value() - { - uint32 value = UINT_MAX; - for (size_t i = 0; i < CUR_DELAY_SIZE; i++) { - value = min(cur_delay_hist[i], value); - } - // value could be UINT_MAX if we have no samples yet... - return value; - } -}; - -struct UTPSocket { - PackedSockAddr addr; - - size_t idx; - - uint16 reorder_count; - byte duplicate_ack; - - // the number of bytes we've received but not acked yet - size_t bytes_since_ack; - - // the number of packets in the send queue. Packets that haven't - // yet been sent count as well as packets marked as needing resend - // the oldest un-acked packet in the send queue is seq_nr - cur_window_packets - uint16 cur_window_packets; - - // how much of the window is used, number of bytes in-flight - // packets that have not yet been sent do not count, packets - // that are marked as needing to be re-sent (due to a timeout) - // don't count either - size_t cur_window; - // maximum window size, in bytes - size_t max_window; - // SO_SNDBUF setting, in bytes - size_t opt_sndbuf; - // SO_RCVBUF setting, in bytes - size_t opt_rcvbuf; - - // Is a FIN packet in the reassembly buffer? - bool got_fin:1; - // Timeout procedure - bool fast_timeout:1; - - // max receive window for other end, in bytes - size_t max_window_user; - // 0 = original uTP header, 1 = second revision - byte version; - CONN_STATE state; - // TickCount when we last decayed window (wraps) - int32 last_rwin_decay; - - // the sequence number of the FIN packet. This field is only set - // when we have received a FIN, and the flag field has the FIN flag set. - // it is used to know when it is safe to destroy the socket, we must have - // received all packets up to this sequence number first. - uint16 eof_pkt; - - // All sequence numbers up to including this have been properly received - // by us - uint16 ack_nr; - // This is the sequence number for the next packet to be sent. - uint16 seq_nr; - - uint16 timeout_seq_nr; - - // This is the sequence number of the next packet we're allowed to - // do a fast resend with. This makes sure we only do a fast-resend - // once per packet. We can resend the packet with this sequence number - // or any later packet (with a higher sequence number). - uint16 fast_resend_seq_nr; - - uint32 reply_micro; - - // the time when we need to send another ack. If there's - // nothing to ack, this is a very large number - uint32 ack_time; - - uint32 last_got_packet; - uint32 last_sent_packet; - uint32 last_measured_delay; - uint32 last_maxed_out_window; - - // the last time we added send quota to the connection - // when adding send quota, this is subtracted from the - // current time multiplied by max_window / rtt - // which is the current allowed send rate. - int32 last_send_quota; - - // the number of bytes we are allowed to send on - // this connection. If this is more than one packet - // size when we run out of data to send, it is clamped - // to the packet size - // this value is multiplied by 100 in order to get - // higher accuracy when dealing with low rates - int32 send_quota; - - SendToProc *send_to_proc; - void *send_to_userdata; - UTPFunctionTable func; - void *userdata; - - // Round trip time - uint rtt; - // Round trip time variance - uint rtt_var; - // Round trip timeout - uint rto; - DelayHist rtt_hist; - uint retransmit_timeout; - // The RTO timer will timeout here. - uint rto_timeout; - // When the window size is set to zero, start this timer. It will send a new packet every 30secs. - uint32 zerowindow_time; - - uint32 conn_seed; - // Connection ID for packets I receive - uint32 conn_id_recv; - // Connection ID for packets I send - uint32 conn_id_send; - // Last rcv window we advertised, in bytes - size_t last_rcv_win; - - DelayHist our_hist; - DelayHist their_hist; - - // extension bytes from SYN packet - byte extensions[8]; - - SizableCircularBuffer inbuf, outbuf; - -#ifdef _DEBUG - // Public stats, returned by UTP_GetStats(). See utp.h - UTPStats _stats; -#endif // _DEBUG - - // Calculates the current receive window - size_t get_rcv_window() const - { - // If we don't have a connection (such as during connection - // establishment, always act as if we have an empty buffer). - if (!userdata) return opt_rcvbuf; - - // Trim window down according to what's already in buffer. - const size_t numbuf = func.get_rb_size(userdata); - assert((int)numbuf >= 0); - return opt_rcvbuf > numbuf ? opt_rcvbuf - numbuf : 0; - } - - // Test if we're ready to decay max_window - // XXX this breaks when spaced by > INT_MAX/2, which is 49 - // days; the failure mode in that case is we do an extra decay - // or fail to do one when we really shouldn't. - bool can_decay_win(int32 msec) const - { - return msec - last_rwin_decay >= MAX_WINDOW_DECAY; - } - - // If we can, decay max window, returns true if we actually did so - void maybe_decay_win() - { - if (can_decay_win(g_current_ms)) { - // TCP uses 0.5 - max_window = (size_t)(max_window * .5); - last_rwin_decay = g_current_ms; - if (max_window < MIN_WINDOW_SIZE) - max_window = MIN_WINDOW_SIZE; - } - } - - size_t get_header_size() const - { - return (version ? sizeof(PacketFormatV1) : sizeof(PacketFormat)); - } - - size_t get_header_extensions_size() const - { - return (version ? sizeof(PacketFormatExtensionsV1) : sizeof(PacketFormatExtensions)); - } - - void sent_ack() - { - ack_time = g_current_ms + 0x70000000; - bytes_since_ack = 0; - } - - size_t get_udp_mtu() const - { - socklen_t len; - SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(&len); - return UTP_GetUDPMTU((const struct sockaddr *)&sa, len); - } - - size_t get_udp_overhead() const - { - socklen_t len; - SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(&len); - return UTP_GetUDPOverhead((const struct sockaddr *)&sa, len); - } - - uint64 get_global_utp_bytes_sent() const - { - socklen_t len; - SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(&len); - return UTP_GetGlobalUTPBytesSent((const struct sockaddr *)&sa, len); - } - - size_t get_overhead() const - { - return get_udp_overhead() + get_header_size(); - } - - void send_data(PacketFormat* b, size_t length, bandwidth_type_t type); - - void send_ack(bool synack = false); - - void send_keep_alive(); - - static void send_rst(SendToProc *send_to_proc, void *send_to_userdata, - const PackedSockAddr &addr, uint32 conn_id_send, - uint16 ack_nr, uint16 seq_nr, byte version); - - void send_packet(OutgoingPacket *pkt); - - bool is_writable(size_t to_write); - - bool flush_packets(); - - void write_outgoing_packet(size_t payload, uint flags); - - void update_send_quota(); - -#ifdef _DEBUG - void check_invariant(); -#endif - - void check_timeouts(); - - int ack_packet(uint16 seq); - - size_t selective_ack_bytes(uint base, const byte* mask, byte len, int64& min_rtt); - - void selective_ack(uint base, const byte *mask, byte len); - - void apply_ledbat_ccontrol(size_t bytes_acked, uint32 actual_delay, int64 min_rtt); - - size_t get_packet_size(); -}; - -Array g_rst_info; -Array g_utp_sockets; - -static void UTP_RegisterSentPacket(size_t length) { - if (length <= PACKET_SIZE_MID) { - if (length <= PACKET_SIZE_EMPTY) { - _global_stats._nraw_send[PACKET_SIZE_EMPTY_BUCKET]++; - } else if (length <= PACKET_SIZE_SMALL) { - _global_stats._nraw_send[PACKET_SIZE_SMALL_BUCKET]++; - } else - _global_stats._nraw_send[PACKET_SIZE_MID_BUCKET]++; - } else { - if (length <= PACKET_SIZE_BIG) { - _global_stats._nraw_send[PACKET_SIZE_BIG_BUCKET]++; - } else - _global_stats._nraw_send[PACKET_SIZE_HUGE_BUCKET]++; - } -} - -void send_to_addr(SendToProc *send_to_proc, void *send_to_userdata, const byte *p, size_t len, const PackedSockAddr &addr) -{ - socklen_t tolen; - SOCKADDR_STORAGE to = addr.get_sockaddr_storage(&tolen); - UTP_RegisterSentPacket(len); - send_to_proc(send_to_userdata, p, len, (const struct sockaddr *)&to, tolen); -} - -void UTPSocket::send_data(PacketFormat* b, size_t length, bandwidth_type_t type) -{ - // time stamp this packet with local time, the stamp goes into - // the header of every packet at the 8th byte for 8 bytes : - // two integers, check packet.h for more - uint64 time = UTP_GetMicroseconds(); - - PacketFormatV1* b1 = (PacketFormatV1*)b; - if (version == 0) { - b->tv_sec = (uint32)(time / 1000000); - b->tv_usec = time % 1000000; - b->reply_micro = reply_micro; - } else { - b1->tv_usec = (uint32)time; - b1->reply_micro = reply_micro; - } - - last_sent_packet = g_current_ms; - -#ifdef _DEBUG - _stats._nbytes_xmit += length; - ++_stats._nxmit; -#endif - if (userdata) { - size_t n; - if (type == payload_bandwidth) { - // if this packet carries payload, just - // count the header as overhead - type = header_overhead; - n = get_overhead(); - } else { - n = length + get_udp_overhead(); - } - func.on_overhead(userdata, true, n, type); - } -#if g_log_utp_verbose - int flags = version == 0 ? b->flags : b1->type(); - uint16 seq_nr = version == 0 ? b->seq_nr : b1->seq_nr; - uint16 ack_nr = version == 0 ? b->ack_nr : b1->ack_nr; - LOG_UTPV("0x%08x: send %s len:%u id:%u timestamp:"I64u" reply_micro:%u flags:%s seq_nr:%u ack_nr:%u", - this, addrfmt(addr, addrbuf), (uint)length, conn_id_send, time, reply_micro, flagnames[flags], - seq_nr, ack_nr); -#endif - send_to_addr(send_to_proc, send_to_userdata, (const byte*)b, length, addr); -} - -void UTPSocket::send_ack(bool synack) -{ - PacketFormatExtensions pfe; - zeromem(&pfe); - PacketFormatExtensionsV1& pfe1 = (PacketFormatExtensionsV1&)pfe; - PacketFormatAck& pfa = (PacketFormatAck&)pfe1; - PacketFormatAckV1& pfa1 = (PacketFormatAckV1&)pfe1; - - size_t len; - last_rcv_win = get_rcv_window(); - if (version == 0) { - pfa.pf.connid = conn_id_send; - pfa.pf.ack_nr = (uint16)ack_nr; - pfa.pf.seq_nr = (uint16)seq_nr; - pfa.pf.flags = ST_STATE; - pfa.pf.ext = 0; - pfa.pf.windowsize = (byte)DIV_ROUND_UP(last_rcv_win, PACKET_SIZE); - len = sizeof(PacketFormat); - } else { - pfa1.pf.set_version(1); - pfa1.pf.set_type(ST_STATE); - pfa1.pf.ext = 0; - pfa1.pf.connid = conn_id_send; - pfa1.pf.ack_nr = ack_nr; - pfa1.pf.seq_nr = seq_nr; - pfa1.pf.windowsize = (uint32)last_rcv_win; - len = sizeof(PacketFormatV1); - } - - // we never need to send EACK for connections - // that are shutting down - if (reorder_count != 0 && state < CS_GOT_FIN) { - // if reorder count > 0, send an EACK. - // reorder count should always be 0 - // for synacks, so this should not be - // as synack - assert(!synack); - if (version == 0) { - pfa.pf.ext = 1; - pfa.ext_next = 0; - pfa.ext_len = 4; - } else { - pfa1.pf.ext = 1; - pfa1.ext_next = 0; - pfa1.ext_len = 4; - } - uint m = 0; - - // reorder count should only be non-zero - // if the packet ack_nr + 1 has not yet - // been received - assert(inbuf.get(ack_nr + 1) == NULL); - size_t window = min(14+16, inbuf.size()); - // Generate bit mask of segments received. - for (size_t i = 0; i < window; i++) { - if (inbuf.get(ack_nr + i + 2) != NULL) { - m |= 1 << i; - LOG_UTPV("0x%08x: EACK packet [%u]", this, ack_nr + i + 2); - } - } - if (version == 0) { - pfa.acks[0] = (byte)m; - pfa.acks[1] = (byte)(m >> 8); - pfa.acks[2] = (byte)(m >> 16); - pfa.acks[3] = (byte)(m >> 24); - } else { - pfa1.acks[0] = (byte)m; - pfa1.acks[1] = (byte)(m >> 8); - pfa1.acks[2] = (byte)(m >> 16); - pfa1.acks[3] = (byte)(m >> 24); - } - len += 4 + 2; - LOG_UTPV("0x%08x: Sending EACK %u [%u] bits:[%032b]", this, ack_nr, conn_id_send, m); - } else if (synack) { - // we only send "extensions" in response to SYN - // and the reorder count is 0 in that state - - LOG_UTPV("0x%08x: Sending ACK %u [%u] with extension bits", this, ack_nr, conn_id_send); - if (version == 0) { - pfe.pf.ext = 2; - pfe.ext_next = 0; - pfe.ext_len = 8; - memset(pfe.extensions, 0, 8); - } else { - pfe1.pf.ext = 2; - pfe1.ext_next = 0; - pfe1.ext_len = 8; - memset(pfe1.extensions, 0, 8); - } - len += 8 + 2; - } else { - LOG_UTPV("0x%08x: Sending ACK %u [%u]", this, ack_nr, conn_id_send); - } - - sent_ack(); - send_data((PacketFormat*)&pfe, len, ack_overhead); -} - -void UTPSocket::send_keep_alive() -{ - ack_nr--; - LOG_UTPV("0x%08x: Sending KeepAlive ACK %u [%u]", this, ack_nr, conn_id_send); - send_ack(); - ack_nr++; -} - -void UTPSocket::send_rst(SendToProc *send_to_proc, void *send_to_userdata, - const PackedSockAddr &addr, uint32 conn_id_send, uint16 ack_nr, uint16 seq_nr, byte version) -{ - PacketFormat pf; - zeromem(&pf); - PacketFormatV1& pf1 = (PacketFormatV1&)pf; - - size_t len; - if (version == 0) { - pf.connid = conn_id_send; - pf.ack_nr = ack_nr; - pf.seq_nr = seq_nr; - pf.flags = ST_RESET; - pf.ext = 0; - pf.windowsize = 0; - len = sizeof(PacketFormat); - } else { - pf1.set_version(1); - pf1.set_type(ST_RESET); - pf1.ext = 0; - pf1.connid = conn_id_send; - pf1.ack_nr = ack_nr; - pf1.seq_nr = seq_nr; - pf1.windowsize = 0; - len = sizeof(PacketFormatV1); - } - - LOG_UTPV("%s: Sending RST id:%u seq_nr:%u ack_nr:%u", addrfmt(addr, addrbuf), conn_id_send, seq_nr, ack_nr); - LOG_UTPV("send %s len:%u id:%u", addrfmt(addr, addrbuf), (uint)len, conn_id_send); - send_to_addr(send_to_proc, send_to_userdata, (const byte*)&pf1, len, addr); -} - -void UTPSocket::send_packet(OutgoingPacket *pkt) -{ - // only count against the quota the first time we - // send the packet. Don't enforce quota when closing - // a socket. Only enforce the quota when we're sending - // at slow rates (max window < packet size) - size_t max_send = min(max_window, opt_sndbuf, max_window_user); - - if (pkt->transmissions == 0 || pkt->need_resend) { - cur_window += pkt->payload; - } - - size_t packet_size = get_packet_size(); - if (pkt->transmissions == 0 && max_send < packet_size) { - assert(state == CS_FIN_SENT || - (int32)pkt->payload <= send_quota / 100); - send_quota = send_quota - (int32)(pkt->payload * 100); - } - - pkt->need_resend = false; - - PacketFormatV1* p1 = (PacketFormatV1*)pkt->data; - PacketFormat* p = (PacketFormat*)pkt->data; - if (version == 0) { - p->ack_nr = ack_nr; - } else { - p1->ack_nr = ack_nr; - } - pkt->time_sent = UTP_GetMicroseconds(); - pkt->transmissions++; - sent_ack(); - send_data((PacketFormat*)pkt->data, pkt->length, - (state == CS_SYN_SENT) ? connect_overhead - : (pkt->transmissions == 1) ? payload_bandwidth - : retransmit_overhead); -} - -bool UTPSocket::is_writable(size_t to_write) -{ - // return true if it's OK to stuff another packet into the - // outgoing queue. Since we may be using packet pacing, we - // might not actually send the packet right away to affect the - // cur_window. The only thing that happens when we add another - // packet is that cur_window_packets is increased. - size_t max_send = min(max_window, opt_sndbuf, max_window_user); - - size_t packet_size = get_packet_size(); - - if (cur_window + packet_size >= max_window) - last_maxed_out_window = g_current_ms; - - // if we don't have enough quota, we can't write regardless - if (USE_PACKET_PACING) { - if (send_quota / 100 < (int32)to_write) return false; - } - - // subtract one to save space for the FIN packet - if (cur_window_packets >= OUTGOING_BUFFER_MAX_SIZE - 1) return false; - - // if sending another packet would not make the window exceed - // the max_window, we can write - if (cur_window + packet_size <= max_send) return true; - - // if the window size is less than a packet, and we have enough - // quota to send a packet, we can write, even though it would - // make the window exceed the max size - // the last condition is needed to not put too many packets - // in the send buffer. cur_window isn't updated until we flush - // the send buffer, so we need to take the number of packets - // into account - if (USE_PACKET_PACING) { - if (max_window < to_write && - cur_window < max_window && - cur_window_packets == 0) { - return true; - } - } - - return false; -} - -bool UTPSocket::flush_packets() -{ - size_t packet_size = get_packet_size(); - - // send packets that are waiting on the pacer to be sent - // i has to be an unsigned 16 bit counter to wrap correctly - // signed types are not guaranteed to wrap the way you expect - for (uint16 i = seq_nr - cur_window_packets; i != seq_nr; ++i) { - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(i); - if (pkt == 0 || (pkt->transmissions > 0 && pkt->need_resend == false)) continue; - // have we run out of quota? - if (!is_writable(pkt->payload)) { - return true; - } - - // Nagle check - // don't send the last packet if we have one packet in-flight - // and the current packet is still smaller than packet_size. - if (i != ((seq_nr - 1) & ACK_NR_MASK) || - cur_window_packets == 1 || - pkt->payload >= packet_size) { - send_packet(pkt); - - // No need to send another ack if there is nothing to reorder. - if (reorder_count == 0) { - sent_ack(); - } - } - } - return false; -} - -void UTPSocket::write_outgoing_packet(size_t payload, uint flags) -{ - // Setup initial timeout timer - if (cur_window_packets == 0) { - retransmit_timeout = rto; - rto_timeout = g_current_ms + retransmit_timeout; - assert(cur_window == 0); - } - - size_t packet_size = get_packet_size(); - do { - assert(cur_window_packets < OUTGOING_BUFFER_MAX_SIZE); - assert(flags == ST_DATA || flags == ST_FIN); - - size_t added = 0; - - OutgoingPacket *pkt = NULL; - - if (cur_window_packets > 0) { - pkt = (OutgoingPacket*)outbuf.get(seq_nr - 1); - } - - const size_t header_size = get_header_size(); - bool append = true; - - // if there's any room left in the last packet in the window - // and it hasn't been sent yet, fill that frame first - if (payload && pkt && !pkt->transmissions && pkt->payload < packet_size) { - // Use the previous unsent packet - added = min(payload + pkt->payload, max(packet_size, pkt->payload)) - pkt->payload; - pkt = (OutgoingPacket*)realloc(pkt, - (sizeof(OutgoingPacket) - 1) + - header_size + - pkt->payload + added); - outbuf.put(seq_nr - 1, pkt); - append = false; - assert(!pkt->need_resend); - } else { - // Create the packet to send. - added = payload; - pkt = (OutgoingPacket*)malloc((sizeof(OutgoingPacket) - 1) + - header_size + - added); - pkt->payload = 0; - pkt->transmissions = 0; - pkt->need_resend = false; - } - - if (added) { - // Fill it with data from the upper layer. - func.on_write(userdata, pkt->data + header_size + pkt->payload, added); - } - pkt->payload += added; - pkt->length = header_size + pkt->payload; - - last_rcv_win = get_rcv_window(); - - PacketFormat* p = (PacketFormat*)pkt->data; - PacketFormatV1* p1 = (PacketFormatV1*)pkt->data; - if (version == 0) { - p->connid = conn_id_send; - p->ext = 0; - p->windowsize = (byte)DIV_ROUND_UP(last_rcv_win, PACKET_SIZE); - p->ack_nr = ack_nr; - p->flags = flags; - } else { - p1->set_version(1); - p1->set_type(flags); - p1->ext = 0; - p1->connid = conn_id_send; - p1->windowsize = (uint32)last_rcv_win; - p1->ack_nr = ack_nr; - } - - if (append) { - // Remember the message in the outgoing queue. - outbuf.ensure_size(seq_nr, cur_window_packets); - outbuf.put(seq_nr, pkt); - if (version == 0) p->seq_nr = seq_nr; - else p1->seq_nr = seq_nr; - seq_nr++; - cur_window_packets++; - } - - payload -= added; - - } while (payload); - - flush_packets(); -} - -void UTPSocket::update_send_quota() -{ - int dt = g_current_ms - last_send_quota; - if (dt == 0) return; - last_send_quota = g_current_ms; - size_t add = max_window * dt * 100 / (rtt_hist.delay_base?rtt_hist.delay_base:50); - if (add > max_window * 100 && add > MAX_CWND_INCREASE_BYTES_PER_RTT * 100) add = max_window; - send_quota += (int32)add; -// LOG_UTPV("0x%08x: UTPSocket::update_send_quota dt:%d rtt:%u max_window:%u quota:%d", -// this, dt, rtt, (uint)max_window, send_quota / 100); -} - -#ifdef _DEBUG -void UTPSocket::check_invariant() -{ - if (reorder_count > 0) { - assert(inbuf.get(ack_nr + 1) == NULL); - } - - size_t outstanding_bytes = 0; - for (int i = 0; i < cur_window_packets; ++i) { - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(seq_nr - i - 1); - if (pkt == 0 || pkt->transmissions == 0 || pkt->need_resend) continue; - outstanding_bytes += pkt->payload; - } - assert(outstanding_bytes == cur_window); -} -#endif - -void UTPSocket::check_timeouts() -{ -#ifdef _DEBUG - check_invariant(); -#endif - - // this invariant should always be true - assert(cur_window_packets == 0 || outbuf.get(seq_nr - cur_window_packets)); - - LOG_UTPV("0x%08x: CheckTimeouts timeout:%d max_window:%u cur_window:%u quota:%d " - "state:%s cur_window_packets:%u bytes_since_ack:%u ack_time:%d", - this, (int)(rto_timeout - g_current_ms), (uint)max_window, (uint)cur_window, - send_quota / 100, statenames[state], cur_window_packets, - (uint)bytes_since_ack, (int)(g_current_ms - ack_time)); - - update_send_quota(); - flush_packets(); - - - if (USE_PACKET_PACING) { - // In case the new send quota made it possible to send another packet - // Mark the socket as writable. If we don't use pacing, the send - // quota does not affect if the socket is writeable - // if we don't use packet pacing, the writable event is triggered - // whenever the cur_window falls below the max_window, so we don't - // need this check then - if (state == CS_CONNECTED_FULL && is_writable(get_packet_size())) { - state = CS_CONNECTED; - LOG_UTPV("0x%08x: Socket writable. max_window:%u cur_window:%u quota:%d packet_size:%u", - this, (uint)max_window, (uint)cur_window, send_quota / 100, (uint)get_packet_size()); - func.on_state(userdata, UTP_STATE_WRITABLE); - } - } - - switch (state) { - case CS_SYN_SENT: - case CS_CONNECTED_FULL: - case CS_CONNECTED: - case CS_FIN_SENT: { - - // Reset max window... - if ((int)(g_current_ms - zerowindow_time) >= 0 && max_window_user == 0) { - max_window_user = PACKET_SIZE; - } - - if ((int)(g_current_ms - rto_timeout) >= 0 && - (!(USE_PACKET_PACING) || cur_window_packets > 0) && - rto_timeout > 0) { - - /* - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(seq_nr - cur_window_packets); - - // If there were a lot of retransmissions, force recomputation of round trip time - if (pkt->transmissions >= 4) - rtt = 0; - */ - - // Increase RTO - const uint new_timeout = retransmit_timeout * 2; - if (new_timeout >= 30000 || (state == CS_SYN_SENT && new_timeout > 6000)) { - // more than 30 seconds with no reply. kill it. - // if we haven't even connected yet, give up sooner. 6 seconds - // means 2 tries at the following timeouts: 3, 6 seconds - if (state == CS_FIN_SENT) - state = CS_DESTROY; - else - state = CS_RESET; - func.on_error(userdata, ETIMEDOUT); - goto getout; - } - - retransmit_timeout = new_timeout; - rto_timeout = g_current_ms + new_timeout; - - // On Timeout - duplicate_ack = 0; - - // rate = min_rate - max_window = get_packet_size(); - send_quota = max((int32)max_window * 100, send_quota); - - // every packet should be considered lost - for (int i = 0; i < cur_window_packets; ++i) { - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(seq_nr - i - 1); - if (pkt == 0 || pkt->transmissions == 0 || pkt->need_resend) continue; - pkt->need_resend = true; - assert(cur_window >= pkt->payload); - cur_window -= pkt->payload; - } - - // used in parse_log.py - LOG_UTP("0x%08x: Packet timeout. Resend. seq_nr:%u. timeout:%u max_window:%u", - this, seq_nr - cur_window_packets, retransmit_timeout, (uint)max_window); - - fast_timeout = true; - timeout_seq_nr = seq_nr; - - if (cur_window_packets > 0) { - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(seq_nr - cur_window_packets); - assert(pkt); - send_quota = max((int32)pkt->length * 100, send_quota); - - // Re-send the packet. - send_packet(pkt); - } - } - - // Mark the socket as writable - if (state == CS_CONNECTED_FULL && is_writable(get_packet_size())) { - state = CS_CONNECTED; - LOG_UTPV("0x%08x: Socket writable. max_window:%u cur_window:%u quota:%d packet_size:%u", - this, (uint)max_window, (uint)cur_window, send_quota / 100, (uint)get_packet_size()); - func.on_state(userdata, UTP_STATE_WRITABLE); - } - - if (state >= CS_CONNECTED && state <= CS_FIN_SENT) { - // Send acknowledgment packets periodically, or when the threshold is reached - if (bytes_since_ack > DELAYED_ACK_BYTE_THRESHOLD || - (int)(g_current_ms - ack_time) >= 0) { - send_ack(); - } - - if ((int)(g_current_ms - last_sent_packet) >= KEEPALIVE_INTERVAL) { - send_keep_alive(); - } - } - - break; - } - - // Close? - case CS_GOT_FIN: - case CS_DESTROY_DELAY: - if ((int)(g_current_ms - rto_timeout) >= 0) { - state = (state == CS_DESTROY_DELAY) ? CS_DESTROY : CS_RESET; - if (cur_window_packets > 0 && userdata) { - func.on_error(userdata, ECONNRESET); - } - } - break; - // prevent warning - case CS_IDLE: - case CS_RESET: - case CS_DESTROY: - break; - } - - getout: - - // make sure we don't accumulate quota when we don't have - // anything to send - int32 limit = max((int32)max_window / 2, 5 * (int32)get_packet_size()) * 100; - if (send_quota > limit) send_quota = limit; -} - -// returns: -// 0: the packet was acked. -// 1: it means that the packet had already been acked -// 2: the packet has not been sent yet -int UTPSocket::ack_packet(uint16 seq) -{ - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(seq); - - // the packet has already been acked (or not sent) - if (pkt == NULL) { - LOG_UTPV("0x%08x: got ack for:%u (already acked, or never sent)", this, seq); - return 1; - } - - // can't ack packets that haven't been sent yet! - if (pkt->transmissions == 0) { - LOG_UTPV("0x%08x: got ack for:%u (never sent, pkt_size:%u need_resend:%u)", - this, seq, (uint)pkt->payload, pkt->need_resend); - return 2; - } - - LOG_UTPV("0x%08x: got ack for:%u (pkt_size:%u need_resend:%u)", - this, seq, (uint)pkt->payload, pkt->need_resend); - - outbuf.put(seq, NULL); - - // if we never re-sent the packet, update the RTT estimate - if (pkt->transmissions == 1) { - // Estimate the round trip time. - const uint32 ertt = (uint32)((UTP_GetMicroseconds() - pkt->time_sent) / 1000); - if (rtt == 0) { - // First round trip time sample - rtt = ertt; - rtt_var = ertt / 2; - // sanity check. rtt should never be more than 6 seconds -// assert(rtt < 6000); - } else { - // Compute new round trip times - const int delta = (int)rtt - ertt; - rtt_var = rtt_var + (int)(abs(delta) - rtt_var) / 4; - rtt = rtt - rtt/8 + ertt/8; - // sanity check. rtt should never be more than 6 seconds -// assert(rtt < 6000); - rtt_hist.add_sample(ertt); - } - rto = max(rtt + rtt_var * 4, 500); - LOG_UTPV("0x%08x: rtt:%u avg:%u var:%u rto:%u", - this, ertt, rtt, rtt_var, rto); - } - retransmit_timeout = rto; - rto_timeout = g_current_ms + rto; - // if need_resend is set, this packet has already - // been considered timed-out, and is not included in - // the cur_window anymore - if (!pkt->need_resend) { - assert(cur_window >= pkt->payload); - cur_window -= pkt->payload; - } - free(pkt); - return 0; -} - -// count the number of bytes that were acked by the EACK header -size_t UTPSocket::selective_ack_bytes(uint base, const byte* mask, byte len, int64& min_rtt) -{ - if (cur_window_packets == 0) return 0; - - size_t acked_bytes = 0; - int bits = len * 8; - - do { - uint v = base + bits; - - // ignore bits that haven't been sent yet - // see comment in UTPSocket::selective_ack - if (((seq_nr - v - 1) & ACK_NR_MASK) >= (uint16)(cur_window_packets - 1)) - continue; - - // ignore bits that represents packets we haven't sent yet - // or packets that have already been acked - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(v); - if (!pkt || pkt->transmissions == 0) - continue; - - // Count the number of segments that were successfully received past it. - if (bits >= 0 && mask[bits>>3] & (1 << (bits & 7))) { - assert((int)(pkt->payload) >= 0); - acked_bytes += pkt->payload; - min_rtt = min(min_rtt, UTP_GetMicroseconds() - pkt->time_sent); - continue; - } - } while (--bits >= -1); - return acked_bytes; -} - -enum { MAX_EACK = 128 }; - -void UTPSocket::selective_ack(uint base, const byte *mask, byte len) -{ - if (cur_window_packets == 0) return; - - // the range is inclusive [0, 31] bits - int bits = len * 8 - 1; - - int count = 0; - - // resends is a stack of sequence numbers we need to resend. Since we - // iterate in reverse over the acked packets, at the end, the top packets - // are the ones we want to resend - int resends[MAX_EACK]; - int nr = 0; - - LOG_UTPV("0x%08x: Got EACK [%032b] base:%u", this, *(uint32*)mask, base); - do { - // we're iterating over the bits from higher sequence numbers - // to lower (kind of in reverse order, wich might not be very - // intuitive) - uint v = base + bits; - - // ignore bits that haven't been sent yet - // and bits that fall below the ACKed sequence number - // this can happen if an EACK message gets - // reordered and arrives after a packet that ACKs up past - // the base for thie EACK message - - // this is essentially the same as: - // if v >= seq_nr || v <= seq_nr - cur_window_packets - // but it takes wrapping into account - - // if v == seq_nr the -1 will make it wrap. if v > seq_nr - // it will also wrap (since it will fall further below 0) - // and be > cur_window_packets. - // if v == seq_nr - cur_window_packets, the result will be - // seq_nr - (seq_nr - cur_window_packets) - 1 - // == seq_nr - seq_nr + cur_window_packets - 1 - // == cur_window_packets - 1 which will be caught by the - // test. If v < seq_nr - cur_window_packets the result will grow - // fall furhter outside of the cur_window_packets range. - - // sequence number space: - // - // rejected < accepted > rejected - // <============+--------------+============> - // ^ ^ - // | | - // (seq_nr-wnd) seq_nr - - if (((seq_nr - v - 1) & ACK_NR_MASK) >= (uint16)(cur_window_packets - 1)) - continue; - - // this counts as a duplicate ack, even though we might have - // received an ack for this packet previously (in another EACK - // message for instance) - bool bit_set = bits >= 0 && mask[bits>>3] & (1 << (bits & 7)); - - // if this packet is acked, it counts towards the duplicate ack counter - if (bit_set) count++; - - // ignore bits that represents packets we haven't sent yet - // or packets that have already been acked - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(v); - if (!pkt || pkt->transmissions == 0) { - LOG_UTPV("0x%08x: skipping %u. pkt:%08x transmissions:%u %s", - this, v, pkt, pkt?pkt->transmissions:0, pkt?"(not sent yet?)":"(already acked?)"); - continue; - } - - // Count the number of segments that were successfully received past it. - if (bit_set) { - // the selective ack should never ACK the packet we're waiting for to decrement cur_window_packets - assert((v & outbuf.mask) != ((seq_nr - cur_window_packets) & outbuf.mask)); - ack_packet(v); - continue; - } - - // Resend segments - // if count is less than our re-send limit, we haven't seen enough - // acked packets in front of this one to warrant a re-send. - // if count == 0, we're still going through the tail of zeroes - if (((v - fast_resend_seq_nr) & ACK_NR_MASK) <= OUTGOING_BUFFER_MAX_SIZE && - count >= DUPLICATE_ACKS_BEFORE_RESEND && - duplicate_ack < DUPLICATE_ACKS_BEFORE_RESEND) { - // resends is a stack, and we're mostly interested in the top of it - // if we're full, just throw away the lower half - if (nr >= MAX_EACK - 2) { - memmove(resends, &resends[MAX_EACK/2], MAX_EACK/2 * sizeof(resends[0])); - nr -= MAX_EACK / 2; - } - resends[nr++] = v; - LOG_UTPV("0x%08x: no ack for %u", this, v); - } else { - LOG_UTPV("0x%08x: not resending %u count:%d dup_ack:%u fast_resend_seq_nr:%u", - this, v, count, duplicate_ack, fast_resend_seq_nr); - } - } while (--bits >= -1); - - if (((base - 1 - fast_resend_seq_nr) & ACK_NR_MASK) <= OUTGOING_BUFFER_MAX_SIZE && - count >= DUPLICATE_ACKS_BEFORE_RESEND) { - // if we get enough duplicate acks to start - // resending, the first packet we should resend - // is base-1 - resends[nr++] = (base - 1) & ACK_NR_MASK; - } else { - LOG_UTPV("0x%08x: not resending %u count:%d dup_ack:%u fast_resend_seq_nr:%u", - this, base - 1, count, duplicate_ack, fast_resend_seq_nr); - } - - bool back_off = false; - int i = 0; - while (nr > 0) { - uint v = resends[--nr]; - // don't consider the tail of 0:es to be lost packets - // only unacked packets with acked packets after should - // be considered lost - OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(v); - - // this may be an old (re-ordered) packet, and some of the - // packets in here may have been acked already. In which - // case they will not be in the send queue anymore - if (!pkt) continue; - - // used in parse_log.py - LOG_UTP("0x%08x: Packet %u lost. Resending", this, v); - - // On Loss - back_off = true; -#ifdef _DEBUG - ++_stats._rexmit; -#endif - send_packet(pkt); - fast_resend_seq_nr = v + 1; - - // Re-send max 4 packets. - if (++i >= 4) break; - } - - if (back_off) - maybe_decay_win(); - - duplicate_ack = count; -} - -void UTPSocket::apply_ledbat_ccontrol(size_t bytes_acked, uint32 actual_delay, int64 min_rtt) -{ - // the delay can never be greater than the rtt. The min_rtt - // variable is the RTT in microseconds - - assert(min_rtt >= 0); - int32 our_delay = min(our_hist.get_value(), uint32(min_rtt)); - assert(our_delay != INT_MAX); - assert(our_delay >= 0); - - SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(); - UTP_DelaySample((sockaddr*)&sa, our_delay / 1000); - - // This test the connection under heavy load from foreground - // traffic. Pretend that our delays are very high to force the - // connection to use sub-packet size window sizes - //our_delay *= 4; - - // target is microseconds - int target = CCONTROL_TARGET; - if (target <= 0) target = 100000; - - double off_target = target - our_delay; - - // this is the same as: - // - // (min(off_target, target) / target) * (bytes_acked / max_window) * MAX_CWND_INCREASE_BYTES_PER_RTT - // - // so, it's scaling the max increase by the fraction of the window this ack represents, and the fraction - // of the target delay the current delay represents. - // The min() around off_target protects against crazy values of our_delay, which may happen when th - // timestamps wraps, or by just having a malicious peer sending garbage. This caps the increase - // of the window size to MAX_CWND_INCREASE_BYTES_PER_RTT per rtt. - // as for large negative numbers, this direction is already capped at the min packet size further down - // the min around the bytes_acked protects against the case where the window size was recently - // shrunk and the number of acked bytes exceeds that. This is considered no more than one full - // window, in order to keep the gain within sane boundries. - - assert(bytes_acked > 0); - double window_factor = (double)min(bytes_acked, max_window) / (double)max(max_window, bytes_acked); - double delay_factor = off_target / target; - double scaled_gain = MAX_CWND_INCREASE_BYTES_PER_RTT * window_factor * delay_factor; - - // since MAX_CWND_INCREASE_BYTES_PER_RTT is a cap on how much the window size (max_window) - // may increase per RTT, we may not increase the window size more than that proportional - // to the number of bytes that were acked, so that once one window has been acked (one rtt) - // the increase limit is not exceeded - // the +1. is to allow for floating point imprecision - assert(scaled_gain <= 1. + MAX_CWND_INCREASE_BYTES_PER_RTT * (int)min(bytes_acked, max_window) / (double)max(max_window, bytes_acked)); - - if (scaled_gain > 0 && g_current_ms - last_maxed_out_window > 300) { - // if it was more than 300 milliseconds since we tried to send a packet - // and stopped because we hit the max window, we're most likely rate - // limited (which prevents us from ever hitting the window size) - // if this is the case, we cannot let the max_window grow indefinitely - scaled_gain = 0; - } - - if (scaled_gain + max_window < MIN_WINDOW_SIZE) { - max_window = MIN_WINDOW_SIZE; - } else { - max_window = (size_t)(max_window + scaled_gain); - } - - // make sure that the congestion window is below max - // make sure that we don't shrink our window too small - max_window = clamp(max_window, MIN_WINDOW_SIZE, opt_sndbuf); - - // used in parse_log.py - LOG_UTP("0x%08x: actual_delay:%u our_delay:%d their_delay:%u off_target:%d max_window:%u " - "delay_base:%u delay_sum:%d target_delay:%d acked_bytes:%u cur_window:%u " - "scaled_gain:%f rtt:%u rate:%u quota:%d wnduser:%u rto:%u timeout:%d get_microseconds:"I64u" " - "cur_window_packets:%u packet_size:%u their_delay_base:%u their_actual_delay:%u", - this, actual_delay, our_delay / 1000, their_hist.get_value() / 1000, - (int)off_target / 1000, (uint)(max_window), our_hist.delay_base, - (our_delay + their_hist.get_value()) / 1000, target / 1000, (uint)bytes_acked, - (uint)(cur_window - bytes_acked), (float)(scaled_gain), rtt, - (uint)(max_window * 1000 / (rtt_hist.delay_base?rtt_hist.delay_base:50)), - send_quota / 100, (uint)max_window_user, rto, (int)(rto_timeout - g_current_ms), - UTP_GetMicroseconds(), cur_window_packets, (uint)get_packet_size(), - their_hist.delay_base, their_hist.delay_base + their_hist.get_value()); -} - -static void UTP_RegisterRecvPacket(UTPSocket *conn, size_t len) -{ -#ifdef _DEBUG - ++conn->_stats._nrecv; - conn->_stats._nbytes_recv += len; -#endif - - if (len <= PACKET_SIZE_MID) { - if (len <= PACKET_SIZE_EMPTY) { - _global_stats._nraw_recv[PACKET_SIZE_EMPTY_BUCKET]++; - } else if (len <= PACKET_SIZE_SMALL) { - _global_stats._nraw_recv[PACKET_SIZE_SMALL_BUCKET]++; - } else - _global_stats._nraw_recv[PACKET_SIZE_MID_BUCKET]++; - } else { - if (len <= PACKET_SIZE_BIG) { - _global_stats._nraw_recv[PACKET_SIZE_BIG_BUCKET]++; - } else - _global_stats._nraw_recv[PACKET_SIZE_HUGE_BUCKET]++; - } -} - -// returns the max number of bytes of payload the uTP -// connection is allowed to send -size_t UTPSocket::get_packet_size() -{ - int header_size = version == 1 - ? sizeof(PacketFormatV1) - : sizeof(PacketFormat); - - size_t mtu = get_udp_mtu(); - - if (DYNAMIC_PACKET_SIZE_ENABLED) { - SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(); - size_t max_packet_size = UTP_GetPacketSize((sockaddr*)&sa); - return min(mtu - header_size, max_packet_size); - } - else - { - return mtu - header_size; - } -} - -// Process an incoming packet -// syn is true if this is the first packet received. It will cut off parsing -// as soon as the header is done -size_t UTP_ProcessIncoming(UTPSocket *conn, const byte *packet, size_t len, bool syn = false) -{ - UTP_RegisterRecvPacket(conn, len); - - g_current_ms = UTP_GetMilliseconds(); - - conn->update_send_quota(); - - const PacketFormat *pf = (PacketFormat*)packet; - const PacketFormatV1 *pf1 = (PacketFormatV1*)packet; - const byte *packet_end = packet + len; - - uint16 pk_seq_nr; - uint16 pk_ack_nr; - uint8 pk_flags; - if (conn->version == 0) { - pk_seq_nr = pf->seq_nr; - pk_ack_nr = pf->ack_nr; - pk_flags = pf->flags; - } else { - pk_seq_nr = pf1->seq_nr; - pk_ack_nr = pf1->ack_nr; - pk_flags = pf1->type(); - } - - if (pk_flags >= ST_NUM_STATES) return 0; - - LOG_UTPV("0x%08x: Got %s. seq_nr:%u ack_nr:%u state:%s version:%u timestamp:"I64u" reply_micro:%u", - conn, flagnames[pk_flags], pk_seq_nr, pk_ack_nr, statenames[conn->state], conn->version, - conn->version == 0?(uint64)(pf->tv_sec) * 1000000 + pf->tv_usec:uint64(pf1->tv_usec), - conn->version == 0?(uint32)(pf->reply_micro):(uint32)(pf1->reply_micro)); - - // mark receipt time - uint64 time = UTP_GetMicroseconds(); - - // RSTs are handled earlier, since the connid matches the send id not the recv id - assert(pk_flags != ST_RESET); - - // TODO: maybe send a ST_RESET if we're in CS_RESET? - - const byte *selack_ptr = NULL; - - // Unpack UTP packet options - // Data pointer - const byte *data = (const byte*)pf + conn->get_header_size(); - if (conn->get_header_size() > len) { - LOG_UTPV("0x%08x: Invalid packet size (less than header size)", conn); - return 0; - } - // Skip the extension headers - uint extension = conn->version == 0 ? pf->ext : pf1->ext; - if (extension != 0) { - do { - // Verify that the packet is valid. - data += 2; - - if ((int)(packet_end - data) < 0 || (int)(packet_end - data) < data[-1]) { - LOG_UTPV("0x%08x: Invalid len of extensions", conn); - return 0; - } - - switch(extension) { - case 1: // Selective Acknowledgment - selack_ptr = data; - break; - case 2: // extension bits - if (data[-1] != 8) { - LOG_UTPV("0x%08x: Invalid len of extension bits header", conn); - return 0; - } - memcpy(conn->extensions, data, 8); - LOG_UTPV("0x%08x: got extension bits:%02x%02x%02x%02x%02x%02x%02x%02x", conn, - conn->extensions[0], conn->extensions[1], conn->extensions[2], conn->extensions[3], - conn->extensions[4], conn->extensions[5], conn->extensions[6], conn->extensions[7]); - } - extension = data[-2]; - data += data[-1]; - } while (extension); - } - - if (conn->state == CS_SYN_SENT) { - // if this is a syn-ack, initialize our ack_nr - // to match the sequence number we got from - // the other end - conn->ack_nr = (pk_seq_nr - 1) & SEQ_NR_MASK; - } - - g_current_ms = UTP_GetMilliseconds(); - conn->last_got_packet = g_current_ms; - - if (syn) { - return 0; - } - - // seqnr is the number of packets past the expected - // packet this is. ack_nr is the last acked, seq_nr is the - // current. Subtracring 1 makes 0 mean "this is the next - // expected packet". - const uint seqnr = (pk_seq_nr - conn->ack_nr - 1) & SEQ_NR_MASK; - - // Getting an invalid sequence number? - if (seqnr >= REORDER_BUFFER_MAX_SIZE) { - if (seqnr >= (SEQ_NR_MASK + 1) - REORDER_BUFFER_MAX_SIZE && pk_flags != ST_STATE) { - conn->ack_time = g_current_ms + min(conn->ack_time - g_current_ms, DELAYED_ACK_TIME_THRESHOLD); - } - LOG_UTPV(" Got old Packet/Ack (%u/%u)=%u!", pk_seq_nr, conn->ack_nr, seqnr); - return 0; - } - - // Process acknowledgment - // acks is the number of packets that was acked - int acks = (pk_ack_nr - (conn->seq_nr - 1 - conn->cur_window_packets)) & ACK_NR_MASK; - - // this happens when we receive an old ack nr - if (acks > conn->cur_window_packets) acks = 0; - - // if we get the same ack_nr as in the last packet - // increase the duplicate_ack counter, otherwise reset - // it to 0 - if (conn->cur_window_packets > 0) { - if (pk_ack_nr == ((conn->seq_nr - conn->cur_window_packets - 1) & ACK_NR_MASK) && - conn->cur_window_packets > 0) { - //++conn->duplicate_ack; - } else { - conn->duplicate_ack = 0; - } - - // TODO: if duplicate_ack == DUPLICATE_ACK_BEFORE_RESEND - // and fast_resend_seq_nr <= ack_nr + 1 - // resend ack_nr + 1 - } - - // figure out how many bytes were acked - size_t acked_bytes = 0; - - // the minimum rtt of all acks - // this is the upper limit on the delay we get back - // from the other peer. Our delay cannot exceed - // the rtt of the packet. If it does, clamp it. - // this is done in apply_ledbat_ccontrol() - int64 min_rtt = INT64_MAX; - - for (int i = 0; i < acks; ++i) { - int seq = conn->seq_nr - conn->cur_window_packets + i; - OutgoingPacket *pkt = (OutgoingPacket*)conn->outbuf.get(seq); - if (pkt == 0 || pkt->transmissions == 0) continue; - assert((int)(pkt->payload) >= 0); - acked_bytes += pkt->payload; - min_rtt = min(min_rtt, UTP_GetMicroseconds() - pkt->time_sent); - } - - // count bytes acked by EACK - if (selack_ptr != NULL) { - acked_bytes += conn->selective_ack_bytes((pk_ack_nr + 2) & ACK_NR_MASK, - selack_ptr, selack_ptr[-1], min_rtt); - } - - LOG_UTPV("0x%08x: acks:%d acked_bytes:%u seq_nr:%d cur_window:%u cur_window_packets:%u relative_seqnr:%u max_window:%u min_rtt:%u rtt:%u", - conn, acks, (uint)acked_bytes, conn->seq_nr, (uint)conn->cur_window, conn->cur_window_packets, - seqnr, (uint)conn->max_window, (uint)(min_rtt / 1000), conn->rtt); - - uint64 p; - - if (conn->version == 0) { - p = uint64(pf->tv_sec) * 1000000 + pf->tv_usec; - } else { - p = pf1->tv_usec; - } - - conn->last_measured_delay = g_current_ms; - - // get delay in both directions - // record the delay to report back - const uint32 their_delay = (uint32)(p == 0 ? 0 : time - p); - conn->reply_micro = their_delay; - uint32 prev_delay_base = conn->their_hist.delay_base; - if (their_delay != 0) conn->their_hist.add_sample(their_delay); - - // if their new delay base is less than their previous one - // we should shift our delay base in the other direction in order - // to take the clock skew into account - if (prev_delay_base != 0 && - wrapping_compare_less(conn->their_hist.delay_base, prev_delay_base)) { - // never adjust more than 10 milliseconds - if (prev_delay_base - conn->their_hist.delay_base <= 10000) { - conn->our_hist.shift(prev_delay_base - conn->their_hist.delay_base); - } - } - - const uint32 actual_delay = conn->version==0 - ?(pf->reply_micro==INT_MAX?0:uint32(pf->reply_micro)) - :(uint32(pf1->reply_micro)==INT_MAX?0:uint32(pf1->reply_micro)); - - // if the actual delay is 0, it means the other end - // hasn't received a sample from us yet, and doesn't - // know what it is. We can't update out history unless - // we have a true measured sample - prev_delay_base = conn->our_hist.delay_base; - if (actual_delay != 0) conn->our_hist.add_sample(actual_delay); - - // if our new delay base is less than our previous one - // we should shift the other end's delay base in the other - // direction in order to take the clock skew into account - // This is commented out because it creates bad interactions - // with our adjustment in the other direction. We don't really - // need our estimates of the other peer to be very accurate - // anyway. The problem with shifting here is that we're more - // likely shift it back later because of a low latency. This - // second shift back would cause us to shift our delay base - // which then get's into a death spiral of shifting delay bases -/* if (prev_delay_base != 0 && - wrapping_compare_less(conn->our_hist.delay_base, prev_delay_base)) { - // never adjust more than 10 milliseconds - if (prev_delay_base - conn->our_hist.delay_base <= 10000) { - conn->their_hist.Shift(prev_delay_base - conn->our_hist.delay_base); - } - } -*/ - - // if the delay estimate exceeds the RTT, adjust the base_delay to - // compensate - if (conn->our_hist.get_value() > uint32(min_rtt)) { - conn->our_hist.shift(conn->our_hist.get_value() - min_rtt); - } - - // only apply the congestion controller on acks - // if we don't have a delay measurement, there's - // no point in invoking the congestion control - if (actual_delay != 0 && acked_bytes >= 1) - conn->apply_ledbat_ccontrol(acked_bytes, actual_delay, min_rtt); - - // sanity check, the other end should never ack packets - // past the point we've sent - if (acks <= conn->cur_window_packets) { - conn->max_window_user = conn->version == 0 - ? pf->windowsize * PACKET_SIZE : pf1->windowsize; - - // If max user window is set to 0, then we startup a timer - // That will reset it to 1 after 15 seconds. - if (conn->max_window_user == 0) - // Reset max_window_user to 1 every 15 seconds. - conn->zerowindow_time = g_current_ms + 15000; - - // Respond to connect message - // Switch to CONNECTED state. - if (conn->state == CS_SYN_SENT) { - conn->state = CS_CONNECTED; - conn->func.on_state(conn->userdata, UTP_STATE_CONNECT); - - // We've sent a fin, and everything was ACKed (including the FIN), - // it's safe to destroy the socket. cur_window_packets == acks - // means that this packet acked all the remaining packets that - // were in-flight. - } else if (conn->state == CS_FIN_SENT && conn->cur_window_packets == acks) { - conn->state = CS_DESTROY; - } - - // Update fast resend counter - if (wrapping_compare_less(conn->fast_resend_seq_nr, (pk_ack_nr + 1) & ACK_NR_MASK)) - conn->fast_resend_seq_nr = pk_ack_nr + 1; - - LOG_UTPV("0x%08x: fast_resend_seq_nr:%u", conn, conn->fast_resend_seq_nr); - - for (int i = 0; i < acks; ++i) { - int ack_status = conn->ack_packet(conn->seq_nr - conn->cur_window_packets); - // if ack_status is 0, the packet was acked. - // if acl_stauts is 1, it means that the packet had already been acked - // if it's 2, the packet has not been sent yet - // We need to break this loop in the latter case. This could potentially - // happen if we get an ack_nr that does not exceed what we have stuffed - // into the outgoing buffer, but does exceed what we have sent - if (ack_status == 2) { -#ifdef _DEBUG - OutgoingPacket* pkt = (OutgoingPacket*)conn->outbuf.get(conn->seq_nr - conn->cur_window_packets); - assert(pkt->transmissions == 0); -#endif - break; - } - conn->cur_window_packets--; - } -#ifdef _DEBUG - if (conn->cur_window_packets == 0) assert(conn->cur_window == 0); -#endif - - // packets in front of this may have been acked by a - // selective ack (EACK). Keep decreasing the window packet size - // until we hit a packet that is still waiting to be acked - // in the send queue - // this is especially likely to happen when the other end - // has the EACK send bug older versions of uTP had - while (conn->cur_window_packets > 0 && !conn->outbuf.get(conn->seq_nr - conn->cur_window_packets)) - conn->cur_window_packets--; - -#ifdef _DEBUG - if (conn->cur_window_packets == 0) assert(conn->cur_window == 0); -#endif - - // this invariant should always be true - assert(conn->cur_window_packets == 0 || conn->outbuf.get(conn->seq_nr - conn->cur_window_packets)); - - // flush Nagle - if (conn->cur_window_packets == 1) { - OutgoingPacket *pkt = (OutgoingPacket*)conn->outbuf.get(conn->seq_nr - 1); - // do we still have quota? - if (pkt->transmissions == 0 && - (!(USE_PACKET_PACING) || conn->send_quota / 100 >= (int32)pkt->length)) { - conn->send_packet(pkt); - - // No need to send another ack if there is nothing to reorder. - if (conn->reorder_count == 0) { - conn->sent_ack(); - } - } - } - - // Fast timeout-retry - if (conn->fast_timeout) { - LOG_UTPV("Fast timeout %u,%u,%u?", (uint)conn->cur_window, conn->seq_nr - conn->timeout_seq_nr, conn->timeout_seq_nr); - // if the fast_resend_seq_nr is not pointing to the oldest outstanding packet, it suggests that we've already - // resent the packet that timed out, and we should leave the fast-timeout mode. - if (((conn->seq_nr - conn->cur_window_packets) & ACK_NR_MASK) != conn->fast_resend_seq_nr) { - conn->fast_timeout = false; - } else { - // resend the oldest packet and increment fast_resend_seq_nr - // to not allow another fast resend on it again - OutgoingPacket *pkt = (OutgoingPacket*)conn->outbuf.get(conn->seq_nr - conn->cur_window_packets); - if (pkt && pkt->transmissions > 0) { - LOG_UTPV("0x%08x: Packet %u fast timeout-retry.", conn, conn->seq_nr - conn->cur_window_packets); -#ifdef _DEBUG - ++conn->_stats._fastrexmit; -#endif - conn->fast_resend_seq_nr++; - conn->send_packet(pkt); - } - } - } - } - - // Process selective acknowledgent - if (selack_ptr != NULL) { - conn->selective_ack(pk_ack_nr + 2, selack_ptr, selack_ptr[-1]); - } - - // this invariant should always be true - assert(conn->cur_window_packets == 0 || conn->outbuf.get(conn->seq_nr - conn->cur_window_packets)); - - LOG_UTPV("0x%08x: acks:%d acked_bytes:%u seq_nr:%u cur_window:%u cur_window_packets:%u quota:%d", - conn, acks, (uint)acked_bytes, conn->seq_nr, (uint)conn->cur_window, conn->cur_window_packets, - conn->send_quota / 100); - - // In case the ack dropped the current window below - // the max_window size, Mark the socket as writable - if (conn->state == CS_CONNECTED_FULL && conn->is_writable(conn->get_packet_size())) { - conn->state = CS_CONNECTED; - LOG_UTPV("0x%08x: Socket writable. max_window:%u cur_window:%u quota:%d packet_size:%u", - conn, (uint)conn->max_window, (uint)conn->cur_window, conn->send_quota / 100, (uint)conn->get_packet_size()); - conn->func.on_state(conn->userdata, UTP_STATE_WRITABLE); - } - - if (pk_flags == ST_STATE) { - // This is a state packet only. - return 0; - } - - // The connection is not in a state that can accept data? - if (conn->state != CS_CONNECTED && - conn->state != CS_CONNECTED_FULL && - conn->state != CS_FIN_SENT) { - return 0; - } - - // Is this a finalize packet? - if (pk_flags == ST_FIN && !conn->got_fin) { - LOG_UTPV("Got FIN eof_pkt:%u", pk_seq_nr); - conn->got_fin = true; - conn->eof_pkt = pk_seq_nr; - // at this point, it is possible for the - // other end to have sent packets with - // sequence numbers higher than seq_nr. - // if this is the case, our reorder_count - // is out of sync. This case is dealt with - // when we re-order and hit the eof_pkt. - // we'll just ignore any packets with - // sequence numbers past this - } - - // Getting an in-order packet? - if (seqnr == 0) { - size_t count = packet_end - data; - if (count > 0 && conn->state != CS_FIN_SENT) { - LOG_UTPV("0x%08x: Got Data len:%u (rb:%u)", conn, (uint)count, (uint)conn->func.get_rb_size(conn->userdata)); - // Post bytes to the upper layer - conn->func.on_read(conn->userdata, data, count); - } - conn->ack_nr++; - conn->bytes_since_ack += count; - - // Check if the next packet has been received too, but waiting - // in the reorder buffer. - for (;;) { - - if (conn->got_fin && conn->eof_pkt == conn->ack_nr) { - if (conn->state != CS_FIN_SENT) { - conn->state = CS_GOT_FIN; - conn->rto_timeout = g_current_ms + min(conn->rto * 3, 60); - - LOG_UTPV("0x%08x: Posting EOF", conn); - conn->func.on_state(conn->userdata, UTP_STATE_EOF); - } - - // if the other end wants to close, ack immediately - conn->send_ack(); - - // reorder_count is not necessarily 0 at this point. - // even though it is most of the time, the other end - // may have sent packets with higher sequence numbers - // than what later end up being eof_pkt - // since we have received all packets up to eof_pkt - // just ignore the ones after it. - conn->reorder_count = 0; - } - - // Quick get-out in case there is nothing to reorder - if (conn->reorder_count == 0) - break; - - // Check if there are additional buffers in the reorder buffers - // that need delivery. - byte *p = (byte*)conn->inbuf.get(conn->ack_nr+1); - if (p == NULL) - break; - conn->inbuf.put(conn->ack_nr+1, NULL); - count = *(uint*)p; - if (count > 0 && conn->state != CS_FIN_SENT) { - // Pass the bytes to the upper layer - conn->func.on_read(conn->userdata, p + sizeof(uint), count); - } - conn->ack_nr++; - conn->bytes_since_ack += count; - - // Free the element from the reorder buffer - free(p); - assert(conn->reorder_count > 0); - conn->reorder_count--; - } - - // start the delayed ACK timer - conn->ack_time = g_current_ms + min(conn->ack_time - g_current_ms, DELAYED_ACK_TIME_THRESHOLD); - } else { - // Getting an out of order packet. - // The packet needs to be remembered and rearranged later. - - // if we have received a FIN packet, and the EOF-sequence number - // is lower than the sequence number of the packet we just received - // something is wrong. - if (conn->got_fin && pk_seq_nr > conn->eof_pkt) { - LOG_UTPV("0x%08x: Got an invalid packet sequence number, past EOF " - "reorder_count:%u len:%u (rb:%u)", - conn, conn->reorder_count, (uint)(packet_end - data), (uint)conn->func.get_rb_size(conn->userdata)); - return 0; - } - - // if the sequence number is entirely off the expected - // one, just drop it. We can't allocate buffer space in - // the inbuf entirely based on untrusted input - if (seqnr > 0x3ff) { - LOG_UTPV("0x%08x: Got an invalid packet sequence number, too far off " - "reorder_count:%u len:%u (rb:%u)", - conn, conn->reorder_count, (uint)(packet_end - data), (uint)conn->func.get_rb_size(conn->userdata)); - return 0; - } - - // we need to grow the circle buffer before we - // check if the packet is already in here, so that - // we don't end up looking at an older packet (since - // the indices wraps around). - conn->inbuf.ensure_size(pk_seq_nr + 1, seqnr + 1); - - // Has this packet already been received? (i.e. a duplicate) - // If that is the case, just discard it. - if (conn->inbuf.get(pk_seq_nr) != NULL) { -#ifdef _DEBUG - ++conn->_stats._nduprecv; -#endif - return 0; - } - - // Allocate memory to fit the packet that needs to re-ordered - byte *mem = (byte*)malloc((packet_end - data) + sizeof(uint)); - *(uint*)mem = (uint)(packet_end - data); - memcpy(mem + sizeof(uint), data, packet_end - data); - - // Insert into reorder buffer and increment the count - // of # of packets to be reordered. - // we add one to seqnr in order to leave the last - // entry empty, that way the assert in send_ack - // is valid. we have to add one to seqnr too, in order - // to make the circular buffer grow around the correct - // point (which is conn->ack_nr + 1). - assert(conn->inbuf.get(pk_seq_nr) == NULL); - assert((pk_seq_nr & conn->inbuf.mask) != ((conn->ack_nr+1) & conn->inbuf.mask)); - conn->inbuf.put(pk_seq_nr, mem); - conn->reorder_count++; - - LOG_UTPV("0x%08x: Got out of order data reorder_count:%u len:%u (rb:%u)", - conn, conn->reorder_count, (uint)(packet_end - data), (uint)conn->func.get_rb_size(conn->userdata)); - - // Setup so the partial ACK message will get sent immediately. - conn->ack_time = g_current_ms + min(conn->ack_time - g_current_ms, 1); - } - - // If ack_time or ack_bytes indicate that we need to send and ack, send one - // here instead of waiting for the timer to trigger - LOG_UTPV("bytes_since_ack:%u ack_time:%d", - (uint)conn->bytes_since_ack, (int)(g_current_ms - conn->ack_time)); - if (conn->state == CS_CONNECTED || conn->state == CS_CONNECTED_FULL) { - if (conn->bytes_since_ack > DELAYED_ACK_BYTE_THRESHOLD || - (int)(g_current_ms - conn->ack_time) >= 0) { - conn->send_ack(); - } - } - return (size_t)(packet_end - data); -} - -inline bool UTP_IsV1(PacketFormatV1 const* pf) -{ - return pf->version() == 1 && pf->type() < ST_NUM_STATES && pf->ext < 3; -} - -void UTP_Free(UTPSocket *conn) -{ - LOG_UTPV("0x%08x: Killing socket", conn); - - conn->func.on_state(conn->userdata, UTP_STATE_DESTROYING); - UTP_SetCallbacks(conn, NULL, NULL); - - assert(conn->idx < g_utp_sockets.GetCount()); - assert(g_utp_sockets[conn->idx] == conn); - - // Unlink object from the global list - assert(g_utp_sockets.GetCount() > 0); - - UTPSocket *last = g_utp_sockets[g_utp_sockets.GetCount() - 1]; - - assert(last->idx < g_utp_sockets.GetCount()); - assert(g_utp_sockets[last->idx] == last); - - last->idx = conn->idx; - - g_utp_sockets[conn->idx] = last; - - // Decrease the count - g_utp_sockets.SetCount(g_utp_sockets.GetCount() - 1); - - // Free all memory occupied by the socket object. - for (size_t i = 0; i <= conn->inbuf.mask; i++) { - free(conn->inbuf.elements[i]); - } - for (size_t i = 0; i <= conn->outbuf.mask; i++) { - free(conn->outbuf.elements[i]); - } - free(conn->inbuf.elements); - free(conn->outbuf.elements); - - // Finally free the socket object - free(conn); -} - - -// Public functions: -/////////////////////////////////////////////////////////////////////////////// - -// Create a UTP socket -UTPSocket *UTP_Create(SendToProc *send_to_proc, void *send_to_userdata, const struct sockaddr *addr, socklen_t addrlen) -{ - UTPSocket *conn = (UTPSocket*)calloc(1, sizeof(UTPSocket)); - - g_current_ms = UTP_GetMilliseconds(); - - UTP_SetCallbacks(conn, NULL, NULL); - conn->our_hist.clear(); - conn->their_hist.clear(); - conn->rto = 3000; - conn->rtt_var = 800; - conn->seq_nr = 1; - conn->ack_nr = 0; - conn->max_window_user = 255 * PACKET_SIZE; - conn->addr = PackedSockAddr((const SOCKADDR_STORAGE*)addr, addrlen); - conn->send_to_proc = send_to_proc; - conn->send_to_userdata = send_to_userdata; - conn->ack_time = g_current_ms + 0x70000000; - conn->last_got_packet = g_current_ms; - conn->last_sent_packet = g_current_ms; - conn->last_measured_delay = g_current_ms + 0x70000000; - conn->last_rwin_decay = int32(g_current_ms) - MAX_WINDOW_DECAY; - conn->last_send_quota = g_current_ms; - conn->send_quota = PACKET_SIZE * 100; - conn->cur_window_packets = 0; - conn->fast_resend_seq_nr = conn->seq_nr; - - // default to version 1 - UTP_SetSockopt(conn, SO_UTPVERSION, 1); - - // we need to fit one packet in the window - // when we start the connection - conn->max_window = conn->get_packet_size(); - conn->state = CS_IDLE; - - conn->outbuf.mask = 15; - conn->inbuf.mask = 15; - - conn->outbuf.elements = (void**)calloc(16, sizeof(void*)); - conn->inbuf.elements = (void**)calloc(16, sizeof(void*)); - - conn->idx = g_utp_sockets.Append(conn); - - LOG_UTPV("0x%08x: UTP_Create", conn); - - return conn; -} - -void UTP_SetCallbacks(UTPSocket *conn, UTPFunctionTable *funcs, void *userdata) -{ - assert(conn); - - if (funcs == NULL) { - funcs = &zero_funcs; - } - conn->func = *funcs; - conn->userdata = userdata; -} - -bool UTP_SetSockopt(UTPSocket* conn, int opt, int val) -{ - assert(conn); - - switch (opt) { - case SO_SNDBUF: - assert(val >= 1); - conn->opt_sndbuf = val; - return true; - case SO_RCVBUF: - conn->opt_rcvbuf = val; - return true; - case SO_UTPVERSION: - assert(conn->state == CS_IDLE); - if (conn->state != CS_IDLE) { - // too late - return false; - } - if (conn->version == 1 && val == 0) { - conn->reply_micro = INT_MAX; - conn->opt_rcvbuf = 200 * 1024; - conn->opt_sndbuf = OUTGOING_BUFFER_MAX_SIZE * PACKET_SIZE; - } else if (conn->version == 0 && val == 1) { - conn->reply_micro = 0; - conn->opt_rcvbuf = 3 * 1024 * 1024 + 512 * 1024; - conn->opt_sndbuf = conn->opt_rcvbuf; - } - conn->version = val; - return true; - } - - return false; -} - -// Try to connect to a specified host. -// 'initial' is the number of data bytes to send in the connect packet. -void UTP_Connect(UTPSocket *conn) -{ - assert(conn); - - assert(conn->state == CS_IDLE); - assert(conn->cur_window_packets == 0); - assert(conn->outbuf.get(conn->seq_nr) == NULL); - assert(sizeof(PacketFormatV1) == 20); - - conn->state = CS_SYN_SENT; - - g_current_ms = UTP_GetMilliseconds(); - - // Create and send a connect message - uint32 conn_seed = UTP_Random(); - - // we identify newer versions by setting the - // first two bytes to 0x0001 - if (conn->version > 0) { - conn_seed &= 0xffff; - } - - // used in parse_log.py - LOG_UTP("0x%08x: UTP_Connect conn_seed:%u packet_size:%u (B) " - "target_delay:%u (ms) delay_history:%u " - "delay_base_history:%u (minutes)", - conn, conn_seed, PACKET_SIZE, CCONTROL_TARGET / 1000, - CUR_DELAY_SIZE, DELAY_BASE_HISTORY); - - // Setup initial timeout timer. - conn->retransmit_timeout = 3000; - conn->rto_timeout = g_current_ms + conn->retransmit_timeout; - conn->last_rcv_win = conn->get_rcv_window(); - - conn->conn_seed = conn_seed; - conn->conn_id_recv = conn_seed; - conn->conn_id_send = conn_seed+1; - // if you need compatibiltiy with 1.8.1, use this. it increases attackability though. - //conn->seq_nr = 1; - conn->seq_nr = UTP_Random(); - - // Create the connect packet. - const size_t header_ext_size = conn->get_header_extensions_size(); - - OutgoingPacket *pkt = (OutgoingPacket*)malloc(sizeof(OutgoingPacket) - 1 + header_ext_size); - - PacketFormatExtensions* p = (PacketFormatExtensions*)pkt->data; - PacketFormatExtensionsV1* p1 = (PacketFormatExtensionsV1*)pkt->data; - - memset(p, 0, header_ext_size); - // SYN packets are special, and have the receive ID in the connid field, - // instead of conn_id_send. - if (conn->version == 0) { - p->pf.connid = conn->conn_id_recv; - p->pf.ext = 2; - p->pf.windowsize = (byte)DIV_ROUND_UP(conn->last_rcv_win, PACKET_SIZE); - p->pf.seq_nr = conn->seq_nr; - p->pf.flags = ST_SYN; - p->ext_next = 0; - p->ext_len = 8; - memset(p->extensions, 0, 8); - } else { - p1->pf.set_version(1); - p1->pf.set_type(ST_SYN); - p1->pf.ext = 2; - p1->pf.connid = conn->conn_id_recv; - p1->pf.windowsize = (uint32)conn->last_rcv_win; - p1->pf.seq_nr = conn->seq_nr; - p1->ext_next = 0; - p1->ext_len = 8; - memset(p1->extensions, 0, 8); - } - pkt->transmissions = 0; - pkt->length = header_ext_size; - pkt->payload = 0; - - //LOG_UTPV("0x%08x: Sending connect %s [%u].", - // conn, addrfmt(conn->addr, addrbuf), conn_seed); - - // Remember the message in the outgoing queue. - conn->outbuf.ensure_size(conn->seq_nr, conn->cur_window_packets); - conn->outbuf.put(conn->seq_nr, pkt); - conn->seq_nr++; - conn->cur_window_packets++; - - conn->send_packet(pkt); -} - -bool UTP_IsIncomingUTP(UTPGotIncomingConnection *incoming_proc, - SendToProc *send_to_proc, void *send_to_userdata, - const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen) -{ - const PackedSockAddr addr((const SOCKADDR_STORAGE*)to, tolen); - - if (len < sizeof(PacketFormat) && len < sizeof(PacketFormatV1)) { - LOG_UTPV("recv %s len:%u too small", addrfmt(addr, addrbuf), (uint)len); - return false; - } - - const PacketFormat* p = (PacketFormat*)buffer; - const PacketFormatV1* p1 = (PacketFormatV1*)buffer; - - const byte version = UTP_IsV1(p1); - const uint32 id = (version == 0) ? p->connid : uint32(p1->connid); - - if (version == 0 && len < sizeof(PacketFormat)) { - LOG_UTPV("recv %s len:%u version:%u too small", addrfmt(addr, addrbuf), (uint)len, version); - return false; - } - - if (version == 1 && len < sizeof(PacketFormatV1)) { - LOG_UTPV("recv %s len:%u version:%u too small", addrfmt(addr, addrbuf), (uint)len, version); - return false; - } - - LOG_UTPV("recv %s len:%u id:%u", addrfmt(addr, addrbuf), (uint)len, id); - - const PacketFormat *pf = (PacketFormat*)p; - const PacketFormatV1 *pf1 = (PacketFormatV1*)p; - - if (version == 0) { - LOG_UTPV("recv id:%u seq_nr:%u ack_nr:%u", id, (uint)pf->seq_nr, (uint)pf->ack_nr); - } else { - LOG_UTPV("recv id:%u seq_nr:%u ack_nr:%u", id, (uint)pf1->seq_nr, (uint)pf1->ack_nr); - } - - const byte flags = version == 0 ? pf->flags : pf1->type(); - - for (size_t i = 0; i < g_utp_sockets.GetCount(); i++) { - UTPSocket *conn = g_utp_sockets[i]; - //LOG_UTPV("Examining UTPSocket %s for %s and (seed:%u s:%u r:%u) for %u", - // addrfmt(conn->addr, addrbuf), addrfmt(addr, addrbuf2), conn->conn_seed, conn->conn_id_send, conn->conn_id_recv, id); - if (conn->addr != addr) - continue; - - if (flags == ST_RESET && (conn->conn_id_send == id || conn->conn_id_recv == id)) { - LOG_UTPV("0x%08x: recv RST for existing connection", conn); - if (!conn->userdata || conn->state == CS_FIN_SENT) { - conn->state = CS_DESTROY; - } else { - conn->state = CS_RESET; - } - if (conn->userdata) { - conn->func.on_overhead(conn->userdata, false, len + conn->get_udp_overhead(), - close_overhead); - const int err = conn->state == CS_SYN_SENT ? - ECONNREFUSED : - ECONNRESET; - conn->func.on_error(conn->userdata, err); - } - return true; - } else if (flags != ST_SYN && conn->conn_id_recv == id) { - LOG_UTPV("0x%08x: recv processing", conn); - const size_t read = UTP_ProcessIncoming(conn, buffer, len); - if (conn->userdata) { - conn->func.on_overhead(conn->userdata, false, - (len - read) + conn->get_udp_overhead(), - header_overhead); - } - return true; - } - } - - if (flags == ST_RESET) { - LOG_UTPV("recv RST for unknown connection"); - return true; - } - - const uint32 seq_nr = version == 0 ? pf->seq_nr : pf1->seq_nr; - if (flags != ST_SYN) { - for (size_t i = 0; i < g_rst_info.GetCount(); i++) { - if (g_rst_info[i].connid != id) - continue; - if (g_rst_info[i].addr != addr) - continue; - if (seq_nr != g_rst_info[i].ack_nr) - continue; - g_rst_info[i].timestamp = UTP_GetMilliseconds(); - LOG_UTPV("recv not sending RST to non-SYN (stored)"); - return true; - } - if (g_rst_info.GetCount() > RST_INFO_LIMIT) { - LOG_UTPV("recv not sending RST to non-SYN (limit at %u stored)", (uint)g_rst_info.GetCount()); - return true; - } - LOG_UTPV("recv send RST to non-SYN (%u stored)", (uint)g_rst_info.GetCount()); - RST_Info &r = g_rst_info.Append(); - r.addr = addr; - r.connid = id; - r.ack_nr = seq_nr; - r.timestamp = UTP_GetMilliseconds(); - - UTPSocket::send_rst(send_to_proc, send_to_userdata, addr, id, seq_nr, UTP_Random(), version); - return true; - } - - if (incoming_proc) { - LOG_UTPV("Incoming connection from %s uTP version:%u", addrfmt(addr, addrbuf), version); - - // Create a new UTP socket to handle this new connection - UTPSocket *conn = UTP_Create(send_to_proc, send_to_userdata, to, tolen); - // Need to track this value to be able to detect duplicate CONNECTs - conn->conn_seed = id; - // This is value that identifies this connection for them. - conn->conn_id_send = id; - // This is value that identifies this connection for us. - conn->conn_id_recv = id+1; - conn->ack_nr = seq_nr; - conn->seq_nr = UTP_Random(); - conn->fast_resend_seq_nr = conn->seq_nr; - - UTP_SetSockopt(conn, SO_UTPVERSION, version); - conn->state = CS_CONNECTED; - - const size_t read = UTP_ProcessIncoming(conn, buffer, len, true); - - LOG_UTPV("0x%08x: recv send connect ACK", conn); - conn->send_ack(true); - - incoming_proc(send_to_userdata, conn); - - // we report overhead after incoming_proc, because the callbacks are setup now - if (conn->userdata) { - // SYN - conn->func.on_overhead(conn->userdata, false, (len - read) + conn->get_udp_overhead(), - header_overhead); - // SYNACK - conn->func.on_overhead(conn->userdata, true, conn->get_overhead(), - ack_overhead); - } - } - - return true; -} - -bool UTP_HandleICMP(const byte* buffer, size_t len, const struct sockaddr *to, socklen_t tolen) -{ - const PackedSockAddr addr((const SOCKADDR_STORAGE*)to, tolen); - - // Want the whole packet so we have connection ID - if (len < sizeof(PacketFormat)) { - return false; - } - - const PacketFormat* p = (PacketFormat*)buffer; - const PacketFormatV1* p1 = (PacketFormatV1*)buffer; - - const byte version = UTP_IsV1(p1); - const uint32 id = (version == 0) ? p->connid : uint32(p1->connid); - - for (size_t i = 0; i < g_utp_sockets.GetCount(); ++i) { - UTPSocket *conn = g_utp_sockets[i]; - if (conn->addr == addr && - conn->conn_id_recv == id) { - // Don't pass on errors for idle/closed connections - if (conn->state != CS_IDLE) { - if (!conn->userdata || conn->state == CS_FIN_SENT) { - LOG_UTPV("0x%08x: icmp packet causing socket destruction", conn); - conn->state = CS_DESTROY; - } else { - conn->state = CS_RESET; - } - if (conn->userdata) { - const int err = conn->state == CS_SYN_SENT ? - ECONNREFUSED : - ECONNRESET; - LOG_UTPV("0x%08x: icmp packet causing error on socket:%d", conn, err); - conn->func.on_error(conn->userdata, err); - } - } - return true; - } - } - return false; -} - -// Write bytes to the UTP socket. -// Returns true if the socket is still writable. -bool UTP_Write(UTPSocket *conn, size_t bytes) -{ - assert(conn); - -#ifdef g_log_utp_verbose - size_t param = bytes; -#endif - - if (conn->state != CS_CONNECTED) { - LOG_UTPV("0x%08x: UTP_Write %u bytes = false (not CS_CONNECTED)", conn, (uint)bytes); - return false; - } - - g_current_ms = UTP_GetMilliseconds(); - - conn->update_send_quota(); - - // don't send unless it will all fit in the window - size_t packet_size = conn->get_packet_size(); - size_t num_to_send = min(bytes, packet_size); - while (conn->is_writable(num_to_send)) { - // Send an outgoing packet. - // Also add it to the outgoing of packets that have been sent but not ACKed. - - if (num_to_send == 0) { - LOG_UTPV("0x%08x: UTP_Write %u bytes = true", conn, (uint)param); - return true; - } - bytes -= num_to_send; - - LOG_UTPV("0x%08x: Sending packet. seq_nr:%u ack_nr:%u wnd:%u/%u/%u rcv_win:%u size:%u quota:%d cur_window_packets:%u", - conn, conn->seq_nr, conn->ack_nr, - (uint)(conn->cur_window + num_to_send), - (uint)conn->max_window, (uint)conn->max_window_user, - (uint)conn->last_rcv_win, num_to_send, conn->send_quota / 100, - conn->cur_window_packets); - conn->write_outgoing_packet(num_to_send, ST_DATA); - num_to_send = min(bytes, packet_size); - } - - // mark the socket as not being writable. - conn->state = CS_CONNECTED_FULL; - LOG_UTPV("0x%08x: UTP_Write %u bytes = false", conn, (uint)bytes); - return false; -} - -void UTP_RBDrained(UTPSocket *conn) -{ - assert(conn); - - const size_t rcvwin = conn->get_rcv_window(); - - if (rcvwin > conn->last_rcv_win) { - // If last window was 0 send ACK immediately, otherwise should set timer - if (conn->last_rcv_win == 0) { - conn->send_ack(); - } else { - conn->ack_time = g_current_ms + min(conn->ack_time - g_current_ms, DELAYED_ACK_TIME_THRESHOLD); - } - } -} - -void UTP_CheckTimeouts() -{ - g_current_ms = UTP_GetMilliseconds(); - - for (size_t i = 0; i < g_rst_info.GetCount(); i++) { - if ((int)(g_current_ms - g_rst_info[i].timestamp) >= RST_INFO_TIMEOUT) { - g_rst_info.MoveUpLast(i); - i--; - } - } - if (g_rst_info.GetCount() != g_rst_info.GetAlloc()) { - g_rst_info.Compact(); - } - - for (size_t i = 0; i != g_utp_sockets.GetCount(); i++) { - UTPSocket *conn = g_utp_sockets[i]; - conn->check_timeouts(); - - // Check if the object was deleted - if (conn->state == CS_DESTROY) { - LOG_UTPV("0x%08x: Destroying", conn); - UTP_Free(conn); - i--; - } - } -} - -size_t UTP_GetPacketSize(UTPSocket *socket) -{ - return socket->get_packet_size(); -} - -void UTP_GetPeerName(UTPSocket *conn, struct sockaddr *addr, socklen_t *addrlen) -{ - assert(conn); - - socklen_t len; - const SOCKADDR_STORAGE sa = conn->addr.get_sockaddr_storage(&len); - *addrlen = min(len, *addrlen); - memcpy(addr, &sa, *addrlen); -} - -void UTP_GetDelays(UTPSocket *conn, int32 *ours, int32 *theirs, uint32 *age) -{ - assert(conn); - - if (ours) *ours = conn->our_hist.get_value(); - if (theirs) *theirs = conn->their_hist.get_value(); - if (age) *age = g_current_ms - conn->last_measured_delay; -} - -#ifdef _DEBUG -void UTP_GetStats(UTPSocket *conn, UTPStats *stats) -{ - assert(conn); - - *stats = conn->_stats; -} -#endif // _DEBUG - -void UTP_GetGlobalStats(UTPGlobalStats *stats) -{ - *stats = _global_stats; -} - -// Close the UTP socket. -// It is not valid for the upper layer to refer to socket after it is closed. -// Data will keep to try being delivered after the close. -void UTP_Close(UTPSocket *conn) -{ - assert(conn); - - assert(conn->state != CS_DESTROY_DELAY && conn->state != CS_FIN_SENT && conn->state != CS_DESTROY); - - LOG_UTPV("0x%08x: UTP_Close in state:%s", conn, statenames[conn->state]); - - switch(conn->state) { - case CS_CONNECTED: - case CS_CONNECTED_FULL: - conn->state = CS_FIN_SENT; - conn->write_outgoing_packet(0, ST_FIN); - break; - - case CS_SYN_SENT: - conn->rto_timeout = UTP_GetMilliseconds() + min(conn->rto * 2, 60); - case CS_GOT_FIN: - conn->state = CS_DESTROY_DELAY; - break; - - default: - conn->state = CS_DESTROY; - break; - } -} diff --git a/third-party/libutp/utp.h b/third-party/libutp/utp.h deleted file mode 100644 index 0086d4c01..000000000 --- a/third-party/libutp/utp.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef __UTP_H__ -#define __UTP_H__ - -#include "utypes.h" - -#ifdef WIN32 -#define _CRT_SECURE_NO_DEPRECATE -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#pragma comment(lib,"ws2_32.lib") -#else -#include -#include -#include -#include -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct UTPSocket; - -// Used to set sockopt on a uTP socket to set the version of uTP -// to use for outgoing connections. This can only be called before -// the uTP socket is connected -#define SO_UTPVERSION 99 - -enum { - // socket has reveived syn-ack (notification only for outgoing connection completion) - // this implies writability - UTP_STATE_CONNECT = 1, - - // socket is able to send more data - UTP_STATE_WRITABLE = 2, - - // connection closed - UTP_STATE_EOF = 3, - - // socket is being destroyed, meaning all data has been sent if possible. - // it is not valid to refer to the socket after this state change occurs - UTP_STATE_DESTROYING = 4, -}; - -// Callbacks called by a uTP socket (register with UTP_SetCallbacks) - -// The uTP socket layer calls this when bytes have been received from the network. -typedef void UTPOnReadProc(void *userdata, const byte *bytes, size_t count); - -// The uTP socket layer calls this to fill the outgoing buffer with bytes. -// The uTP layer takes responsibility that those bytes will be delivered. -typedef void UTPOnWriteProc(void *userdata, byte *bytes, size_t count); - -// The uTP socket layer calls this to retrieve number of bytes currently in read buffer -typedef size_t UTPGetRBSize(void *userdata); - -// The uTP socket layer calls this whenever the socket becomes writable. -typedef void UTPOnStateChangeProc(void *userdata, int state); - -// The uTP socket layer calls this when an error occurs on the socket. -// These errors currently include ECONNREFUSED, ECONNRESET and ETIMEDOUT, but -// could eventually include any BSD socket error. -typedef void UTPOnErrorProc(void *userdata, int errcode); - -// The uTP socket layer calls this to report overhead statistics -typedef void UTPOnOverheadProc(void *userdata, bool send, size_t count, int type); - -struct UTPFunctionTable { - UTPOnReadProc *on_read; - UTPOnWriteProc *on_write; - UTPGetRBSize *get_rb_size; - UTPOnStateChangeProc *on_state; - UTPOnErrorProc *on_error; - UTPOnOverheadProc *on_overhead; -}; - - -// The uTP socket layer calls this when a new incoming uTP connection is established -// this implies writability -typedef void UTPGotIncomingConnection(void *userdata, struct UTPSocket* s); - -// The uTP socket layer calls this to send UDP packets -typedef void SendToProc(void *userdata, const byte *p, size_t len, const struct sockaddr *to, socklen_t tolen); - - -// Functions which can be called with a uTP socket - -// Create a uTP socket -struct UTPSocket *UTP_Create(SendToProc *send_to_proc, void *send_to_userdata, - const struct sockaddr *addr, socklen_t addrlen); - -// Setup the callbacks - must be done before connect or on incoming connection -void UTP_SetCallbacks(struct UTPSocket *socket, struct UTPFunctionTable *func, void *userdata); - -// Valid options include SO_SNDBUF, SO_RCVBUF and SO_UTPVERSION -bool UTP_SetSockopt(struct UTPSocket *socket, int opt, int val); - -// Try to connect to a specified host. -void UTP_Connect(struct UTPSocket *socket); - -// Process a UDP packet from the network. This will process a packet for an existing connection, -// or create a new connection and call incoming_proc. Returns true if the packet was processed -// in some way, false if the packet did not appear to be uTP. -bool UTP_IsIncomingUTP(UTPGotIncomingConnection *incoming_proc, - SendToProc *send_to_proc, void *send_to_userdata, - const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen); - -// Process an ICMP received UDP packet. -bool UTP_HandleICMP(const byte* buffer, size_t len, const struct sockaddr *to, socklen_t tolen); - -// Write bytes to the uTP socket. -// Returns true if the socket is still writable. -bool UTP_Write(struct UTPSocket *socket, size_t count); - -// Notify the uTP socket of buffer drain -void UTP_RBDrained(struct UTPSocket *socket); - -// Call periodically to process timeouts and other periodic events -void UTP_CheckTimeouts(void); - -// Retrieves the peer address of the specified socket, stores this address in the -// sockaddr structure pointed to by the addr argument, and stores the length of this -// address in the object pointed to by the addrlen argument. -void UTP_GetPeerName(struct UTPSocket *socket, struct sockaddr *addr, socklen_t *addrlen); - -void UTP_GetDelays(struct UTPSocket *socket, int32 *ours, int32 *theirs, uint32 *age); - -size_t UTP_GetPacketSize(struct UTPSocket *socket); - -#ifdef _DEBUG -struct UTPStats { - uint64 _nbytes_recv; // total bytes received - uint64 _nbytes_xmit; // total bytes transmitted - uint32 _rexmit; // retransmit counter - uint32 _fastrexmit; // fast retransmit counter - uint32 _nxmit; // transmit counter - uint32 _nrecv; // receive counter (total) - uint32 _nduprecv; // duplicate receive counter -}; - -// Get stats for UTP socket -void UTP_GetStats(struct UTPSocket *socket, UTPStats *stats); -#endif - -// Close the UTP socket. -// It is not valid to issue commands for this socket after it is closed. -// This does not actually destroy the socket until outstanding data is sent, at which -// point the socket will change to the UTP_STATE_DESTROYING state. -void UTP_Close(struct UTPSocket *socket); - -struct UTPGlobalStats { - uint32 _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU bytes fpr all connections (global) - uint32 _nraw_send[5]; // total packets sent less than 300/600/1200/MTU bytes for all connections (global) -}; - -void UTP_GetGlobalStats(struct UTPGlobalStats *stats); - -#ifdef __cplusplus -} -#endif - -#endif //__UTP_H__ diff --git a/third-party/libutp/utp_config.h b/third-party/libutp/utp_config.h deleted file mode 100644 index 7ee870ad4..000000000 --- a/third-party/libutp/utp_config.h +++ /dev/null @@ -1,39 +0,0 @@ -#define CCONTROL_TARGET (100 * 1000) // us -#define RATE_CHECK_INTERVAL 10000 // ms -#define DYNAMIC_PACKET_SIZE_ENABLED false -#define DYNAMIC_PACKET_SIZE_FACTOR 2 -// This should return the global number of bytes sent, used for determining dynamic -// packet size based on rate - -#warning implement this in libtransmission -uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen) { return 0; } - -enum bandwidth_type_t { - payload_bandwidth, connect_overhead, - close_overhead, ack_overhead, - header_overhead, retransmit_overhead -}; - -#ifdef WIN32 -#define I64u "%I64u" -#else -#define I64u "%Lu" -#endif -#ifdef WIN32 -#define snprintf _snprintf -#endif - -#define g_log_utp 0 -#define g_log_utp_verbose 0 -void utp_log(char const* fmt, ...) -{ - /* - printf("[%u] ", UTP_GetMilliseconds()); - va_list vl; - va_start(vl, fmt); - vprintf(fmt, vl); - va_end(vl); - puts(""); - fflush(stdout); - */ -}; diff --git a/third-party/libutp/utp_config_example.h b/third-party/libutp/utp_config_example.h deleted file mode 100644 index ea5b5c6f0..000000000 --- a/third-party/libutp/utp_config_example.h +++ /dev/null @@ -1,26 +0,0 @@ -#define CCONTROL_TARGET (100 * 1000) // us -#define RATE_CHECK_INTERVAL 10000 // ms -#define DYNAMIC_PACKET_SIZE_ENABLED false -#define DYNAMIC_PACKET_SIZE_FACTOR 2 -// This should return the global number of bytes sent, used for determining dynamic -// packet size based on rate -uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen) { return 0; } - -enum bandwidth_type_t { - payload_bandwidth, connect_overhead, - close_overhead, ack_overhead, - header_overhead, retransmit_overhead -}; - -#ifdef WIN32 -#define I64u "%I64u" -#else -#define I64u "%Lu" -#endif -#ifdef WIN32 -#define snprintf _snprintf -#endif - -#define g_log_utp 0 -#define g_log_utp_verbose 0 -void utp_log(char const* fmt, ...); diff --git a/third-party/libutp/utp_utils.cpp b/third-party/libutp/utp_utils.cpp deleted file mode 100644 index 5515e62a1..000000000 --- a/third-party/libutp/utp_utils.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "StdAfx.h" - -#include "utypes.h" -#include -#include - -#ifdef WIN32 - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -typedef ULONGLONG (WINAPI GetTickCount64Proc)(void); -static GetTickCount64Proc *pt2GetTickCount64; -static GetTickCount64Proc *pt2RealGetTickCount; - -static uint64 startPerformanceCounter; -static uint64 startGetTickCount; -// MSVC 6 standard doesn't like division with uint64s -static double counterPerMicrosecond; - -uint64 UTGetTickCount64() -{ - if (pt2GetTickCount64) { - return pt2GetTickCount64(); - } - if (pt2RealGetTickCount) { - uint64 v = pt2RealGetTickCount(); - // fix return value from GetTickCount - return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000); - } - return (uint64)GetTickCount(); -} - -void Time_Initialize() -{ - HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); - pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64"); - // not a typo. GetTickCount actually returns 64 bits - pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount"); - - uint64 frequency; - QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter); - QueryPerformanceFrequency((LARGE_INTEGER*)&frequency); - counterPerMicrosecond = (double)frequency / 1000000.0f; - startGetTickCount = UTGetTickCount64(); -} - -int64 abs64(int64 x) { return x < 0 ? -x : x; } - -static uint64 GetMicroseconds() -{ - static bool time_init = false; - if (!time_init) { - time_init = true; - Time_Initialize(); - } - - uint64 counter; - uint64 tick; - - QueryPerformanceCounter((LARGE_INTEGER*) &counter); - tick = UTGetTickCount64(); - - // unfortunately, QueryPerformanceCounter is not guaranteed - // to be monotonic. Make it so. - int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond); - // if the QPC clock leaps more than one second off GetTickCount64() - // something is seriously fishy. Adjust QPC to stay monotonic - int64 tick_diff = tick - startGetTickCount; - if (abs64(ret / 100000 - tick_diff / 100) > 10) { - startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond); - ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond); - } - return ret; -} - -#else //!WIN32 - -#include -#include // Linux needs both time.h and sys/time.h -#include - -#include -#include -#include - -#if defined(__APPLE__) -#include - -static uint64 GetMicroseconds() -{ - // http://developer.apple.com/mac/library/qa/qa2004/qa1398.html - // http://www.macresearch.org/tutorial_performance_and_time - static mach_timebase_info_data_t sTimebaseInfo; - static uint64_t start_tick = 0; - uint64_t tick; - // Returns a counter in some fraction of a nanoseconds - tick = mach_absolute_time(); - if (sTimebaseInfo.denom == 0) { - // Get the timer ratio to convert mach_absolute_time to nanoseconds - mach_timebase_info(&sTimebaseInfo); - start_tick = tick; - } - // Calculate the elapsed time, convert it to microseconds and return it. - return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000); -} - -#else //!__APPLE__ - -/* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that - POSIX clocks work -- we could be running a recent libc with an ancient - kernel (think OpenWRT). -- jch */ - -static uint64_t GetMicroseconds() -{ - static int have_posix_clocks = -1; - int rc; - -#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC) - if (have_posix_clocks < 0) { - struct timespec ts; - rc = clock_gettime(CLOCK_MONOTONIC, &ts); - if (rc < 0) { - have_posix_clocks = 0; - } else { - have_posix_clocks = 1; - } - } - - if (have_posix_clocks) { - struct timespec ts; - rc = clock_gettime(CLOCK_MONOTONIC, &ts); - return uint64(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000; - } -#endif - { - struct timeval tv; - rc = gettimeofday(&tv, NULL); - return uint64(tv.tv_sec) * 1000000 + tv.tv_usec; - } -} -#endif //!__APPLE__ - -#endif //!WIN32 - -uint64 UTP_GetMicroseconds() -{ - static uint64 offset = 0, previous = 0; - - uint64 now = GetMicroseconds() + offset; - if (previous > now) { - /* Eek! */ - offset += previous - now; - now = previous; - } - previous = now; - return now; -} - -uint32 UTP_GetMilliseconds() -{ - return UTP_GetMicroseconds() / 1000; -} - - -#define ETHERNET_MTU 1500 -#define IPV4_HEADER_SIZE 20 -#define IPV6_HEADER_SIZE 40 -#define UDP_HEADER_SIZE 8 -#define GRE_HEADER_SIZE 24 -#define PPPOE_HEADER_SIZE 8 -#define MPPE_HEADER_SIZE 2 -// packets have been observed in the wild that were fragmented -// with a payload of 1416 for the first fragment -// There are reports of routers that have MTU sizes as small as 1392 -#define FUDGE_HEADER_SIZE 36 -#define TEREDO_MTU 1280 - -#define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE) -#define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE) -#define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD) - -#define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE) -#define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE) -#define UDP_TEREDO_MTU (TEREDO_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE) - -uint16 UTP_GetUDPMTU(const struct sockaddr *remote, socklen_t remotelen) -{ - // Since we don't know the local address of the interface, - // be conservative and assume all IPv6 connections are Teredo. - return remote->sa_family == AF_INET6 ? UDP_TEREDO_MTU : UDP_IPV4_MTU; -} - -uint16 UTP_GetUDPOverhead(const struct sockaddr *remote, socklen_t remotelen) -{ - // Since we don't know the local address of the interface, - // be conservative and assume all IPv6 connections are Teredo. - return remote->sa_family == AF_INET6 ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD; -} - -uint32 UTP_Random() -{ - return rand(); -} - -void UTP_DelaySample(const struct sockaddr *remote, int sample_ms) {} -size_t UTP_GetPacketSize(const struct sockaddr *remote) { return 1500; } - diff --git a/third-party/libutp/utp_utils.h b/third-party/libutp/utp_utils.h deleted file mode 100644 index 033984f3e..000000000 --- a/third-party/libutp/utp_utils.h +++ /dev/null @@ -1,16 +0,0 @@ -// This should return the MTU to the destination -uint16 UTP_GetUDPMTU(const struct sockaddr *remote, socklen_t remotelen); -// This should return the number of bytes of UDP overhead for one packet to the -// destination, for overhead calculation only -uint16 UTP_GetUDPOverhead(const struct sockaddr *remote, socklen_t remotelen); -// This should return monotonically increasing milliseconds, start point does not matter -uint32 UTP_GetMilliseconds(); -// This should return monotonically increasing microseconds, start point does not matter -uint64 UTP_GetMicroseconds(); -// This should return a random uint32 -uint32 UTP_Random(); -// This is called every time we have a delay sample is made -void UTP_DelaySample(const struct sockaddr *remote, int sample_ms); -// Should return the max packet size to use when sending to the given address -size_t UTP_GetPacketSize(const struct sockaddr *remote); - diff --git a/third-party/libutp/utypes.h b/third-party/libutp/utypes.h deleted file mode 100644 index 79bafcd92..000000000 --- a/third-party/libutp/utypes.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __UTYPES_H__ -#define __UTYPES_H__ - -// standard types -typedef unsigned char byte; -typedef unsigned char uint8; -typedef signed char int8; -typedef unsigned short uint16; -typedef signed short int16; -typedef unsigned int uint; -typedef unsigned int uint32; -typedef signed int int32; - -#ifdef _MSC_VER -typedef unsigned __int64 uint64; -typedef signed __int64 int64; -#else -typedef unsigned long long uint64; -typedef long long int64; -#endif - -/* compile-time assert */ -#ifndef CASSERT -#define CASSERT( exp, name ) typedef int is_not_##name [ (exp ) ? 1 : -1 ]; -#endif - -CASSERT(8 == sizeof(uint64), sizeof_uint64_is_8) -CASSERT(8 == sizeof(int64), sizeof_int64_is_8) - -#ifndef INT64_MAX -#define INT64_MAX 0x7fffffffffffffffLL -#endif - -// always ANSI -typedef const char * cstr; -typedef char * str; - -#ifndef __cplusplus -typedef uint8 bool; -#endif - -#endif //__UTYPES_H__ diff --git a/third-party/miniupnp/Changelog.txt b/third-party/miniupnp/Changelog.txt deleted file mode 100644 index 53e9a112b..000000000 --- a/third-party/miniupnp/Changelog.txt +++ /dev/null @@ -1,585 +0,0 @@ -$Id: Changelog.txt,v 1.193 2014/02/05 17:26:45 nanard Exp $ -miniUPnP client Changelog. - -2014/02/05: - handle EINPROGRESS after connect() - -2014/02/03: - minixml now handle XML comments - -VERSION 1.9 : released 2014/01/31 - -2014/01/31: - added argument remoteHost to UPNP_GetSpecificPortMappingEntry() - increment API_VERSION to 10 - -2013/12/09: - --help and -h arguments in upnpc.c - -2013/10/07: - fixed potential buffer overrun in miniwget.c - Modified UPNP_GetValidIGD() to check for ExternalIpAddress - -2013/08/01: - define MAXHOSTNAMELEN if not already done - -2013/06/06: - update upnpreplyparse to allow larger values (128 chars instead of 64) - -2013/05/14: - Update upnpreplyparse to take into account "empty" elements - validate upnpreplyparse.c code with "make check" - -2013/05/03: - Fix Solaris build thanks to Maciej Małecki - -2013/04/27: - Fix testminiwget.sh for BSD - -2013/03/23: - Fixed Makefile for *BSD - -2013/03/11: - Update Makefile to use JNAerator version 0.11 - -2013/02/11: - Fix testminiwget.sh for use with dash - Use $(DESTDIR) in Makefile - -VERSION 1.8 : released 2013/02/06 - -2012/10/16: - fix testminiwget with no IPv6 support - -2012/09/27: - Rename all include guards to not clash with C99 - (7.1.3 Reserved identifiers). - -2012/08/30: - Added -e option to upnpc program (set description for port mappings) - -2012/08/29: - Python 3 support (thanks to Christopher Foo) - -2012/08/11: - Fix a memory link in UPNP_GetValidIGD() - Try to handle scope id in link local IPv6 URL under MS Windows - -2012/07/20: - Disable HAS_IP_MREQN on DragonFly BSD - -2012/06/28: - GetUPNPUrls() now inserts scope into link-local IPv6 addresses - -2012/06/23: - More error return checks in upnpc.c - #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id - parseURL() now parses IPv6 addresses scope - new parameter for miniwget() : IPv6 address scope - increment API_VERSION to 9 - -2012/06/20: - fixed CMakeLists.txt - -2012/05/29 - Improvements in testminiwget.sh - -VERSION 1.7 : released 2012/05/24 - -2012/05/01: - Cleanup settings of CFLAGS in Makefile - Fix signed/unsigned integer comparaisons - -2012/04/20: - Allow to specify protocol with TCP or UDP for -A option - -2012/04/09: - Only try to fetch XML description once in UPNP_GetValidIGD() - Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. - -2012/04/05: - minor improvements to minihttptestserver.c - -2012/03/15: - upnperrors.c returns valid error string for unrecognized error codes - -2012/03/08: - make minihttptestserver listen on loopback interface instead of 0.0.0.0 - -2012/01/25: - Maven installation thanks to Alexey Kuznetsov - -2012/01/21: - Replace WIN32 macro by _WIN32 - -2012/01/19: - Fixes in java wrappers thanks to Alexey Kuznetsov : - https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc - Make and install .deb packages (python) thanks to Alexey Kuznetsov : - https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc - -2012/01/07: - The multicast interface can now be specified by name with IPv4. - -2012/01/02: - Install man page - -2011/11/25: - added header to Port Mappings list in upnpc.c - -2011/10/09: - Makefile : make clean now removes jnaerator generated files. - MINIUPNPC_VERSION in miniupnpc.h (updated by make) - -2011/09/12: - added rootdescURL to UPNPUrls structure. - -VERSION 1.6 : released 2011/07/25 - -2011/07/25: - Update doc for version 1.6 release - -2011/06/18: - Fix for windows in miniwget.c - -2011/06/04: - display remote host in port mapping listing - -2011/06/03: - Fix in make install : there were missing headers - -2011/05/26: - Fix the socket leak in miniwget thanks to Richard Marsh. - Permit to add leaseduration in -a command. Display lease duration. - -2011/05/15: - Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 - -2011/05/09: - add a test in testminiwget.sh. - more error checking in miniwget.c - -2011/05/06: - Adding some tool to test and validate miniwget.c - simplified and debugged miniwget.c - -2011/04/11: - moving ReceiveData() to a receivedata.c file. - parsing presentation url - adding IGD v2 WANIPv6FirewallControl commands - -2011/04/10: - update of miniupnpcmodule.c - comments in miniwget.c, update in testminiwget - Adding errors codes from IGD v2 - new functions in upnpc.c for IGD v2 - -2011/04/09: - Support for litteral ip v6 address in miniwget - -2011/04/08: - Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 - Updating APIVERSION - Supporting IPV6 in upnpDiscover() - Adding a -6 option to upnpc command line tool - -2011/03/18: - miniwget/parseURL() : return an error when url param is null. - fixing GetListOfPortMappings() - -2011/03/14: - upnpDiscover() now reporting an error code. - improvements in comments. - -2011/03/11: - adding miniupnpcstrings.h.cmake and CMakeLists.txt files. - -2011/02/15: - Implementation of GetListOfPortMappings() - -2011/02/07: - updates to minixml to support character data starting with spaces - minixml now support CDATA - upnpreplyparse treats specificaly - change in simpleUPnPcommand to return the buffer (simplification) - -2011/02/06: - Added leaseDuration argument to AddPortMapping() - Starting to implement GetListOfPortMappings() - -2011/01/11: - updating wingenminiupnpcstrings.c - -2011/01/04: - improving updateminiupnpcstrings.sh - -VERSION 1.5 : released 2011/01/01 - -2010/12/21: - use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo - -2010/12/11: - Improvements on getHTTPResponse() code. - -2010/12/09: - new code for miniwget that handle Chunked transfer encoding - using getHTTPResponse() in SOAP call code - Adding MANIFEST.in for 'python setup.py bdist_rpm' - -2010/11/25: - changes to minissdpc.c to compile under Win32. - see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 - -2010/09/17: - Various improvement to Makefile from Michał Górny - -2010/08/05: - Adding the script "external-ip.sh" from Reuben Hawkins - -2010/06/09: - update to python module to match modification made on 2010/04/05 - update to Java test code to match modification made on 2010/04/05 - all UPNP_* function now return an error if the SOAP request failed - at HTTP level. - -2010/04/17: - Using GetBestRoute() under win32 in order to find the - right interface to use. - -2010/04/12: - Retrying with HTTP/1.1 if HTTP/1.0 failed. see - http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 - -2010/04/07: - avoid returning duplicates in upnpDiscover() - -2010/04/05: - Create a connecthostport.h/.c with connecthostport() function - and use it in miniwget and miniupnpc. - Use getnameinfo() instead of inet_ntop or inet_ntoa - Work to make miniupnpc IPV6 compatible... - Add java test code. - Big changes in order to support device having both WANIPConnection - and WANPPPConnection. - -2010/04/04: - Use getaddrinfo() instead of gethostbyname() in miniwget. - -2010/01/06: - #define _DARWIN_C_SOURCE for Mac OS X - -2009/12/19: - Improve MinGW32 build - -2009/12/11: - adding a MSVC9 project to build the static library and executable - -2009/12/10: - Fixing some compilation stuff for Windows/MinGW - -2009/12/07: - adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS - some fixes for Windows when using virtual ethernet adapters (it is the - case with VMWare installed). - -2009/12/04: - some fixes for AmigaOS compilation - Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked - transfer encoding) - -2009/12/03: - updating printIDG and testigddescparse.c for debug. - modifications to compile under AmigaOS - adding a testminiwget program - Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked - transfer encoding - -2009/11/26: - fixing updateminiupnpcstrings.sh to take into account - which command that does not return an error code. - -VERSION 1.4 : released 2009/10/30 - -2009/10/16: - using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. - -2009/10/10: - Some fixes for compilation under Solaris - compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 - -2009/09/21: - fixing the code to ignore EINTR during connect() calls. - -2009/08/07: - Set socket timeout for connect() - Some cleanup in miniwget.c - -2009/08/04: - remove multiple redirections with -d in upnpc.c - Print textual error code in upnpc.c - Ignore EINTR during the connect() and poll() calls. - -2009/07/29: - fix in updateminiupnpcstrings.sh if OS name contains "/" - Sending a correct value for MX: field in SSDP request - -2009/07/20: - Change the Makefile to compile under Mac OS X - Fixed a stackoverflow in getDevicesFromMiniSSDPD() - -2009/07/09: - Compile under Haiku - generate miniupnpcstrings.h.in from miniupnpcstrings.h - -2009/06/04: - patching to compile under CygWin and cross compile for minGW - -VERSION 1.3 : - -2009/04/17: - updating python module - Use strtoull() when using C99 - -2009/02/28: - Fixed miniwget.c for compiling under sun - -2008/12/18: - cleanup in Makefile (thanks to Paul de Weerd) - minissdpc.c : win32 compatibility - miniupnpc.c : changed xmlns prefix from 'm' to 'u' - Removed NDEBUG (using DEBUG) - -2008/10/14: - Added the ExternalHost argument to DeletePortMapping() - -2008/10/11: - Added the ExternalHost argument to AddPortMapping() - Put a correct User-Agent: header in HTTP requests. - -VERSION 1.2 : - -2008/10/07: - Update docs - -2008/09/25: - Integrated sameport patch from Dario Meloni : Added a "sameport" - argument to upnpDiscover(). - -2008/07/18: - small modif to make Clang happy :) - -2008/07/17: - #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... - -2008/07/14: - include declspec.h in installation (to /usr/include/miniupnpc) - -VERSION 1.1 : - -2008/07/04: - standard options for install/ln instead of gnu-specific stuff. - -2008/07/03: - now builds a .dll and .lib with win32. (mingw32) - -2008/04/28: - make install now install the binary of the upnpc tool - -2008/04/27: - added testupnpigd.py - added error strings for miniupnpc "internal" errors - improved python module error/exception reporting. - -2008/04/23: - Completely rewrite igd_desc_parse.c in order to be compatible with - Linksys WAG200G - Added testigddescparse - updated python module - -VERSION 1.0 : - -2008/02/21: - put some #ifdef DEBUG around DisplayNameValueList() - -2008/02/18: - Improved error reporting in upnpcommands.c - UPNP_GetStatusInfo() returns LastConnectionError - -2008/02/16: - better error handling in minisoap.c - improving display of "valid IGD found" in upnpc.c - -2008/02/03: - Fixing UPNP_GetValidIGD() - improved make install :) - -2007/12/22: - Adding upnperrors.c/h to provide a strupnperror() function - used to translate UPnP error codes to string. - -2007/12/19: - Fixing getDevicesFromMiniSSDPD() - improved error reporting of UPnP functions - -2007/12/18: - It is now possible to specify a different location for MiniSSDPd socket. - working with MiniSSDPd is now more efficient. - python module improved. - -2007/12/16: - improving error reporting - -2007/12/13: - Try to improve compatibility by using HTTP/1.0 instead of 1.1 and - XML a bit different for SOAP. - -2007/11/25: - fixed select() call for linux - -2007/11/15: - Added -fPIC to CFLAG for better shared library code. - -2007/11/02: - Fixed a potential socket leak in miniwget2() - -2007/10/16: - added a parameter to upnpDiscover() in order to allow the use of another - interface than the default multicast interface. - -2007/10/12: - Fixed the creation of symbolic link in Makefile - -2007/10/08: - Added man page - -2007/10/02: - fixed memory bug in GetUPNPUrls() - -2007/10/01: - fixes in the Makefile - Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. - Added SONAME in the shared library to please debian :) - fixed MS Windows compilation (minissdpd is not available under MS Windows). - -2007/09/25: - small change to Makefile to be able to install in a different location - (default is /usr) - -2007/09/24: - now compiling both shared and static library - -2007/09/19: - Cosmetic changes on upnpc.c - -2007/09/02: - adapting to new miniSSDPd (release version ?) - -2007/08/31: - Usage of miniSSDPd to skip discovery process. - -2007/08/27: - fixed python module to allow compilation with Python older than Python 2.4 - -2007/06/12: - Added a python module. - -2007/05/19: - Fixed compilation under MinGW - -2007/05/15: - fixed a memory leak in AddPortMapping() - Added testupnpreplyparse executable to check the parsing of - upnp soap messages - minixml now ignore namespace prefixes. - -2007/04/26: - upnpc now displays external ip address with -s or -l - -2007/04/11: - changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" - -2007/03/19: - cleanup in miniwget.c - -2007/03/01: - Small typo fix... - -2007/01/30: - Now parsing the HTTP header from SOAP responses in order to - get content-length value. - -2007/01/29: - Fixed the Soap Query to speedup the HTTP request. - added some Win32 DLL stuff... - -2007/01/27: - Fixed some WIN32 compatibility issues - -2006/12/14: - Added UPNPIGD_IsConnected() function in miniupnp.c/.h - Added UPNP_GetValidIGD() in miniupnp.c/.h - cleaned upnpc.c main(). now using UPNP_GetValidIGD() - -2006/12/07: - Version 1.0-RC1 released - -2006/12/03: - Minor changes to compile under SunOS/Solaris - -2006/11/30: - made a minixml parser validator program - updated minixml to handle attributes correctly - -2006/11/22: - Added a -r option to the upnpc sample thanks to Alexander Hubmann. - -2006/11/19: - Cleanup code to make it more ANSI C compliant - -2006/11/10: - detect and display local lan address. - -2006/11/04: - Packets and Bytes Sent/Received are now unsigned int. - -2006/11/01: - Bug fix thanks to Giuseppe D'Angelo - -2006/10/31: - C++ compatibility for .h files. - Added a way to get ip Address on the LAN used to reach the IGD. - -2006/10/25: - Added M-SEARCH to the services in the discovery process. - -2006/10/22: - updated the Makefile to use makedepend, added a "make install" - update Makefile - -2006/10/20: - fixing the description url parsing thanks to patch sent by - Wayne Dawe. - Fixed/translated some comments. - Implemented a better discover process, first looking - for IGD then for root devices (as some devices only reply to - M-SEARCH for root devices). - -2006/09/02: - added freeUPNPDevlist() function. - -2006/08/04: - More command line arguments checking - -2006/08/01: - Added the .bat file to compile under Win32 with minGW32 - -2006/07/31: - Fixed the rootdesc parser (igd_desc_parse.c) - -2006/07/20: - parseMSEARCHReply() is now returning the ST: line as well - starting changes to detect several UPnP devices on the network - -2006/07/19: - using GetCommonLinkProperties to get down/upload bitrate - diff --git a/third-party/miniupnp/LICENSE b/third-party/miniupnp/LICENSE deleted file mode 100644 index ac89a7516..000000000 --- a/third-party/miniupnp/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -MiniUPnPc -Copyright (c) 2005-2011, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. - diff --git a/third-party/miniupnp/Makefile.am b/third-party/miniupnp/Makefile.am deleted file mode 100644 index cc6edb14d..000000000 --- a/third-party/miniupnp/Makefile.am +++ /dev/null @@ -1,47 +0,0 @@ -noinst_LIBRARIES = libminiupnp.a - -AM_CFLAGS = @PTHREAD_CFLAGS@ -DNDEBUG -D_GNU_SOURCE - -libminiupnp_a_SOURCES = \ - connecthostport.c \ - igd_desc_parse.c \ - minisoap.c \ - minissdpc.c \ - miniupnpc.c \ - miniwget.c \ - minixml.c \ - portlistingparse.c \ - receivedata.c \ - upnpcommands.c \ - upnpreplyparse.c - -noinst_HEADERS = \ - bsdqueue.h \ - codelength.h \ - connecthostport.h \ - declspec.h \ - igd_desc_parse.h \ - minisoap.h \ - minissdpc.h \ - miniupnpc.h \ - miniupnpctypes.h \ - miniwget.h \ - minixml.h \ - portlistingparse.h \ - receivedata.h \ - upnpcommands.h \ - upnpreplyparse.h - -EXTRA_DIST = \ - README \ - LICENSE \ - miniupnpcstrings.h.in \ - updateminiupnpcstrings.sh - -BUILT_SOURCES = \ - miniupnpcstrings.h - -miniupnpcstrings.h: Makefile - $(srcdir)/updateminiupnpcstrings.sh $(srcdir)/VERSION $(srcdir)/miniupnpcstrings.h.in $@ - -DISTCLEANFILES = $(builddir)/miniupnpcstrings.h diff --git a/third-party/miniupnp/README b/third-party/miniupnp/README deleted file mode 100644 index b23478de9..000000000 --- a/third-party/miniupnp/README +++ /dev/null @@ -1,66 +0,0 @@ -Project: miniupnp -Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ -github: https://github.com/miniupnp/miniupnp -freecode: http://freecode.com/projects/miniupnp -Author: Thomas Bernard -Copyright (c) 2005-2012 Thomas Bernard -This software is subject to the conditions detailed in the -LICENSE file provided within this distribution. - - -For the comfort of Win32 users, bsdqueue.h is included in the distribution. -Its licence is included in the header of the file. -bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system. - - -* miniUPnP Client - miniUPnPc * - -To compile, simply run 'gmake' (could be 'make' on your system). -Under win32, to compile with MinGW, type "mingw32make.bat". -MS Visual C solution and project files are supplied in the msvc/ subdirectory. - -The compilation is known to work under linux, FreeBSD, -OpenBSD, MacOS X, AmigaOS and cygwin. -The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3. -upx (http://upx.sourceforge.net) is used to compress the win32 .exe files. - -To install the library and headers on the system use : -> su -> make install -> exit - -alternatively, to install into a specific location, use : -> INSTALLPREFIX=/usr/local make install - -upnpc.c is a sample client using the libminiupnpc. -To use the libminiupnpc in your application, link it with -libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h, -upnpcommands.h and miniwget.h : -- upnpDiscover() -- miniwget() -- parserootdesc() -- GetUPNPUrls() -- UPNP_* (calling UPNP methods) - -Note : use #include etc... for the includes -and -lminiupnpc for the link - -Discovery process is speeded up when MiniSSDPd is running on the machine. - - -* Python module * - -you can build a python module with 'make pythonmodule' -and install it with 'make installpythonmodule'. -setup.py (and setupmingw32.py) are included in the distribution. - - -Feel free to contact me if you have any problem : -e-mail : miniupnp@free.fr - -If you are using libminiupnpc in your application, please -send me an email ! - -For any question, you can use the web forum : -http://miniupnp.tuxfamily.org/forum/ - diff --git a/third-party/miniupnp/VERSION b/third-party/miniupnp/VERSION deleted file mode 100644 index d3bdbdf1f..000000000 --- a/third-party/miniupnp/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.7 diff --git a/third-party/miniupnp/apiversions.txt b/third-party/miniupnp/apiversions.txt deleted file mode 100644 index 69f61c799..000000000 --- a/third-party/miniupnp/apiversions.txt +++ /dev/null @@ -1,127 +0,0 @@ -$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $ - -Differences in API between miniUPnPc versions - -====================== miniUPnPc version 1.9 ====================== -API version 10 - -upnpcommands.h: - added argument remoteHost to UPNP_GetSpecificPortMappingEntry() - -miniupnpc.h: - updated macros : - #define MINIUPNPC_VERSION "1.9" - #define MINIUPNPC_API_VERSION 10 - -====================== miniUPnPc version 1.8 ====================== -API version 9 - -miniupnpc.h: - updated macros : - #define MINIUPNPC_VERSION "1.8" - #define MINIUPNPC_API_VERSION 9 - added "unsigned int scope_id;" to struct UPNPDev - added scope_id argument to GetUPNPUrls() - - - -====================== miniUPnPc version 1.7 ====================== -API version 8 - -miniupnpc.h : - add new macros : - #define MINIUPNPC_VERSION "1.7" - #define MINIUPNPC_API_VERSION 8 - add rootdescURL to struct UPNPUrls - - - -====================== miniUPnPc version 1.6 ====================== -API version 8 - -Adding support for IPv6. -igd_desc_parse.h : - struct IGDdatas_service : - add char presentationurl[MINIUPNPC_URL_MAXSIZE]; - struct IGDdatas : - add struct IGDdatas_service IPv6FC; -miniupnpc.h : - new macros : - #define UPNPDISCOVER_SUCCESS (0) - #define UPNPDISCOVER_UNKNOWN_ERROR (-1) - #define UPNPDISCOVER_SOCKET_ERROR (-101) - #define UPNPDISCOVER_MEMORY_ERROR (-102) - simpleUPnPcommand() prototype changed (but is normaly not used by API users) - add arguments ipv6 and error to upnpDiscover() : - struct UPNPDev * - upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, - int * error); - add controlURL_6FC member to struct UPNPUrls : - struct UPNPUrls { - char * controlURL; - char * ipcondescURL; - char * controlURL_CIF; - char * controlURL_6FC; - }; - -upnpcommands.h : - add leaseDuration argument to UPNP_AddPortMapping() - add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry() - add UPNP_GetListOfPortMappings() function (IGDv2) - add IGDv2 IPv6 related functions : - UPNP_GetFirewallStatus() - UPNP_GetOutboundPinholeTimeout() - UPNP_AddPinhole() - UPNP_UpdatePinhole() - UPNP_DeletePinhole() - UPNP_CheckPinholeWorking() - UPNP_GetPinholePackets() - - - -====================== miniUPnPc version 1.5 ====================== -API version 5 - -new function : -int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); -new macro in upnpcommands.h : -#define UPNPCOMMAND_HTTP_ERROR - -====================== miniUPnPc version 1.4 ====================== -Same API as version 1.3 - -====================== miniUPnPc version 1.3 ====================== -API version 4 - -Use UNSIGNED_INTEGER type for -UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(), -UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived() -Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping() - -====================== miniUPnPc version 1.2 ====================== -API version 3 - -added sameport argument to upnpDiscover() -struct UPNPDev * -upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int sameport); - -====================== miniUPnPc Version 1.1 ====================== -Same API as 1.0 - - -====================== miniUPnPc Version 1.0 ====================== -API version 2 - - -struct UPNPDev { - struct UPNPDev * pNext; - char * descURL; - char * st; - char buffer[2]; -}; -struct UPNPDev * upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock); - diff --git a/third-party/miniupnp/bsdqueue.h b/third-party/miniupnp/bsdqueue.h deleted file mode 100644 index c6afe1f7c..000000000 --- a/third-party/miniupnp/bsdqueue.h +++ /dev/null @@ -1,531 +0,0 @@ -/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */ -/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines five types of data structures: singly-linked lists, - * lists, simple queues, tail queues, and circular queues. - * - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -#ifdef QUEUE_MACRO_DEBUG -#define _Q_INVALIDATE(a) (a) = ((void *)-1) -#else -#define _Q_INVALIDATE(a) -#endif - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#ifdef SLIST_ENTRY -#undef SLIST_ENTRY -#endif - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List access methods. - */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = SLIST_FIRST(head); \ - (var) != SLIST_END(head); \ - (var) = SLIST_NEXT(var, field)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != SLIST_END(head); \ - (varp) = &SLIST_NEXT((var), field)) - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) { \ - SLIST_FIRST(head) = SLIST_END(head); \ -} - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (0) - -#define SLIST_REMOVE_NEXT(head, elm, field) do { \ - (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (0) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->slh_first; \ - \ - while (curelm->field.sle_next != (elm)) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ - _Q_INVALIDATE((elm)->field.sle_next); \ - } \ -} while (0) - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List access methods - */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for((var) = LIST_FIRST(head); \ - (var)!= LIST_END(head); \ - (var) = LIST_NEXT(var, field)) - -/* - * List functions. - */ -#define LIST_INIT(head) do { \ - LIST_FIRST(head) = LIST_END(head); \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (0) - -#define LIST_REMOVE(elm, field) do { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ -} while (0) - -#define LIST_REPLACE(elm, elm2, field) do { \ - if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ - (elm2)->field.le_next->field.le_prev = \ - &(elm2)->field.le_next; \ - (elm2)->field.le_prev = (elm)->field.le_prev; \ - *(elm2)->field.le_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ -} while (0) - -/* - * Simple queue definitions. - */ -#define SIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define SIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define SIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Simple queue access methods. - */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) - -/* - * Simple queue functions. - */ -#define SIMPLEQ_INIT(head) do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ -} while (0) - -#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (0) - -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ -} while (0) - -#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ - if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * tail queue access methods - */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -/* XXX */ -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) \ - (TAILQ_FIRST(head) == TAILQ_END(head)) - -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_PREV(var, headname, field)) - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) do { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ -} while (0) - -#define TAILQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ - (elm2)->field.tqe_next->field.tqe_prev = \ - &(elm2)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm2)->field.tqe_next; \ - (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ - *(elm2)->field.tqe_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ -} while (0) - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue access methods - */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_NEXT(var, field)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for((var) = CIRCLEQ_LAST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_PREV(var, field)) - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ -} while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} while (0) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ -} while (0) - -#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ - CIRCLEQ_END(head)) \ - (head).cqh_last = (elm2); \ - else \ - (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ - if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ - CIRCLEQ_END(head)) \ - (head).cqh_first = (elm2); \ - else \ - (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/third-party/miniupnp/codelength.h b/third-party/miniupnp/codelength.h deleted file mode 100644 index d342bd141..000000000 --- a/third-party/miniupnp/codelength.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $Id: codelength.h,v 1.4 2012/09/27 15:40:29 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas BERNARD - * copyright (c) 2005-2011 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -#ifndef CODELENGTH_H_INCLUDED -#define CODELENGTH_H_INCLUDED - -/* Encode length by using 7bit per Byte : - * Most significant bit of each byte specifies that the - * following byte is part of the code */ -#define DECODELENGTH(n, p) n = 0; \ - do { n = (n << 7) | (*p & 0x7f); } \ - while((*(p++)&0x80) && (n<(1<<25))); - -#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ - n = 0; \ - do { \ - if((p) >= (p_limit)) break; \ - n = (n << 7) | (*(p) & 0x7f); \ - } while((*((p)++)&0x80) && (n<(1<<25))); - -#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ - if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ - if(n>=16384) *(p++) = (n >> 14) | 0x80; \ - if(n>=128) *(p++) = (n >> 7) | 0x80; \ - *(p++) = n & 0x7f; - -#endif - diff --git a/third-party/miniupnp/connecthostport.c b/third-party/miniupnp/connecthostport.c deleted file mode 100644 index d66ae315f..000000000 --- a/third-party/miniupnp/connecthostport.c +++ /dev/null @@ -1,261 +0,0 @@ -/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2010-2014 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -/* use getaddrinfo() or gethostbyname() - * uncomment the following line in order to use gethostbyname() */ -#ifdef NO_GETADDRINFO -#define USE_GETHOSTBYNAME -#endif - -#include -#include -#ifdef _WIN32 -#include -#include -#include -#define MAXHOSTNAMELEN 64 -#define snprintf _snprintf -#define herror -#define socklen_t int -#else /* #ifdef _WIN32 */ -#include -#include -#include -#include -#define closesocket close -#include -#include -/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions - * during the connect() call */ -#define MINIUPNPC_IGNORE_EINTR -#ifndef USE_GETHOSTBYNAME -#include -#include -#include -#endif /* #ifndef USE_GETHOSTBYNAME */ -#endif /* #else _WIN32 */ - -/* definition of PRINT_SOCKET_ERROR */ -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -#if defined(__amigaos__) || defined(__amigaos4__) -#define herror(A) printf("%s\n", A) -#endif - -#include "connecthostport.h" - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -/* connecthostport() - * return a socket connected (TCP) to the host and port - * or -1 in case of error */ -int connecthostport(const char * host, unsigned short port, - unsigned int scope_id) -{ - int s, n; -#ifdef USE_GETHOSTBYNAME - struct sockaddr_in dest; - struct hostent *hp; -#else /* #ifdef USE_GETHOSTBYNAME */ - char tmp_host[MAXHOSTNAMELEN+1]; - char port_str[8]; - struct addrinfo *ai, *p; - struct addrinfo hints; -#endif /* #ifdef USE_GETHOSTBYNAME */ -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT - struct timeval timeout; -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - -#ifdef USE_GETHOSTBYNAME - hp = gethostbyname(host); - if(hp == NULL) - { - herror(host); - return -1; - } - memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); - memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); - s = socket(PF_INET, SOCK_STREAM, 0); - if(s < 0) - { - PRINT_SOCKET_ERROR("socket"); - return -1; - } -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT - /* setting a 3 seconds timeout for the connect() call */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - dest.sin_family = AF_INET; - dest.sin_port = htons(port); - n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); -#ifdef MINIUPNPC_IGNORE_EINTR - /* EINTR The system call was interrupted by a signal that was caught - * EINPROGRESS The socket is nonblocking and the connection cannot - * be completed immediately. */ - while(n < 0 && (errno == EINTR || errno = EINPROGRESS)) - { - socklen_t len; - fd_set wset; - int err; - FD_ZERO(&wset); - FD_SET(s, &wset); - if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) - continue; - /*len = 0;*/ - /*n = getpeername(s, NULL, &len);*/ - len = sizeof(err); - if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { - PRINT_SOCKET_ERROR("getsockopt"); - closesocket(s); - return -1; - } - if(err != 0) { - errno = err; - n = -1; - } - } -#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ - if(n<0) - { - PRINT_SOCKET_ERROR("connect"); - closesocket(s); - return -1; - } -#else /* #ifdef USE_GETHOSTBYNAME */ - /* use getaddrinfo() instead of gethostbyname() */ - memset(&hints, 0, sizeof(hints)); - /* hints.ai_flags = AI_ADDRCONFIG; */ -#ifdef AI_NUMERICSERV - hints.ai_flags = AI_NUMERICSERV; -#endif - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ - /* hints.ai_protocol = IPPROTO_TCP; */ - snprintf(port_str, sizeof(port_str), "%hu", port); - if(host[0] == '[') - { - /* literal ip v6 address */ - int i, j; - for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) - { - tmp_host[i] = host[j]; - if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ - j+=2; /* skip "25" */ - } - tmp_host[i] = '\0'; - } - else - { - strncpy(tmp_host, host, MAXHOSTNAMELEN); - } - tmp_host[MAXHOSTNAMELEN] = '\0'; - n = getaddrinfo(tmp_host, port_str, &hints, &ai); - if(n != 0) - { -#ifdef _WIN32 - fprintf(stderr, "getaddrinfo() error : %d\n", n); -#else - fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); -#endif - return -1; - } - s = -1; - for(p = ai; p; p = p->ai_next) - { - s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if(s < 0) - continue; - if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) { - struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr; - addr6->sin6_scope_id = scope_id; - } -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT - /* setting a 3 seconds timeout for the connect() call */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - n = connect(s, p->ai_addr, p->ai_addrlen); -#ifdef MINIUPNPC_IGNORE_EINTR - /* EINTR The system call was interrupted by a signal that was caught - * EINPROGRESS The socket is nonblocking and the connection cannot - * be completed immediately. */ - while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) - { - socklen_t len; - fd_set wset; - int err; - FD_ZERO(&wset); - FD_SET(s, &wset); - if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) - continue; - /*len = 0;*/ - /*n = getpeername(s, NULL, &len);*/ - len = sizeof(err); - if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { - PRINT_SOCKET_ERROR("getsockopt"); - closesocket(s); - freeaddrinfo(ai); - return -1; - } - if(err != 0) { - errno = err; - n = -1; - } - } -#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ - if(n < 0) - { - closesocket(s); - continue; - } - else - { - break; - } - } - freeaddrinfo(ai); - if(s < 0) - { - PRINT_SOCKET_ERROR("socket"); - return -1; - } - if(n < 0) - { - PRINT_SOCKET_ERROR("connect"); - return -1; - } -#endif /* #ifdef USE_GETHOSTBYNAME */ - return s; -} - diff --git a/third-party/miniupnp/connecthostport.h b/third-party/miniupnp/connecthostport.h deleted file mode 100644 index 56941d6fa..000000000 --- a/third-party/miniupnp/connecthostport.h +++ /dev/null @@ -1,18 +0,0 @@ -/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ - * Author: Thomas Bernard - * Copyright (c) 2010-2012 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef CONNECTHOSTPORT_H_INCLUDED -#define CONNECTHOSTPORT_H_INCLUDED - -/* connecthostport() - * return a socket connected (TCP) to the host and port - * or -1 in case of error */ -int connecthostport(const char * host, unsigned short port, - unsigned int scope_id); - -#endif - diff --git a/third-party/miniupnp/declspec.h b/third-party/miniupnp/declspec.h deleted file mode 100644 index 77299693b..000000000 --- a/third-party/miniupnp/declspec.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef DECLSPEC_H_INCLUDED -#define DECLSPEC_H_INCLUDED - -#if defined(_WIN32) && !defined(STATICLIB) - /* for windows dll */ - #ifdef MINIUPNP_EXPORTS - #define LIBSPEC __declspec(dllexport) - #else - #define LIBSPEC __declspec(dllimport) - #endif -#else - #if defined(__GNUC__) && __GNUC__ >= 4 - /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ - #define LIBSPEC __attribute__ ((visibility ("default"))) - #else - #define LIBSPEC - #endif -#endif - -#endif - diff --git a/third-party/miniupnp/igd_desc_parse.c b/third-party/miniupnp/igd_desc_parse.c deleted file mode 100644 index 6c3e65677..000000000 --- a/third-party/miniupnp/igd_desc_parse.c +++ /dev/null @@ -1,125 +0,0 @@ -/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */ -/* Project : miniupnp - * http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2010 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include "igd_desc_parse.h" -#include -#include - -/* Start element handler : - * update nesting level counter and copy element name */ -void IGDstartelt(void * d, const char * name, int l) -{ - struct IGDdatas * datas = (struct IGDdatas *)d; - memcpy( datas->cureltname, name, l); - datas->cureltname[l] = '\0'; - datas->level++; - if( (l==7) && !memcmp(name, "service", l) ) { - datas->tmp.controlurl[0] = '\0'; - datas->tmp.eventsuburl[0] = '\0'; - datas->tmp.scpdurl[0] = '\0'; - datas->tmp.servicetype[0] = '\0'; - } -} - -/* End element handler : - * update nesting level counter and update parser state if - * service element is parsed */ -void IGDendelt(void * d, const char * name, int l) -{ - struct IGDdatas * datas = (struct IGDdatas *)d; - datas->level--; - /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ - if( (l==7) && !memcmp(name, "service", l) ) - { - /* - if( datas->state < 1 - && !strcmp(datas->servicetype, - // "urn:schemas-upnp-org:service:WANIPConnection:1") ) - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) - datas->state ++; - */ - if(0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) { - memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); - } else if(0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) { - memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); - } else if(0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANIPConnection:1") - || 0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANPPPConnection:1") ) { - if(datas->first.servicetype[0] == '\0') { - memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); - } else { - memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); - } - } - } -} - -/* Data handler : - * copy data depending on the current element name and state */ -void IGDdata(void * d, const char * data, int l) -{ - struct IGDdatas * datas = (struct IGDdatas *)d; - char * dstmember = 0; - /*printf("%2d %s : %.*s\n", - datas->level, datas->cureltname, l, data); */ - if( !strcmp(datas->cureltname, "URLBase") ) - dstmember = datas->urlbase; - else if( !strcmp(datas->cureltname, "presentationURL") ) - dstmember = datas->presentationurl; - else if( !strcmp(datas->cureltname, "serviceType") ) - dstmember = datas->tmp.servicetype; - else if( !strcmp(datas->cureltname, "controlURL") ) - dstmember = datas->tmp.controlurl; - else if( !strcmp(datas->cureltname, "eventSubURL") ) - dstmember = datas->tmp.eventsuburl; - else if( !strcmp(datas->cureltname, "SCPDURL") ) - dstmember = datas->tmp.scpdurl; -/* else if( !strcmp(datas->cureltname, "deviceType") ) - dstmember = datas->devicetype_tmp;*/ - if(dstmember) - { - if(l>=MINIUPNPC_URL_MAXSIZE) - l = MINIUPNPC_URL_MAXSIZE-1; - memcpy(dstmember, data, l); - dstmember[l] = '\0'; - } -} - -void printIGD(struct IGDdatas * d) -{ - printf("urlbase = '%s'\n", d->urlbase); - printf("WAN Device (Common interface config) :\n"); - /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ - printf(" serviceType = '%s'\n", d->CIF.servicetype); - printf(" controlURL = '%s'\n", d->CIF.controlurl); - printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); - printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); - printf("primary WAN Connection Device (IP or PPP Connection):\n"); - /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ - printf(" servicetype = '%s'\n", d->first.servicetype); - printf(" controlURL = '%s'\n", d->first.controlurl); - printf(" eventSubURL = '%s'\n", d->first.eventsuburl); - printf(" SCPDURL = '%s'\n", d->first.scpdurl); - printf("secondary WAN Connection Device (IP or PPP Connection):\n"); - /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ - printf(" servicetype = '%s'\n", d->second.servicetype); - printf(" controlURL = '%s'\n", d->second.controlurl); - printf(" eventSubURL = '%s'\n", d->second.eventsuburl); - printf(" SCPDURL = '%s'\n", d->second.scpdurl); - printf("WAN IPv6 Firewall Control :\n"); - /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ - printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); - printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); - printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); - printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); -} - - diff --git a/third-party/miniupnp/igd_desc_parse.h b/third-party/miniupnp/igd_desc_parse.h deleted file mode 100644 index 0a49b019d..000000000 --- a/third-party/miniupnp/igd_desc_parse.h +++ /dev/null @@ -1,48 +0,0 @@ -/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */ -/* Project : miniupnp - * http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2010 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef IGD_DESC_PARSE_H_INCLUDED -#define IGD_DESC_PARSE_H_INCLUDED - -/* Structure to store the result of the parsing of UPnP - * descriptions of Internet Gateway Devices */ -#define MINIUPNPC_URL_MAXSIZE (128) -struct IGDdatas_service { - char controlurl[MINIUPNPC_URL_MAXSIZE]; - char eventsuburl[MINIUPNPC_URL_MAXSIZE]; - char scpdurl[MINIUPNPC_URL_MAXSIZE]; - char servicetype[MINIUPNPC_URL_MAXSIZE]; - /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ -}; - -struct IGDdatas { - char cureltname[MINIUPNPC_URL_MAXSIZE]; - char urlbase[MINIUPNPC_URL_MAXSIZE]; - char presentationurl[MINIUPNPC_URL_MAXSIZE]; - int level; - /*int state;*/ - /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ - struct IGDdatas_service CIF; - /* "urn:schemas-upnp-org:service:WANIPConnection:1" - * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ - struct IGDdatas_service first; - /* if both WANIPConnection and WANPPPConnection are present */ - struct IGDdatas_service second; - /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ - struct IGDdatas_service IPv6FC; - /* tmp */ - struct IGDdatas_service tmp; -}; - -void IGDstartelt(void *, const char *, int); -void IGDendelt(void *, const char *, int); -void IGDdata(void *, const char *, int); -void printIGD(struct IGDdatas *); - -#endif - diff --git a/third-party/miniupnp/minisoap.c b/third-party/miniupnp/minisoap.c deleted file mode 100644 index e45a481ac..000000000 --- a/third-party/miniupnp/minisoap.c +++ /dev/null @@ -1,121 +0,0 @@ -/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2012 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * - * Minimal SOAP implementation for UPnP protocol. - */ -#include -#include -#ifdef _WIN32 -#include -#include -#define snprintf _snprintf -#else -#include -#include -#include -#endif -#include "minisoap.h" -#include "miniupnpcstrings.h" - -/* only for malloc */ -#include - -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -/* httpWrite sends the headers and the body to the socket - * and returns the number of bytes sent */ -static int -httpWrite(int fd, const char * body, int bodysize, - const char * headers, int headerssize) -{ - int n = 0; - /*n = write(fd, headers, headerssize);*/ - /*if(bodysize>0) - n += write(fd, body, bodysize);*/ - /* Note : my old linksys router only took into account - * soap request that are sent into only one packet */ - char * p; - /* TODO: AVOID MALLOC */ - p = malloc(headerssize+bodysize); - if(!p) - return 0; - memcpy(p, headers, headerssize); - memcpy(p+headerssize, body, bodysize); - /*n = write(fd, p, headerssize+bodysize);*/ - n = send(fd, p, headerssize+bodysize, 0); - if(n<0) { - PRINT_SOCKET_ERROR("send"); - } - /* disable send on the socket */ - /* draytek routers dont seems to like that... */ -#if 0 -#ifdef _WIN32 - if(shutdown(fd, SD_SEND)<0) { -#else - if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ -#endif - PRINT_SOCKET_ERROR("shutdown"); - } -#endif - free(p); - return n; -} - -/* self explanatory */ -int soapPostSubmit(int fd, - const char * url, - const char * host, - unsigned short port, - const char * action, - const char * body, - const char * httpversion) -{ - int bodysize; - char headerbuf[512]; - int headerssize; - char portstr[8]; - bodysize = (int)strlen(body); - /* We are not using keep-alive HTTP connections. - * HTTP/1.1 needs the header Connection: close to do that. - * This is the default with HTTP/1.0 - * Using HTTP/1.1 means we need to support chunked transfer-encoding : - * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked - * transfer encoding. */ - /* Connection: Close is normally there only in HTTP/1.1 but who knows */ - portstr[0] = '\0'; - if(port != 80) - snprintf(portstr, sizeof(portstr), ":%hu", port); - headerssize = snprintf(headerbuf, sizeof(headerbuf), - "POST %s HTTP/%s\r\n" - "Host: %s%s\r\n" - "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" - "Content-Length: %d\r\n" - "Content-Type: text/xml\r\n" - "SOAPAction: \"%s\"\r\n" - "Connection: Close\r\n" - "Cache-Control: no-cache\r\n" /* ??? */ - "Pragma: no-cache\r\n" - "\r\n", - url, httpversion, host, portstr, bodysize, action); -#ifdef DEBUG - /*printf("SOAP request : headersize=%d bodysize=%d\n", - headerssize, bodysize); - */ - printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", - url, httpversion, host, portstr); - printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); - printf("Headers :\n%s", headerbuf); - printf("Body :\n%s\n", body); -#endif - return httpWrite(fd, body, bodysize, headerbuf, headerssize); -} - - diff --git a/third-party/miniupnp/minisoap.h b/third-party/miniupnp/minisoap.h deleted file mode 100644 index 14c859d1e..000000000 --- a/third-party/miniupnp/minisoap.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ -#ifndef MINISOAP_H_INCLUDED -#define MINISOAP_H_INCLUDED - -/*int httpWrite(int, const char *, int, const char *);*/ -int soapPostSubmit(int, const char *, const char *, unsigned short, - const char *, const char *, const char *); - -#endif - diff --git a/third-party/miniupnp/minissdpc.c b/third-party/miniupnp/minissdpc.c deleted file mode 100644 index c4913fb89..000000000 --- a/third-party/miniupnp/minissdpc.c +++ /dev/null @@ -1,133 +0,0 @@ -/* $Id: minissdpc.c,v 1.16 2012/03/05 19:42:46 nanard Exp $ */ -/* Project : miniupnp - * Web : http://miniupnp.free.fr/ - * Author : Thomas BERNARD - * copyright (c) 2005-2012 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -/*#include */ -#include -#include -#include -#include -#include -#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) -#ifdef _WIN32 -#include -#include -#include -#include -#include -#endif -#if defined(__amigaos__) || defined(__amigaos4__) -#include -#endif -#if defined(__amigaos__) -#define uint16_t unsigned short -#endif -/* Hack */ -#define UNIX_PATH_LEN 108 -struct sockaddr_un { - uint16_t sun_family; - char sun_path[UNIX_PATH_LEN]; -}; -#else -#include -#include -#endif - -#include "minissdpc.h" -#include "miniupnpc.h" - -#include "codelength.h" - -struct UPNPDev * -getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) -{ - struct UPNPDev * tmp; - struct UPNPDev * devlist = NULL; - unsigned char buffer[2048]; - ssize_t n; - unsigned char * p; - unsigned char * url; - unsigned int i; - unsigned int urlsize, stsize, usnsize, l; - int s; - struct sockaddr_un addr; - - s = socket(AF_UNIX, SOCK_STREAM, 0); - if(s < 0) - { - /*syslog(LOG_ERR, "socket(unix): %m");*/ - perror("socket(unix)"); - return NULL; - } - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); - /* TODO : check if we need to handle the EINTR */ - if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) - { - /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ - close(s); - return NULL; - } - stsize = strlen(devtype); - buffer[0] = 1; /* request type 1 : request devices/services by type */ - p = buffer + 1; - l = stsize; CODELENGTH(l, p); - if(p + stsize > buffer + sizeof(buffer)) - { - /* devtype is too long ! */ - close(s); - return NULL; - } - memcpy(p, devtype, stsize); - p += stsize; - if(write(s, buffer, p - buffer) < 0) - { - /*syslog(LOG_ERR, "write(): %m");*/ - perror("minissdpc.c: write()"); - close(s); - return NULL; - } - n = read(s, buffer, sizeof(buffer)); - if(n<=0) - { - perror("minissdpc.c: read()"); - close(s); - return NULL; - } - p = buffer + 1; - for(i = 0; i < buffer[0]; i++) - { - if(p+2>=buffer+sizeof(buffer)) - break; - DECODELENGTH(urlsize, p); - if(p+urlsize+2>=buffer+sizeof(buffer)) - break; - url = p; - p += urlsize; - DECODELENGTH(stsize, p); - if(p+stsize+2>=buffer+sizeof(buffer)) - break; - tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); - tmp->pNext = devlist; - tmp->descURL = tmp->buffer; - tmp->st = tmp->buffer + 1 + urlsize; - memcpy(tmp->buffer, url, urlsize); - tmp->buffer[urlsize] = '\0'; - memcpy(tmp->buffer + urlsize + 1, p, stsize); - p += stsize; - tmp->buffer[urlsize+1+stsize] = '\0'; - devlist = tmp; - /* added for compatibility with recent versions of MiniSSDPd - * >= 2007/12/19 */ - DECODELENGTH(usnsize, p); - p += usnsize; - if(p>buffer + sizeof(buffer)) - break; - } - close(s); - return devlist; -} - diff --git a/third-party/miniupnp/minissdpc.h b/third-party/miniupnp/minissdpc.h deleted file mode 100644 index 915b0026f..000000000 --- a/third-party/miniupnp/minissdpc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2005-2007 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINISSDPC_H_INCLUDED -#define MINISSDPC_H_INCLUDED - -struct UPNPDev * -getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); - -#endif - diff --git a/third-party/miniupnp/miniupnpc.c b/third-party/miniupnp/miniupnpc.c deleted file mode 100644 index 82e753507..000000000 --- a/third-party/miniupnp/miniupnpc.c +++ /dev/null @@ -1,1046 +0,0 @@ -/* $Id: miniupnpc.c,v 1.117 2014/01/31 14:19:13 nanard Exp $ */ -/* Project : miniupnp - * Web : http://miniupnp.free.fr/ - * Author : Thomas BERNARD - * copyright (c) 2005-2014 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENSE file. */ -#define __EXTENSIONS__ 1 -#if !defined(__APPLE__) && !defined(__sun) -#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__) -#ifndef __cplusplus -#define _XOPEN_SOURCE 600 -#endif -#endif -#ifndef __BSD_VISIBLE -#define __BSD_VISIBLE 1 -#endif -#endif - -#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) -#define HAS_IP_MREQN -#endif - -#include -#include -#include -#ifdef _WIN32 -/* Win32 Specific includes and defines */ -#include -#include -#include -#include -#define snprintf _snprintf -#define strdup _strdup -#ifndef strncasecmp -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define strncasecmp _memicmp -#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#define strncasecmp memicmp -#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#endif /* #ifndef strncasecmp */ -#define MAXHOSTNAMELEN 64 -#else /* #ifdef _WIN32 */ -/* Standard POSIX includes */ -#include -#if defined(__amigaos__) && !defined(__amigaos4__) -/* Amiga OS 3 specific stuff */ -#define socklen_t int -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#if !defined(__amigaos__) && !defined(__amigaos4__) -#include -#endif -#include -#include -#define closesocket close -#endif /* #else _WIN32 */ -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT -#include -#endif -#if defined(__amigaos__) || defined(__amigaos4__) -/* Amiga OS specific stuff */ -#define TIMEVAL struct timeval -#endif - - -#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) -/* Several versions of glibc don't define this structure, define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ -struct ip_mreqn -{ - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_address; /* local IP address of interface */ - int imr_ifindex; /* Interface index */ -}; -#endif - -#include "miniupnpc.h" -#include "minissdpc.h" -#include "miniwget.h" -#include "minisoap.h" -#include "minixml.h" -#include "upnpcommands.h" -#include "connecthostport.h" -#include "receivedata.h" - -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -#define SOAPPREFIX "s" -#define SERVICEPREFIX "u" -#define SERVICEPREFIX2 'u' - -/* root description parsing */ -LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) -{ - struct xmlparser parser; - /* xmlparser object */ - parser.xmlstart = buffer; - parser.xmlsize = bufsize; - parser.data = data; - parser.starteltfunc = IGDstartelt; - parser.endeltfunc = IGDendelt; - parser.datafunc = IGDdata; - parser.attfunc = 0; - parsexml(&parser); -#ifdef DEBUG - printIGD(data); -#endif -} - -/* simpleUPnPcommand2 : - * not so simple ! - * return values : - * pointer - OK - * NULL - error */ -static char * simpleUPnPcommand2(int s, const char * url, const char * service, - const char * action, struct UPNParg * args, - int * bufsize, const char * httpversion) -{ - char hostname[MAXHOSTNAMELEN+1]; - unsigned short port = 0; - char * path; - char soapact[128]; - char soapbody[2048]; - char * buf; - int n; - - *bufsize = 0; - snprintf(soapact, sizeof(soapact), "%s#%s", service, action); - if(args==NULL) - { - /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), - "\r\n" - "<" SOAPPREFIX ":Envelope " - "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " - SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" - "<" SOAPPREFIX ":Body>" - "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" - "" - "" - "\r\n", action, service, action); - } - else - { - char * p; - const char * pe, * pv; - int soapbodylen; - soapbodylen = snprintf(soapbody, sizeof(soapbody), - "\r\n" - "<" SOAPPREFIX ":Envelope " - "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " - SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" - "<" SOAPPREFIX ":Body>" - "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", - action, service); - p = soapbody + soapbodylen; - while(args->elt) - { - /* check that we are never overflowing the string... */ - if(soapbody + sizeof(soapbody) <= p + 100) - { - /* we keep a margin of at least 100 bytes */ - return NULL; - } - *(p++) = '<'; - pe = args->elt; - while(*pe) - *(p++) = *(pe++); - *(p++) = '>'; - if((pv = args->val)) - { - while(*pv) - *(p++) = *(pv++); - } - *(p++) = '<'; - *(p++) = '/'; - pe = args->elt; - while(*pe) - *(p++) = *(pe++); - *(p++) = '>'; - args++; - } - *(p++) = '<'; - *(p++) = '/'; - *(p++) = SERVICEPREFIX2; - *(p++) = ':'; - pe = action; - while(*pe) - *(p++) = *(pe++); - strncpy(p, ">\r\n", - soapbody + sizeof(soapbody) - p); - } - if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; - if(s < 0) { - s = connecthostport(hostname, port, 0); - if(s < 0) { - /* failed to connect */ - return NULL; - } - } - - n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); - if(n<=0) { -#ifdef DEBUG - printf("Error sending SOAP request\n"); -#endif - closesocket(s); - return NULL; - } - - buf = getHTTPResponse(s, bufsize); -#ifdef DEBUG - if(*bufsize > 0 && buf) - { - printf("SOAP Response :\n%.*s\n", *bufsize, buf); - } -#endif - closesocket(s); - return buf; -} - -/* simpleUPnPcommand : - * not so simple ! - * return values : - * pointer - OK - * NULL - error */ -char * simpleUPnPcommand(int s, const char * url, const char * service, - const char * action, struct UPNParg * args, - int * bufsize) -{ - char * buf; - -#if 1 - buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); -#else - buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); - if (!buf || *bufsize == 0) - { -#if DEBUG - printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); -#endif - buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); - } -#endif - return buf; -} - -/* parseMSEARCHReply() - * the last 4 arguments are filled during the parsing : - * - location/locationsize : "location:" field of the SSDP reply packet - * - st/stsize : "st:" field of the SSDP reply packet. - * The strings are NOT null terminated */ -static void -parseMSEARCHReply(const char * reply, int size, - const char * * location, int * locationsize, - const char * * st, int * stsize) -{ - int a, b, i; - i = 0; - a = i; /* start of the line */ - b = 0; /* end of the "header" (position of the colon) */ - while(isin6_family = AF_INET6; - if(sameport) - p->sin6_port = htons(PORT); - 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); - p->sin_addr.s_addr = INADDR_ANY; - } -#ifdef _WIN32 -/* This code could help us to use the right Network interface for - * SSDP multicast traffic */ -/* Get IP associated with the index given in the ip_forward struct - * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ - if(!ipv6 - && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { - DWORD dwRetVal = 0; - PMIB_IPADDRTABLE pIPAddrTable; - DWORD dwSize = 0; -#ifdef DEBUG - IN_ADDR IPAddr; -#endif - int i; -#ifdef DEBUG - printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); -#endif - pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); - if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { - free(pIPAddrTable); - pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); - } - if(pIPAddrTable) { - dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); -#ifdef DEBUG - printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); -#endif - for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { -#ifdef DEBUG - printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); - IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; - printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); - IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; - printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); - IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; - printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); - printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); - printf("\tType and State[%d]:", i); - printf("\n"); -#endif - if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { - /* Set the address of this interface to be used */ - struct in_addr mc_if; - memset(&mc_if, 0, sizeof(mc_if)); - mc_if.s_addr = pIPAddrTable->table[i].dwAddr; - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { - PRINT_SOCKET_ERROR("setsockopt"); - } - ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; -#ifndef DEBUG - break; -#endif - } - } - free(pIPAddrTable); - pIPAddrTable = NULL; - } - } -#endif - -#ifdef _WIN32 - if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) -#else - if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) -#endif - { - if(error) - *error = UPNPDISCOVER_SOCKET_ERROR; - PRINT_SOCKET_ERROR("setsockopt"); - return NULL; - } - - if(multicastif) - { - if(ipv6) { -#if !defined(_WIN32) - /* according to MSDN, if_nametoindex() is supported since - * MS Windows Vista and MS Windows Server 2008. - * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ - unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ - if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } -#else -#ifdef DEBUG - printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); -#endif -#endif - } else { - struct in_addr mc_if; - mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ - if(mc_if.s_addr != INADDR_NONE) - { - ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } - } else { -#ifdef HAS_IP_MREQN - /* was not an ip address, try with an interface name */ - struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ - memset(&reqn, 0, sizeof(struct ip_mreqn)); - reqn.imr_ifindex = if_nametoindex(multicastif); - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } -#else -#ifdef DEBUG - printf("Setting of multicast interface not supported with interface name.\n"); -#endif -#endif - } - } - } - - /* Before sending the packed, we first "bind" in order to be able - * to receive the response */ - if (bind(sudp, (const struct sockaddr *)&sockudp_r, - ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) - { - if(error) - *error = UPNPDISCOVER_SOCKET_ERROR; - PRINT_SOCKET_ERROR("bind"); - closesocket(sudp); - return NULL; - } - - if(error) - *error = UPNPDISCOVER_SUCCESS; - /* Calculating maximum response time in seconds */ - mx = ((unsigned int)delay) / 1000u; - if(mx == 0) { - mx = 1; - delay = 1000; - } - /* receiving SSDP response packet */ - for(n = 0; deviceList[deviceIndex]; deviceIndex++) - { - if(n == 0) - { - /* sending the SSDP M-SEARCH packet */ - n = snprintf(bufr, sizeof(bufr), - MSearchMsgFmt, - ipv6 ? - (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") - : UPNP_MCAST_ADDR, - deviceList[deviceIndex], mx); -#ifdef DEBUG - printf("Sending %s", bufr); -#endif -#ifdef NO_GETADDRINFO - /* the following code is not using getaddrinfo */ - /* emission */ - memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); - if(ipv6) { - struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; - p->sin6_family = AF_INET6; - p->sin6_port = htons(PORT); - inet_pton(AF_INET6, - linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, - &(p->sin6_addr)); - } else { - struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; - p->sin_family = AF_INET; - p->sin_port = htons(PORT); - p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); - } - n = sendto(sudp, bufr, n, 0, - &sockudp_w, - ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - if (n < 0) { - if(error) - *error = UPNPDISCOVER_SOCKET_ERROR; - PRINT_SOCKET_ERROR("sendto"); - break; - } -#else /* #ifdef NO_GETADDRINFO */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ - hints.ai_socktype = SOCK_DGRAM; - /*hints.ai_flags = */ - if ((rv = getaddrinfo(ipv6 - ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) - : UPNP_MCAST_ADDR, - XSTR(PORT), &hints, &servinfo)) != 0) { - if(error) - *error = UPNPDISCOVER_SOCKET_ERROR; -#ifdef _WIN32 - fprintf(stderr, "getaddrinfo() failed: %d\n", rv); -#else - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); -#endif - break; - } - for(p = servinfo; p; p = p->ai_next) { - n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); - if (n < 0) { -#ifdef DEBUG - char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; - if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, - sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); - } -#endif - PRINT_SOCKET_ERROR("sendto"); - continue; - } - } - freeaddrinfo(servinfo); - if(n < 0) { - if(error) - *error = UPNPDISCOVER_SOCKET_ERROR; - break; - } -#endif /* #ifdef NO_GETADDRINFO */ - } - /* Waiting for SSDP REPLY packet to M-SEARCH */ - n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); - if (n < 0) { - /* error */ - if(error) - *error = UPNPDISCOVER_SOCKET_ERROR; - break; - } else if (n == 0) { - /* no data or Time Out */ - if (devlist) { - /* no more device type to look for... */ - if(error) - *error = UPNPDISCOVER_SUCCESS; - break; - } - if(ipv6) { - if(linklocal) { - linklocal = 0; - --deviceIndex; - } else { - linklocal = 1; - } - } - } else { - const char * descURL=NULL; - int urlsize=0; - const char * st=NULL; - int stsize=0; - /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */ - parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); - if(st&&descURL) - { -#ifdef DEBUG - printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", - stsize, st, urlsize, descURL); -#endif - for(tmp=devlist; tmp; tmp = tmp->pNext) { - if(memcmp(tmp->descURL, descURL, urlsize) == 0 && - tmp->descURL[urlsize] == '\0' && - memcmp(tmp->st, st, stsize) == 0 && - tmp->st[stsize] == '\0') - break; - } - /* at the exit of the loop above, tmp is null if - * no duplicate device was found */ - if(tmp) - continue; - tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); - if(!tmp) { - /* memory allocation error */ - if(error) - *error = UPNPDISCOVER_MEMORY_ERROR; - break; - } - tmp->pNext = devlist; - tmp->descURL = tmp->buffer; - tmp->st = tmp->buffer + 1 + urlsize; - memcpy(tmp->buffer, descURL, urlsize); - tmp->buffer[urlsize] = '\0'; - memcpy(tmp->buffer + urlsize + 1, st, stsize); - tmp->buffer[urlsize+1+stsize] = '\0'; - tmp->scope_id = scope_id; - devlist = tmp; - } - } - } - closesocket(sudp); - return devlist; -} - -/* freeUPNPDevlist() should be used to - * free the chained list returned by upnpDiscover() */ -LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist) -{ - struct UPNPDev * next; - while(devlist) - { - next = devlist->pNext; - free(devlist); - devlist = next; - } -} - -static void -url_cpy_or_cat(char * dst, const char * src, int n) -{ - if( (src[0] == 'h') - &&(src[1] == 't') - &&(src[2] == 't') - &&(src[3] == 'p') - &&(src[4] == ':') - &&(src[5] == '/') - &&(src[6] == '/')) - { - strncpy(dst, src, n); - } - else - { - int l = strlen(dst); - if(src[0] != '/') - dst[l++] = '/'; - if(l<=n) - strncpy(dst + l, src, n - l); - } -} - -/* Prepare the Urls for usage... - */ -LIBSPEC void -GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, - const char * descURL, unsigned int scope_id) -{ - char * p; - int n1, n2, n3, n4; -#ifdef IF_NAMESIZE - char ifname[IF_NAMESIZE]; -#else - char scope_str[8]; -#endif - - n1 = strlen(data->urlbase); - if(n1==0) - n1 = strlen(descURL); - if(scope_id != 0) { -#ifdef IF_NAMESIZE - if(if_indextoname(scope_id, ifname)) { - n1 += 3 + strlen(ifname); /* 3 == strlen(%25) */ - } -#else - /* under windows, scope is numerical */ - snprintf(scope_str, sizeof(scope_str), "%u", scope_id); -#endif - } - n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */ - n2 = n1; n3 = n1; n4 = n1; - n1 += strlen(data->first.scpdurl); - n2 += strlen(data->first.controlurl); - n3 += strlen(data->CIF.controlurl); - n4 += strlen(data->IPv6FC.controlurl); - - /* allocate memory to store URLs */ - urls->ipcondescURL = (char *)malloc(n1); - urls->controlURL = (char *)malloc(n2); - urls->controlURL_CIF = (char *)malloc(n3); - urls->controlURL_6FC = (char *)malloc(n4); - - /* strdup descURL */ - urls->rootdescURL = strdup(descURL); - - /* get description of WANIPConnection */ - if(data->urlbase[0] != '\0') - strncpy(urls->ipcondescURL, data->urlbase, n1); - else - strncpy(urls->ipcondescURL, descURL, n1); - p = strchr(urls->ipcondescURL+7, '/'); - if(p) p[0] = '\0'; - if(scope_id != 0) { - if(0 == memcmp(urls->ipcondescURL, "http://[fe80:", 13)) { - /* this is a linklocal IPv6 address */ - p = strchr(urls->ipcondescURL, ']'); - if(p) { - /* insert %25 into URL */ -#ifdef IF_NAMESIZE - memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); - memcpy(p, "%25", 3); - memcpy(p + 3, ifname, strlen(ifname)); -#else - memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); - memcpy(p, "%25", 3); - memcpy(p + 3, scope_str, strlen(scope_str)); -#endif - } - } - } - strncpy(urls->controlURL, urls->ipcondescURL, n2); - strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3); - strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4); - - url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1); - - url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2); - - url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3); - - url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4); - -#ifdef DEBUG - printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL, - (unsigned)strlen(urls->ipcondescURL), n1); - printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL, - (unsigned)strlen(urls->controlURL), n2); - printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF, - (unsigned)strlen(urls->controlURL_CIF), n3); - printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC, - (unsigned)strlen(urls->controlURL_6FC), n4); -#endif -} - -LIBSPEC void -FreeUPNPUrls(struct UPNPUrls * urls) -{ - if(!urls) - return; - free(urls->controlURL); - urls->controlURL = 0; - free(urls->ipcondescURL); - urls->ipcondescURL = 0; - free(urls->controlURL_CIF); - urls->controlURL_CIF = 0; - free(urls->controlURL_6FC); - urls->controlURL_6FC = 0; - free(urls->rootdescURL); - urls->rootdescURL = 0; -} - -int -UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) -{ - char status[64]; - unsigned int uptime; - status[0] = '\0'; - UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, - status, &uptime, NULL); - if(0 == strcmp("Connected", status)) - { - return 1; - } - else - return 0; -} - - -/* UPNP_GetValidIGD() : - * return values : - * -1 = Internal error - * 0 = NO IGD found - * 1 = A valid connected IGD has been found - * 2 = A valid IGD has been found but it reported as - * not connected - * 3 = an UPnP device has been found but was not recognized as an IGD - * - * In any positive non zero return case, the urls and data structures - * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to - * free allocated memory. - */ -LIBSPEC int -UPNP_GetValidIGD(struct UPNPDev * devlist, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen) -{ - struct xml_desc { - char * xml; - int size; - int is_igd; - } * desc = NULL; - struct UPNPDev * dev; - int ndev = 0; - int i; - int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ - int n_igd = 0; - char extIpAddr[16]; - if(!devlist) - { -#ifdef DEBUG - printf("Empty devlist\n"); -#endif - return 0; - } - /* counting total number of devices in the list */ - for(dev = devlist; dev; dev = dev->pNext) - ndev++; - if(ndev > 0) - { - desc = calloc(ndev, sizeof(struct xml_desc)); - if(!desc) - return -1; /* memory allocation error */ - } - /* Step 1 : downloading descriptions and testing type */ - for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) - { - /* we should choose an internet gateway device. - * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ - desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), - lanaddr, lanaddrlen, - dev->scope_id); -#ifdef DEBUG - if(!desc[i].xml) - { - printf("error getting XML description %s\n", dev->descURL); - } -#endif - if(desc[i].xml) - { - memset(data, 0, sizeof(struct IGDdatas)); - memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(desc[i].xml, desc[i].size, data); - if(0==strcmp(data->CIF.servicetype, - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) - { - desc[i].is_igd = 1; - n_igd++; - } - } - } - /* iterate the list to find a device depending on state */ - for(state = 1; state <= 3; state++) - { - for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) - { - if(desc[i].xml) - { - memset(data, 0, sizeof(struct IGDdatas)); - memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(desc[i].xml, desc[i].size, data); - if(desc[i].is_igd || state >= 3 ) - { - GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); - - /* in state 2 and 3 we dont test if device is connected ! */ - if(state >= 2) - goto free_and_return; -#ifdef DEBUG - printf("UPNPIGD_IsConnected(%s) = %d\n", - urls->controlURL, - UPNPIGD_IsConnected(urls, data)); -#endif - /* checks that status is connected AND there is a external IP address assigned */ - if(UPNPIGD_IsConnected(urls, data) - && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) - goto free_and_return; - FreeUPNPUrls(urls); - if(data->second.servicetype[0] != '\0') { -#ifdef DEBUG - printf("We tried %s, now we try %s !\n", - data->first.servicetype, data->second.servicetype); -#endif - /* swaping WANPPPConnection and WANIPConnection ! */ - memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); - memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); - memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); - GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); -#ifdef DEBUG - printf("UPNPIGD_IsConnected(%s) = %d\n", - urls->controlURL, - UPNPIGD_IsConnected(urls, data)); -#endif - if(UPNPIGD_IsConnected(urls, data) - && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) - goto free_and_return; - FreeUPNPUrls(urls); - } - } - memset(data, 0, sizeof(struct IGDdatas)); - } - } - } - state = 0; -free_and_return: - if(desc) { - for(i = 0; i < ndev; i++) { - if(desc[i].xml) { - free(desc[i].xml); - } - } - free(desc); - } - return state; -} - -/* UPNP_GetIGDFromUrl() - * Used when skipping the discovery process. - * return value : - * 0 - Not ok - * 1 - OK */ -int -UPNP_GetIGDFromUrl(const char * rootdescurl, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen) -{ - char * descXML; - int descXMLsize = 0; - descXML = miniwget_getaddr(rootdescurl, &descXMLsize, - lanaddr, lanaddrlen, 0); - if(descXML) { - memset(data, 0, sizeof(struct IGDdatas)); - memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(descXML, descXMLsize, data); - free(descXML); - descXML = NULL; - GetUPNPUrls(urls, data, rootdescurl, 0); - return 1; - } else { - return 0; - } -} - diff --git a/third-party/miniupnp/miniupnpc.h b/third-party/miniupnp/miniupnpc.h deleted file mode 100644 index 3af109cf1..000000000 --- a/third-party/miniupnp/miniupnpc.h +++ /dev/null @@ -1,130 +0,0 @@ -/* $Id: miniupnpc.h,v 1.35 2014/01/31 13:26:34 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ - * Author: Thomas Bernard - * Copyright (c) 2005-2012 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINIUPNPC_H_INCLUDED -#define MINIUPNPC_H_INCLUDED - -#include "declspec.h" -#include "igd_desc_parse.h" - -/* error codes : */ -#define UPNPDISCOVER_SUCCESS (0) -#define UPNPDISCOVER_UNKNOWN_ERROR (-1) -#define UPNPDISCOVER_SOCKET_ERROR (-101) -#define UPNPDISCOVER_MEMORY_ERROR (-102) - -/* versions : */ -#define MINIUPNPC_VERSION "1.9.20140401" -#define MINIUPNPC_API_VERSION 10 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structures definitions : */ -struct UPNParg { const char * elt; const char * val; }; - -char * -simpleUPnPcommand(int, const char *, const char *, - const char *, struct UPNParg *, - int *); - -struct UPNPDev { - struct UPNPDev * pNext; - char * descURL; - char * st; - unsigned int scope_id; - char buffer[2]; -}; - -/* upnpDiscover() - * discover UPnP devices on the network. - * The discovered devices are returned as a chained list. - * It is up to the caller to free the list with freeUPNPDevlist(). - * 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. */ -LIBSPEC struct UPNPDev * -upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, - int * error); -/* freeUPNPDevlist() - * free list returned by upnpDiscover() */ -LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); - -/* parserootdesc() : - * parse root XML description of a UPnP device and fill the IGDdatas - * structure. */ -LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); - -/* structure used to get fast access to urls - * controlURL: controlURL of the WANIPConnection - * ipcondescURL: url of the description of the WANIPConnection - * controlURL_CIF: controlURL of the WANCommonInterfaceConfig - * controlURL_6FC: controlURL of the WANIPv6FirewallControl - */ -struct UPNPUrls { - char * controlURL; - char * ipcondescURL; - char * controlURL_CIF; - char * controlURL_6FC; - char * rootdescURL; -}; - -/* UPNP_GetValidIGD() : - * return values : - * 0 = NO IGD found - * 1 = A valid connected IGD has been found - * 2 = A valid IGD has been found but it reported as - * not connected - * 3 = an UPnP device has been found but was not recognized as an IGD - * - * In any non zero return case, the urls and data structures - * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to - * free allocated memory. - */ -LIBSPEC int -UPNP_GetValidIGD(struct UPNPDev * devlist, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); - -/* UPNP_GetIGDFromUrl() - * Used when skipping the discovery process. - * return value : - * 0 - Not ok - * 1 - OK */ -LIBSPEC int -UPNP_GetIGDFromUrl(const char * rootdescurl, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); - -LIBSPEC void -GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, - const char *, unsigned int); - -LIBSPEC void -FreeUPNPUrls(struct UPNPUrls *); - -/* return 0 or 1 */ -LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/third-party/miniupnp/miniupnpcstrings.h.in b/third-party/miniupnp/miniupnpcstrings.h.in deleted file mode 100644 index c32e3a133..000000000 --- a/third-party/miniupnp/miniupnpcstrings.h.in +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: miniupnpcstrings.h.in,v 1.5 2012/10/16 16:48:26 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2005-2011 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINIUPNPCSTRINGS_H_INCLUDED -#define MINIUPNPCSTRINGS_H_INCLUDED - -#define OS_STRING "OS/version" -#define MINIUPNPC_VERSION_STRING "version" - -#endif - diff --git a/third-party/miniupnp/miniupnpctypes.h b/third-party/miniupnp/miniupnpctypes.h deleted file mode 100644 index 591c32fb6..000000000 --- a/third-party/miniupnp/miniupnpctypes.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ -/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org - * Author : Thomas Bernard - * Copyright (c) 2011 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided within this distribution */ -#ifndef MINIUPNPCTYPES_H_INCLUDED -#define MINIUPNPCTYPES_H_INCLUDED - -#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) -#define UNSIGNED_INTEGER unsigned long long -#define STRTOUI strtoull -#else -#define UNSIGNED_INTEGER unsigned int -#define STRTOUI strtoul -#endif - -#endif - diff --git a/third-party/miniupnp/miniwget.c b/third-party/miniupnp/miniwget.c deleted file mode 100644 index 813db9324..000000000 --- a/third-party/miniupnp/miniwget.c +++ /dev/null @@ -1,575 +0,0 @@ -/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */ -/* Project : miniupnp - * Website : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2014 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include -#include -#include -#include -#ifdef _WIN32 -#include -#include -#include -#define MAXHOSTNAMELEN 64 -#define MIN(x,y) (((x)<(y))?(x):(y)) -#define snprintf _snprintf -#define socklen_t int -#ifndef strncasecmp -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define strncasecmp _memicmp -#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#define strncasecmp memicmp -#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#endif /* #ifndef strncasecmp */ -#else /* #ifdef _WIN32 */ -#include -#include -#if defined(__amigaos__) && !defined(__amigaos4__) -#define socklen_t int -#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#include -#include -#include -#include -#define closesocket close -#endif /* #else _WIN32 */ -#if defined(__sun) || defined(sun) -#define MIN(x,y) (((x)<(y))?(x):(y)) -#endif - -#include "miniupnpcstrings.h" -#include "miniwget.h" -#include "connecthostport.h" -#include "receivedata.h" - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -/* - * Read a HTTP response from a socket. - * Process Content-Length and Transfer-encoding headers. - * return a pointer to the content buffer, which length is saved - * to the length parameter. - */ -void * -getHTTPResponse(int s, int * size) -{ - char buf[2048]; - int n; - int endofheaders = 0; - int chunked = 0; - int content_length = -1; - unsigned int chunksize = 0; - unsigned int bytestocopy = 0; - /* buffers : */ - char * header_buf; - unsigned int header_buf_len = 2048; - unsigned int header_buf_used = 0; - char * content_buf; - unsigned int content_buf_len = 2048; - unsigned int content_buf_used = 0; - char chunksize_buf[32]; - unsigned int chunksize_buf_index; - - header_buf = malloc(header_buf_len); - content_buf = malloc(content_buf_len); - chunksize_buf[0] = '\0'; - chunksize_buf_index = 0; - - while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) - { - if(endofheaders == 0) - { - int i; - int linestart=0; - int colon=0; - int valuestart=0; - if(header_buf_used + n > header_buf_len) { - header_buf = realloc(header_buf, header_buf_used + n); - header_buf_len = header_buf_used + n; - } - memcpy(header_buf + header_buf_used, buf, n); - header_buf_used += n; - /* search for CR LF CR LF (end of headers) - * recognize also LF LF */ - i = 0; - while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { - if(header_buf[i] == '\r') { - i++; - if(header_buf[i] == '\n') { - i++; - if(i < (int)header_buf_used && header_buf[i] == '\r') { - i++; - if(i < (int)header_buf_used && header_buf[i] == '\n') { - endofheaders = i+1; - } - } - } - } else if(header_buf[i] == '\n') { - i++; - if(header_buf[i] == '\n') { - endofheaders = i+1; - } - } - i++; - } - if(endofheaders == 0) - continue; - /* parse header lines */ - for(i = 0; i < endofheaders - 1; i++) { - if(colon <= linestart && header_buf[i]==':') - { - colon = i; - while(i < (endofheaders-1) - && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) - i++; - valuestart = i + 1; - } - /* detecting end of line */ - else if(header_buf[i]=='\r' || header_buf[i]=='\n') - { - if(colon > linestart && valuestart > colon) - { -#ifdef DEBUG - printf("header='%.*s', value='%.*s'\n", - colon-linestart, header_buf+linestart, - i-valuestart, header_buf+valuestart); -#endif - if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) - { - content_length = atoi(header_buf+valuestart); -#ifdef DEBUG - printf("Content-Length: %d\n", content_length); -#endif - } - else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) - && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) - { -#ifdef DEBUG - printf("chunked transfer-encoding!\n"); -#endif - chunked = 1; - } - } - while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n')) - i++; - linestart = i; - colon = linestart; - valuestart = 0; - } - } - /* copy the remaining of the received data back to buf */ - n = header_buf_used - endofheaders; - memcpy(buf, header_buf + endofheaders, n); - /* if(headers) */ - } - if(endofheaders) - { - /* content */ - if(chunked) - { - int i = 0; - while(i < n) - { - if(chunksize == 0) - { - /* reading chunk size */ - if(chunksize_buf_index == 0) { - /* skipping any leading CR LF */ - if(i= '0' - && chunksize_buf[j] <= '9') - chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); - else - chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); - } - chunksize_buf[0] = '\0'; - chunksize_buf_index = 0; - i++; - } else { - /* not finished to get chunksize */ - continue; - } -#ifdef DEBUG - printf("chunksize = %u (%x)\n", chunksize, chunksize); -#endif - if(chunksize == 0) - { -#ifdef DEBUG - printf("end of HTTP content - %d %d\n", i, n); - /*printf("'%.*s'\n", n-i, buf+i);*/ -#endif - goto end_of_stream; - } - } - bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); - if((content_buf_used + bytestocopy) > content_buf_len) - { - if(content_length >= (int)(content_buf_used + bytestocopy)) { - content_buf_len = content_length; - } else { - content_buf_len = content_buf_used + bytestocopy; - } - content_buf = (char *)realloc((void *)content_buf, - content_buf_len); - } - memcpy(content_buf + content_buf_used, buf + i, bytestocopy); - content_buf_used += bytestocopy; - i += bytestocopy; - chunksize -= bytestocopy; - } - } - else - { - /* not chunked */ - if(content_length > 0 - && (int)(content_buf_used + n) > content_length) { - /* skipping additional bytes */ - n = content_length - content_buf_used; - } - if(content_buf_used + n > content_buf_len) - { - if(content_length >= (int)(content_buf_used + n)) { - content_buf_len = content_length; - } else { - content_buf_len = content_buf_used + n; - } - content_buf = (char *)realloc((void *)content_buf, - content_buf_len); - } - memcpy(content_buf + content_buf_used, buf, n); - content_buf_used += n; - } - } - /* use the Content-Length header value if available */ - if(content_length > 0 && (int)content_buf_used >= content_length) - { -#ifdef DEBUG - printf("End of HTTP content\n"); -#endif - break; - } - } -end_of_stream: - free(header_buf); header_buf = NULL; - *size = content_buf_used; - if(content_buf_used == 0) - { - free(content_buf); - content_buf = NULL; - } - return content_buf; -} - -/* miniwget3() : - * do all the work. - * Return NULL if something failed. */ -static void * -miniwget3(const char * host, - unsigned short port, const char * path, - int * size, char * addr_str, int addr_str_len, - const char * httpversion, unsigned int scope_id) -{ - char buf[2048]; - int s; - int n; - int len; - int sent; - void * content; - - *size = 0; - s = connecthostport(host, port, scope_id); - if(s < 0) - return NULL; - - /* get address for caller ! */ - if(addr_str) - { - struct sockaddr_storage saddr; - socklen_t saddrlen; - - saddrlen = sizeof(saddr); - if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) - { - perror("getsockname"); - } - else - { -#if defined(__amigaos__) && !defined(__amigaos4__) - /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); - * But his function make a string with the port : nn.nn.nn.nn:port */ -/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), - NULL, addr_str, (DWORD *)&addr_str_len)) - { - printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); - }*/ - /* the following code is only compatible with ip v4 addresses */ - strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); -#else -#if 0 - if(saddr.sa_family == AF_INET6) { - inet_ntop(AF_INET6, - &(((struct sockaddr_in6 *)&saddr)->sin6_addr), - addr_str, addr_str_len); - } else { - inet_ntop(AF_INET, - &(((struct sockaddr_in *)&saddr)->sin_addr), - addr_str, addr_str_len); - } -#endif - /* getnameinfo return ip v6 address with the scope identifier - * such as : 2a01:e35:8b2b:7330::%4281128194 */ - n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, - addr_str, addr_str_len, - NULL, 0, - NI_NUMERICHOST | NI_NUMERICSERV); - if(n != 0) { -#ifdef _WIN32 - fprintf(stderr, "getnameinfo() failed : %d\n", n); -#else - fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); -#endif - } -#endif - } -#ifdef DEBUG - printf("address miniwget : %s\n", addr_str); -#endif - } - - len = snprintf(buf, sizeof(buf), - "GET %s HTTP/%s\r\n" - "Host: %s:%d\r\n" - "Connection: Close\r\n" - "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" - - "\r\n", - path, httpversion, host, port); - sent = 0; - /* sending the HTTP request */ - while(sent < len) - { - n = send(s, buf+sent, len-sent, 0); - if(n < 0) - { - perror("send"); - closesocket(s); - return NULL; - } - else - { - sent += n; - } - } - content = getHTTPResponse(s, size); - closesocket(s); - return content; -} - -/* miniwget2() : - * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ -static void * -miniwget2(const char * host, - unsigned short port, const char * path, - int * size, char * addr_str, int addr_str_len, - unsigned int scope_id) -{ - char * respbuffer; - -#if 1 - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.1", scope_id); -#else - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.0", scope_id); - if (*size == 0) - { -#ifdef DEBUG - printf("Retrying with HTTP/1.1\n"); -#endif - free(respbuffer); - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.1", scope_id); - } -#endif - return respbuffer; -} - - - - -/* parseURL() - * arguments : - * url : source string not modified - * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) - * port : port (destination) - * path : pointer to the path part of the URL - * - * Return values : - * 0 - Failure - * 1 - Success */ -int -parseURL(const char * url, - char * hostname, unsigned short * port, - char * * path, unsigned int * scope_id) -{ - char * p1, *p2, *p3; - if(!url) - return 0; - p1 = strstr(url, "://"); - if(!p1) - return 0; - p1 += 3; - if( (url[0]!='h') || (url[1]!='t') - ||(url[2]!='t') || (url[3]!='p')) - return 0; - memset(hostname, 0, MAXHOSTNAMELEN + 1); - if(*p1 == '[') - { - /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ - char * scope; - scope = strchr(p1, '%'); - p2 = strchr(p1, ']'); - if(p2 && scope && scope < p2 && scope_id) { - /* parse scope */ -#ifdef IF_NAMESIZE - char tmp[IF_NAMESIZE]; - int l; - scope++; - /* "%25" is just '%' in URL encoding */ - if(scope[0] == '2' && scope[1] == '5') - scope += 2; /* skip "25" */ - l = p2 - scope; - if(l >= IF_NAMESIZE) - l = IF_NAMESIZE - 1; - memcpy(tmp, scope, l); - tmp[l] = '\0'; - *scope_id = if_nametoindex(tmp); - if(*scope_id == 0) { - *scope_id = (unsigned int)strtoul(tmp, NULL, 10); - } -#else - /* under windows, scope is numerical */ - char tmp[8]; - int l; - scope++; - /* "%25" is just '%' in URL encoding */ - if(scope[0] == '2' && scope[1] == '5') - scope += 2; /* skip "25" */ - l = p2 - scope; - if(l >= sizeof(tmp)) - l = sizeof(tmp) - 1; - memcpy(tmp, scope, l); - tmp[l] = '\0'; - *scope_id = (unsigned int)strtoul(tmp, NULL, 10); -#endif - } - p3 = strchr(p1, '/'); - if(p2 && p3) - { - p2++; - strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); - if(*p2 == ':') - { - *port = 0; - p2++; - while( (*p2 >= '0') && (*p2 <= '9')) - { - *port *= 10; - *port += (unsigned short)(*p2 - '0'); - p2++; - } - } - else - { - *port = 80; - } - *path = p3; - return 1; - } - } - p2 = strchr(p1, ':'); - p3 = strchr(p1, '/'); - if(!p3) - return 0; - if(!p2 || (p2>p3)) - { - strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); - *port = 80; - } - else - { - strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); - *port = 0; - p2++; - while( (*p2 >= '0') && (*p2 <= '9')) - { - *port *= 10; - *port += (unsigned short)(*p2 - '0'); - p2++; - } - } - *path = p3; - return 1; -} - -void * -miniwget(const char * url, int * size, unsigned int scope_id) -{ - unsigned short port; - char * path; - /* protocol://host:port/chemin */ - char hostname[MAXHOSTNAMELEN+1]; - *size = 0; - if(!parseURL(url, hostname, &port, &path, &scope_id)) - return NULL; -#ifdef DEBUG - printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", - hostname, port, path, scope_id); -#endif - return miniwget2(hostname, port, path, size, 0, 0, scope_id); -} - -void * -miniwget_getaddr(const char * url, int * size, - char * addr, int addrlen, unsigned int scope_id) -{ - unsigned short port; - char * path; - /* protocol://host:port/path */ - char hostname[MAXHOSTNAMELEN+1]; - *size = 0; - if(addr) - addr[0] = '\0'; - if(!parseURL(url, hostname, &port, &path, &scope_id)) - return NULL; -#ifdef DEBUG - printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", - hostname, port, path, scope_id); -#endif - return miniwget2(hostname, port, path, size, addr, addrlen, scope_id); -} - diff --git a/third-party/miniupnp/miniwget.h b/third-party/miniupnp/miniwget.h deleted file mode 100644 index 31bcea322..000000000 --- a/third-party/miniupnp/miniwget.h +++ /dev/null @@ -1,30 +0,0 @@ -/* $Id: miniwget.h,v 1.8 2012/09/27 15:42:10 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2012 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef MINIWGET_H_INCLUDED -#define MINIWGET_H_INCLUDED - -#include "declspec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -LIBSPEC void * getHTTPResponse(int s, int * size); - -LIBSPEC void * miniwget(const char *, int *, unsigned int); - -LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int); - -int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/third-party/miniupnp/minixml.c b/third-party/miniupnp/minixml.c deleted file mode 100644 index 3e201ec2c..000000000 --- a/third-party/miniupnp/minixml.c +++ /dev/null @@ -1,229 +0,0 @@ -/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */ -/* minixml.c : the minimum size a xml parser can be ! */ -/* Project : miniupnp - * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author : Thomas Bernard - -Copyright (c) 2005-2014, Thomas BERNARD -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. - * The name of the author may not 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 OWNER 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. -*/ -#include -#include "minixml.h" - -/* parseatt : used to parse the argument list - * return 0 (false) in case of success and -1 (true) if the end - * of the xmlbuffer is reached. */ -static int parseatt(struct xmlparser * p) -{ - const char * attname; - int attnamelen; - const char * attvalue; - int attvaluelen; - while(p->xml < p->xmlend) - { - if(*p->xml=='/' || *p->xml=='>') - return 0; - if( !IS_WHITE_SPACE(*p->xml) ) - { - char sep; - attname = p->xml; - attnamelen = 0; - while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) - { - attnamelen++; p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - while(*(p->xml++) != '=') - { - if(p->xml >= p->xmlend) - return -1; - } - while(IS_WHITE_SPACE(*p->xml)) - { - p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - sep = *p->xml; - if(sep=='\'' || sep=='\"') - { - p->xml++; - if(p->xml >= p->xmlend) - return -1; - attvalue = p->xml; - attvaluelen = 0; - while(*p->xml != sep) - { - attvaluelen++; p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - } - else - { - attvalue = p->xml; - attvaluelen = 0; - while( !IS_WHITE_SPACE(*p->xml) - && *p->xml != '>' && *p->xml != '/') - { - attvaluelen++; p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - } - /*printf("%.*s='%.*s'\n", - attnamelen, attname, attvaluelen, attvalue);*/ - if(p->attfunc) - p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); - } - p->xml++; - } - return -1; -} - -/* parseelt parse the xml stream and - * call the callback functions when needed... */ -static void parseelt(struct xmlparser * p) -{ - int i; - const char * elementname; - while(p->xml < (p->xmlend - 1)) - { - if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); - p->xml += 3; - } - else if((p->xml)[0]=='<' && (p->xml)[1]!='?') - { - i = 0; elementname = ++p->xml; - while( !IS_WHITE_SPACE(*p->xml) - && (*p->xml!='>') && (*p->xml!='/') - ) - { - i++; p->xml++; - if (p->xml >= p->xmlend) - return; - /* to ignore namespace : */ - if(*p->xml==':') - { - i = 0; - elementname = ++p->xml; - } - } - if(i>0) - { - if(p->starteltfunc) - p->starteltfunc(p->data, elementname, i); - if(parseatt(p)) - return; - if(*p->xml!='/') - { - const char * data; - i = 0; data = ++p->xml; - if (p->xml >= p->xmlend) - return; - while( IS_WHITE_SPACE(*p->xml) ) - { - i++; p->xml++; - if (p->xml >= p->xmlend) - return; - } - if(memcmp(p->xml, "xml += 9; - data = p->xml; - i = 0; - while(memcmp(p->xml, "]]>", 3) != 0) - { - i++; p->xml++; - if ((p->xml + 3) >= p->xmlend) - return; - } - if(i>0 && p->datafunc) - p->datafunc(p->data, data, i); - while(*p->xml!='<') - { - p->xml++; - if (p->xml >= p->xmlend) - return; - } - } - else - { - while(*p->xml!='<') - { - i++; p->xml++; - if ((p->xml + 1) >= p->xmlend) - return; - } - if(i>0 && p->datafunc && *(p->xml + 1) == '/') - p->datafunc(p->data, data, i); - } - } - } - else if(*p->xml == '/') - { - i = 0; elementname = ++p->xml; - if (p->xml >= p->xmlend) - return; - while((*p->xml != '>')) - { - i++; p->xml++; - if (p->xml >= p->xmlend) - return; - } - if(p->endeltfunc) - p->endeltfunc(p->data, elementname, i); - p->xml++; - } - } - else - { - p->xml++; - } - } -} - -/* the parser must be initialized before calling this function */ -void parsexml(struct xmlparser * parser) -{ - parser->xml = parser->xmlstart; - parser->xmlend = parser->xmlstart + parser->xmlsize; - parseelt(parser); -} - - diff --git a/third-party/miniupnp/minixml.h b/third-party/miniupnp/minixml.h deleted file mode 100644 index 9f43aa48c..000000000 --- a/third-party/miniupnp/minixml.h +++ /dev/null @@ -1,37 +0,0 @@ -/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ -/* minimal xml parser - * - * Project : miniupnp - * Website : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef MINIXML_H_INCLUDED -#define MINIXML_H_INCLUDED -#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) - -/* if a callback function pointer is set to NULL, - * the function is not called */ -struct xmlparser { - const char *xmlstart; - const char *xmlend; - const char *xml; /* pointer to current character */ - int xmlsize; - void * data; - void (*starteltfunc) (void *, const char *, int); - void (*endeltfunc) (void *, const char *, int); - void (*datafunc) (void *, const char *, int); - void (*attfunc) (void *, const char *, int, const char *, int); -}; - -/* parsexml() - * the xmlparser structure must be initialized before the call - * the following structure members have to be initialized : - * xmlstart, xmlsize, data, *func - * xml is for internal usage, xmlend is computed automatically */ -void parsexml(struct xmlparser *); - -#endif - diff --git a/third-party/miniupnp/portlistingparse.c b/third-party/miniupnp/portlistingparse.c deleted file mode 100644 index 19e3054eb..000000000 --- a/third-party/miniupnp/portlistingparse.c +++ /dev/null @@ -1,159 +0,0 @@ -/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2011 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ -#include -#include -#include "portlistingparse.h" -#include "minixml.h" - -/* list of the elements */ -static const struct { - const portMappingElt code; - const char * const str; -} elements[] = { - { PortMappingEntry, "PortMappingEntry"}, - { NewRemoteHost, "NewRemoteHost"}, - { NewExternalPort, "NewExternalPort"}, - { NewProtocol, "NewProtocol"}, - { NewInternalPort, "NewInternalPort"}, - { NewInternalClient, "NewInternalClient"}, - { NewEnabled, "NewEnabled"}, - { NewDescription, "NewDescription"}, - { NewLeaseTime, "NewLeaseTime"}, - { PortMappingEltNone, NULL} -}; - -/* Helper function */ -static UNSIGNED_INTEGER -atoui(const char * p, int l) -{ - UNSIGNED_INTEGER r = 0; - while(l > 0 && *p) - { - if(*p >= '0' && *p <= '9') - r = r*10 + (*p - '0'); - else - break; - p++; - l--; - } - return r; -} - -/* Start element handler */ -static void -startelt(void * d, const char * name, int l) -{ - int i; - struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; - pdata->curelt = PortMappingEltNone; - for(i = 0; elements[i].str; i++) - { - if(memcmp(name, elements[i].str, l) == 0) - { - pdata->curelt = elements[i].code; - break; - } - } - if(pdata->curelt == PortMappingEntry) - { - struct PortMapping * pm; - pm = calloc(1, sizeof(struct PortMapping)); - LIST_INSERT_HEAD( &(pdata->head), pm, entries); - } -} - -/* End element handler */ -static void -endelt(void * d, const char * name, int l) -{ - struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; - (void)name; - (void)l; - pdata->curelt = PortMappingEltNone; -} - -/* Data handler */ -static void -data(void * d, const char * data, int l) -{ - struct PortMapping * pm; - struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; - pm = pdata->head.lh_first; - if(!pm) - return; - if(l > 63) - l = 63; - switch(pdata->curelt) - { - case NewRemoteHost: - memcpy(pm->remoteHost, data, l); - pm->remoteHost[l] = '\0'; - break; - case NewExternalPort: - pm->externalPort = (unsigned short)atoui(data, l); - break; - case NewProtocol: - if(l > 3) - l = 3; - memcpy(pm->protocol, data, l); - pm->protocol[l] = '\0'; - break; - case NewInternalPort: - pm->internalPort = (unsigned short)atoui(data, l); - break; - case NewInternalClient: - memcpy(pm->internalClient, data, l); - pm->internalClient[l] = '\0'; - break; - case NewEnabled: - pm->enabled = (unsigned char)atoui(data, l); - break; - case NewDescription: - memcpy(pm->description, data, l); - pm->description[l] = '\0'; - break; - case NewLeaseTime: - pm->leaseTime = atoui(data, l); - break; - default: - break; - } -} - - -/* Parse the PortMappingList XML document for IGD version 2 - */ -void -ParsePortListing(const char * buffer, int bufsize, - struct PortMappingParserData * pdata) -{ - struct xmlparser parser; - - memset(pdata, 0, sizeof(struct PortMappingParserData)); - LIST_INIT(&(pdata->head)); - /* init xmlparser */ - parser.xmlstart = buffer; - parser.xmlsize = bufsize; - parser.data = pdata; - parser.starteltfunc = startelt; - parser.endeltfunc = endelt; - parser.datafunc = data; - parser.attfunc = 0; - parsexml(&parser); -} - -void -FreePortListing(struct PortMappingParserData * pdata) -{ - struct PortMapping * pm; - while((pm = pdata->head.lh_first) != NULL) - { - LIST_REMOVE(pm, entries); - free(pm); - } -} - diff --git a/third-party/miniupnp/portlistingparse.h b/third-party/miniupnp/portlistingparse.h deleted file mode 100644 index bafa2a47c..000000000 --- a/third-party/miniupnp/portlistingparse.h +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id: portlistingparse.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2011-2012 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ -#ifndef PORTLISTINGPARSE_H_INCLUDED -#define PORTLISTINGPARSE_H_INCLUDED - -#include "declspec.h" -/* for the definition of UNSIGNED_INTEGER */ -#include "miniupnpctypes.h" - -#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__) -#include "bsdqueue.h" -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* sample of PortMappingEntry : - - 202.233.2.1 - 2345 - TCP - 2345 - 192.168.1.137 - 1 - dooom - 345 - - */ -typedef enum { PortMappingEltNone, - PortMappingEntry, NewRemoteHost, - NewExternalPort, NewProtocol, - NewInternalPort, NewInternalClient, - NewEnabled, NewDescription, - NewLeaseTime } portMappingElt; - -struct PortMapping { - LIST_ENTRY(PortMapping) entries; - UNSIGNED_INTEGER leaseTime; - unsigned short externalPort; - unsigned short internalPort; - char remoteHost[64]; - char internalClient[64]; - char description[64]; - char protocol[4]; - unsigned char enabled; -}; - -struct PortMappingParserData { - LIST_HEAD(portmappinglisthead, PortMapping) head; - portMappingElt curelt; -}; - -LIBSPEC void -ParsePortListing(const char * buffer, int bufsize, - struct PortMappingParserData * pdata); - -LIBSPEC void -FreePortListing(struct PortMappingParserData * pdata); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/third-party/miniupnp/receivedata.c b/third-party/miniupnp/receivedata.c deleted file mode 100644 index 9599556ab..000000000 --- a/third-party/miniupnp/receivedata.c +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id: receivedata.c,v 1.5 2013/10/07 09:48:36 nanard Exp $ */ -/* Project : miniupnp - * Website : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2011-2012 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include -#ifdef _WIN32 -#include -#include -#else -#include -#if defined(__amigaos__) && !defined(__amigaos4__) -#define socklen_t int -#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#include -#if !defined(__amigaos__) && !defined(__amigaos4__) -#include -#endif -#include -#define MINIUPNPC_IGNORE_EINTR -#endif - -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -#include "receivedata.h" - -int -receivedata(int socket, - char * data, int length, - int timeout, unsigned int * scope_id) -{ -#ifdef MINIUPNPC_GET_SRC_ADDR -#ifdef DEBUG - /* to shut up valgrind about uninit value */ - struct sockaddr_storage src_addr = {0}; -#else - struct sockaddr_storage src_addr; -#endif - socklen_t src_addr_len = sizeof(src_addr); -#endif - int n; -#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) - /* using poll */ - struct pollfd fds[1]; /* for the poll */ -#ifdef MINIUPNPC_IGNORE_EINTR - do { -#endif - fds[0].fd = socket; - fds[0].events = POLLIN; - n = poll(fds, 1, timeout); -#ifdef MINIUPNPC_IGNORE_EINTR - } while(n < 0 && errno == EINTR); -#endif - if(n < 0) { - PRINT_SOCKET_ERROR("poll"); - return -1; - } else if(n == 0) { - /* timeout */ - return 0; - } -#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ - /* using select under _WIN32 and amigaos */ - fd_set socketSet; - TIMEVAL timeval; - FD_ZERO(&socketSet); - FD_SET(socket, &socketSet); - timeval.tv_sec = timeout / 1000; - timeval.tv_usec = (timeout % 1000) * 1000; - n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); - if(n < 0) { - PRINT_SOCKET_ERROR("select"); - return -1; - } else if(n == 0) { - return 0; - } -#endif -#ifdef MINIUPNPC_GET_SRC_ADDR - n = recvfrom(socket, data, length, 0, - (struct sockaddr *)&src_addr, &src_addr_len); -#else - n = recv(socket, data, length, 0); -#endif - if(n<0) { - PRINT_SOCKET_ERROR("recv"); - } -#ifdef MINIUPNPC_GET_SRC_ADDR - if (src_addr.ss_family == AF_INET6) { - const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr; -#ifdef DEBUG - printf("scope_id=%u\n", src_addr6->sin6_scope_id); -#endif - if(scope_id) - *scope_id = src_addr6->sin6_scope_id; - } -#endif - return n; -} - - diff --git a/third-party/miniupnp/receivedata.h b/third-party/miniupnp/receivedata.h deleted file mode 100644 index 0520a11d3..000000000 --- a/third-party/miniupnp/receivedata.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2011-2012 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef RECEIVEDATA_H_INCLUDED -#define RECEIVEDATA_H_INCLUDED - -/* Reads data from the specified socket. - * Returns the number of bytes read if successful, zero if no bytes were - * read or if we timed out. Returns negative if there was an error. */ -int receivedata(int socket, - char * data, int length, - int timeout, unsigned int * scope_id); - -#endif - diff --git a/third-party/miniupnp/updateminiupnpcstrings.sh b/third-party/miniupnp/updateminiupnpcstrings.sh deleted file mode 100755 index 0639da6a7..000000000 --- a/third-party/miniupnp/updateminiupnpcstrings.sh +++ /dev/null @@ -1,54 +0,0 @@ -#! /bin/sh -# $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $ -# project miniupnp : http://miniupnp.free.fr/ -# (c) 2009 Thomas Bernard - -VERSION_FILE="$1" -TEMPLATE_FILE="$2" -FILE="$3" -TMPFILE="$3.tmp" - -# detecting the OS name and version -OS_NAME=`uname -s` -OS_VERSION=`uname -r` -if [ -f /etc/debian_version ]; then - OS_NAME=Debian - OS_VERSION=`cat /etc/debian_version` -fi -# use lsb_release (Linux Standard Base) when available -LSB_RELEASE=`which lsb_release` -if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then - OS_NAME=`${LSB_RELEASE} -i -s` - OS_VERSION=`${LSB_RELEASE} -r -s` - case $OS_NAME in - Debian) - #OS_VERSION=`${LSB_RELEASE} -c -s` - ;; - Ubuntu) - #OS_VERSION=`${LSB_RELEASE} -c -s` - ;; - esac -fi - -# on AmigaOS 3, uname -r returns "unknown", so we use uname -v -if [ "$OS_NAME" = "AmigaOS" ]; then - if [ "$OS_VERSION" = "unknown" ]; then - OS_VERSION=`uname -v` - fi -fi - -echo "Detected OS [$OS_NAME] version [$OS_VERSION]" -MINIUPNPC_VERSION=`cat "${VERSION_FILE}"` -echo "MiniUPnPc version [${MINIUPNPC_VERSION}]" - -EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|" -#echo $EXPR -test -f "${FILE}.in" -echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE." -sed -e "$EXPR" < "$TEMPLATE_FILE" > "$TMPFILE" - -EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|" -echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE." -sed -e "$EXPR" < "$TMPFILE" > "$FILE" -rm "$TMPFILE" - diff --git a/third-party/miniupnp/upnpcommands.c b/third-party/miniupnp/upnpcommands.c deleted file mode 100644 index ad6978105..000000000 --- a/third-party/miniupnp/upnpcommands.c +++ /dev/null @@ -1,1098 +0,0 @@ -/* $Id: upnpcommands.c,v 1.42 2014/01/31 13:18:25 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2012 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#include -#include -#include -#include "upnpcommands.h" -#include "miniupnpc.h" -#include "portlistingparse.h" - -static UNSIGNED_INTEGER -my_atoui(const char * s) -{ - return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; -} - -/* - * */ -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesSent(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalBytesSent", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* - * */ -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesReceived(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalBytesReceived", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* - * */ -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsSent(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalPacketsSent", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* - * */ -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsReceived(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalPacketsReceived", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* UPNP_GetStatusInfo() call the corresponding UPNP method - * returns the current status and uptime */ -LIBSPEC int -UPNP_GetStatusInfo(const char * controlURL, - const char * servicetype, - char * status, - unsigned int * uptime, - char * lastconnerror) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * p; - char * up; - char * err; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!status && !uptime) - return UPNPCOMMAND_INVALID_ARGS; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetStatusInfo", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - up = GetValueFromNameValueList(&pdata, "NewUptime"); - p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); - err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); - if(p && up) - ret = UPNPCOMMAND_SUCCESS; - - if(status) { - if(p){ - strncpy(status, p, 64 ); - status[63] = '\0'; - }else - status[0]= '\0'; - } - - if(uptime) { - if(up) - sscanf(up,"%u",uptime); - else - uptime = 0; - } - - if(lastconnerror) { - if(err) { - strncpy(lastconnerror, err, 64 ); - lastconnerror[63] = '\0'; - } else - lastconnerror[0] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - -/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method - * returns the connection type */ -LIBSPEC int -UPNP_GetConnectionTypeInfo(const char * controlURL, - const char * servicetype, - char * connectionType) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!connectionType) - return UPNPCOMMAND_INVALID_ARGS; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetConnectionTypeInfo", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewConnectionType"); - /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ - /* PossibleConnectionTypes will have several values.... */ - if(p) { - strncpy(connectionType, p, 64 ); - connectionType[63] = '\0'; - ret = UPNPCOMMAND_SUCCESS; - } else - connectionType[0] = '\0'; - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - -/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. - * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. - * One of the values can be null - * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only - * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */ -LIBSPEC int -UPNP_GetLinkLayerMaxBitRates(const char * controlURL, - const char * servicetype, - unsigned int * bitrateDown, - unsigned int * bitrateUp) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - char * down; - char * up; - char * p; - - if(!bitrateDown && !bitrateUp) - return UPNPCOMMAND_INVALID_ARGS; - - /* shouldn't we use GetCommonLinkProperties ? */ - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetCommonLinkProperties", 0, &bufsize))) { - /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ - /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ - down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); - up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); - /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ - /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ - if(down && up) - ret = UPNPCOMMAND_SUCCESS; - - if(bitrateDown) { - if(down) - sscanf(down,"%u",bitrateDown); - else - *bitrateDown = 0; - } - - if(bitrateUp) { - if(up) - sscanf(up,"%u",bitrateUp); - else - *bitrateUp = 0; - } - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - - -/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. - * if the third arg is not null the value is copied to it. - * at least 16 bytes must be available - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR Either an UPnP error code or an unknown error. - * - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - */ -LIBSPEC int -UPNP_GetExternalIPAddress(const char * controlURL, - const char * servicetype, - char * extIpAdd) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!extIpAdd || !controlURL || !servicetype) - return UPNPCOMMAND_INVALID_ARGS; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetExternalIPAddress", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ - p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); - if(p) { - strncpy(extIpAdd, p, 16 ); - extIpAdd[15] = '\0'; - ret = UPNPCOMMAND_SUCCESS; - } else - extIpAdd[0] = '\0'; - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - return ret; -} - -LIBSPEC int -UPNP_AddPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration) -{ - struct UPNParg * AddPortMappingArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!inPort || !inClient || !proto || !extPort) - return UPNPCOMMAND_INVALID_ARGS; - - AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); - AddPortMappingArgs[0].elt = "NewRemoteHost"; - AddPortMappingArgs[0].val = remoteHost; - AddPortMappingArgs[1].elt = "NewExternalPort"; - AddPortMappingArgs[1].val = extPort; - AddPortMappingArgs[2].elt = "NewProtocol"; - AddPortMappingArgs[2].val = proto; - AddPortMappingArgs[3].elt = "NewInternalPort"; - AddPortMappingArgs[3].val = inPort; - AddPortMappingArgs[4].elt = "NewInternalClient"; - AddPortMappingArgs[4].val = inClient; - AddPortMappingArgs[5].elt = "NewEnabled"; - AddPortMappingArgs[5].val = "1"; - AddPortMappingArgs[6].elt = "NewPortMappingDescription"; - AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; - AddPortMappingArgs[7].elt = "NewLeaseDuration"; - AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "AddPortMapping", AddPortMappingArgs, - &bufsize))) { - free(AddPortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - /*buffer[bufsize] = '\0';*/ - /*puts(buffer);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) { - /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } else { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(AddPortMappingArgs); - return ret; -} - -LIBSPEC int -UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, - const char * extPort, const char * proto, - const char * remoteHost) -{ - /*struct NameValueParserData pdata;*/ - struct UPNParg * DeletePortMappingArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!extPort || !proto) - return UPNPCOMMAND_INVALID_ARGS; - - DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); - DeletePortMappingArgs[0].elt = "NewRemoteHost"; - DeletePortMappingArgs[0].val = remoteHost; - DeletePortMappingArgs[1].elt = "NewExternalPort"; - DeletePortMappingArgs[1].val = extPort; - DeletePortMappingArgs[2].elt = "NewProtocol"; - DeletePortMappingArgs[2].val = proto; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "DeletePortMapping", - DeletePortMappingArgs, &bufsize))) { - free(DeletePortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } else { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(DeletePortMappingArgs); - return ret; -} - -LIBSPEC int -UPNP_GetGenericPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * index, - char * extPort, - char * intClient, - char * intPort, - char * protocol, - char * desc, - char * enabled, - char * rHost, - char * duration) -{ - struct NameValueParserData pdata; - struct UPNParg * GetPortMappingArgs; - char * buffer; - int bufsize; - char * p; - int r = UPNPCOMMAND_UNKNOWN_ERROR; - if(!index) - return UPNPCOMMAND_INVALID_ARGS; - intClient[0] = '\0'; - intPort[0] = '\0'; - GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); - GetPortMappingArgs[0].elt = "NewPortMappingIndex"; - GetPortMappingArgs[0].val = index; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetGenericPortMappingEntry", - GetPortMappingArgs, &bufsize))) { - free(GetPortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); - if(p && rHost) - { - strncpy(rHost, p, 64); - rHost[63] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewExternalPort"); - if(p && extPort) - { - strncpy(extPort, p, 6); - extPort[5] = '\0'; - r = UPNPCOMMAND_SUCCESS; - } - p = GetValueFromNameValueList(&pdata, "NewProtocol"); - if(p && protocol) - { - strncpy(protocol, p, 4); - protocol[3] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewInternalClient"); - if(p && intClient) - { - strncpy(intClient, p, 16); - intClient[15] = '\0'; - r = 0; - } - p = GetValueFromNameValueList(&pdata, "NewInternalPort"); - if(p && intPort) - { - strncpy(intPort, p, 6); - intPort[5] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewEnabled"); - if(p && enabled) - { - strncpy(enabled, p, 4); - enabled[3] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); - if(p && desc) - { - strncpy(desc, p, 80); - desc[79] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); - if(p && duration) - { - strncpy(duration, p, 16); - duration[15] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - r = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &r); - } - ClearNameValueList(&pdata); - free(GetPortMappingArgs); - return r; -} - -LIBSPEC int -UPNP_GetPortMappingNumberOfEntries(const char * controlURL, - const char * servicetype, - unsigned int * numEntries) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char* p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetPortMappingNumberOfEntries", 0, - &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } -#ifdef DEBUG - DisplayNameValueList(buffer, bufsize); -#endif - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); - if(numEntries && p) { - *numEntries = 0; - sscanf(p, "%u", numEntries); - ret = UPNPCOMMAND_SUCCESS; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - return ret; -} - -/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping - * the result is returned in the intClient and intPort strings - * please provide 16 and 6 bytes of data */ -LIBSPEC int -UPNP_GetSpecificPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * extPort, - const char * proto, - const char * remoteHost, - char * intClient, - char * intPort, - char * desc, - char * enabled, - char * leaseDuration) -{ - struct NameValueParserData pdata; - struct UPNParg * GetPortMappingArgs; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!intPort || !intClient || !extPort || !proto) - return UPNPCOMMAND_INVALID_ARGS; - - GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); - GetPortMappingArgs[0].elt = "NewRemoteHost"; - GetPortMappingArgs[0].val = remoteHost; - GetPortMappingArgs[1].elt = "NewExternalPort"; - GetPortMappingArgs[1].val = extPort; - GetPortMappingArgs[2].elt = "NewProtocol"; - GetPortMappingArgs[2].val = proto; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetSpecificPortMappingEntry", - GetPortMappingArgs, &bufsize))) { - free(GetPortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "NewInternalClient"); - if(p) { - strncpy(intClient, p, 16); - intClient[15] = '\0'; - ret = UPNPCOMMAND_SUCCESS; - } else - intClient[0] = '\0'; - - p = GetValueFromNameValueList(&pdata, "NewInternalPort"); - if(p) { - strncpy(intPort, p, 6); - intPort[5] = '\0'; - } else - intPort[0] = '\0'; - - p = GetValueFromNameValueList(&pdata, "NewEnabled"); - if(p && enabled) { - strncpy(enabled, p, 4); - enabled[3] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); - if(p && desc) { - strncpy(desc, p, 80); - desc[79] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); - if(p && leaseDuration) - { - strncpy(leaseDuration, p, 16); - leaseDuration[15] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - free(GetPortMappingArgs); - return ret; -} - -/* UPNP_GetListOfPortMappings() - * - * Possible UPNP Error codes : - * 606 Action not Authorized - * 730 PortMappingNotFound - no port mapping is found in the specified range. - * 733 InconsistantParameters - NewStartPort and NewEndPort values are not - * consistent. - */ -LIBSPEC int -UPNP_GetListOfPortMappings(const char * controlURL, - const char * servicetype, - const char * startPort, - const char * endPort, - const char * protocol, - const char * numberOfPorts, - struct PortMappingParserData * data) -{ - struct NameValueParserData pdata; - struct UPNParg * GetListOfPortMappingsArgs; - const char * p; - char * buffer; - int bufsize; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!startPort || !endPort || !protocol) - return UPNPCOMMAND_INVALID_ARGS; - - GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); - GetListOfPortMappingsArgs[0].elt = "NewStartPort"; - GetListOfPortMappingsArgs[0].val = startPort; - GetListOfPortMappingsArgs[1].elt = "NewEndPort"; - GetListOfPortMappingsArgs[1].val = endPort; - GetListOfPortMappingsArgs[2].elt = "NewProtocol"; - GetListOfPortMappingsArgs[2].val = protocol; - GetListOfPortMappingsArgs[3].elt = "NewManage"; - GetListOfPortMappingsArgs[3].val = "1"; - GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; - GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetListOfPortMappings", - GetListOfPortMappingsArgs, &bufsize))) { - free(GetListOfPortMappingsArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - free(GetListOfPortMappingsArgs); - - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ - /*if(p) { - printf("NewPortListing : %s\n", p); - }*/ - /*printf("NewPortListing(%d chars) : %s\n", - pdata.portListingLength, pdata.portListing);*/ - if(pdata.portListing) - { - /*struct PortMapping * pm; - int i = 0;*/ - ParsePortListing(pdata.portListing, pdata.portListingLength, - data); - ret = UPNPCOMMAND_SUCCESS; - /* - for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) - { - printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", - i, pm->protocol, pm->externalPort, pm->internalClient, - pm->internalPort, - pm->description, pm->remoteHost); - i++; - } - */ - /*FreePortListing(&data);*/ - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - - /*printf("%.*s", bufsize, buffer);*/ - - return ret; -} - -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -LIBSPEC int -UPNP_GetFirewallStatus(const char * controlURL, - const char * servicetype, - int * firewallEnabled, - int * inboundPinholeAllowed) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * fe, *ipa, *p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!firewallEnabled || !inboundPinholeAllowed) - return UPNPCOMMAND_INVALID_ARGS; - - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetFirewallStatus", 0, &bufsize); - if(!buffer) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); - ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); - if(ipa && fe) - ret = UPNPCOMMAND_SUCCESS; - if(fe) - *firewallEnabled = my_atoui(fe); - /*else - *firewallEnabled = 0;*/ - if(ipa) - *inboundPinholeAllowed = my_atoui(ipa); - /*else - *inboundPinholeAllowed = 0;*/ - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - -LIBSPEC int -UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - int * opTimeout) -{ - struct UPNParg * GetOutboundPinholeTimeoutArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - char * p; - int ret; - - if(!intPort || !intClient || !proto || !remotePort || !remoteHost) - return UPNPCOMMAND_INVALID_ARGS; - - GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); - GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; - GetOutboundPinholeTimeoutArgs[0].val = remoteHost; - GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; - GetOutboundPinholeTimeoutArgs[1].val = remotePort; - GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; - GetOutboundPinholeTimeoutArgs[2].val = proto; - GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; - GetOutboundPinholeTimeoutArgs[3].val = intPort; - GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; - GetOutboundPinholeTimeoutArgs[4].val = intClient; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); - if(p) - *opTimeout = my_atoui(p); - } - ClearNameValueList(&pdata); - free(GetOutboundPinholeTimeoutArgs); - return ret; -} - -LIBSPEC int -UPNP_AddPinhole(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - const char * leaseTime, - char * uniqueID) -{ - struct UPNParg * AddPinholeArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - char * p; - int ret; - - if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) - return UPNPCOMMAND_INVALID_ARGS; - - AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); - /* RemoteHost can be wilcarded */ - if(strncmp(remoteHost, "empty", 5)==0) - { - AddPinholeArgs[0].elt = "RemoteHost"; - AddPinholeArgs[0].val = ""; - } - else - { - AddPinholeArgs[0].elt = "RemoteHost"; - AddPinholeArgs[0].val = remoteHost; - } - AddPinholeArgs[1].elt = "RemotePort"; - AddPinholeArgs[1].val = remotePort; - AddPinholeArgs[2].elt = "Protocol"; - AddPinholeArgs[2].val = proto; - AddPinholeArgs[3].elt = "InternalPort"; - AddPinholeArgs[3].val = intPort; - if(strncmp(intClient, "empty", 5)==0) - { - AddPinholeArgs[4].elt = "InternalClient"; - AddPinholeArgs[4].val = ""; - } - else - { - AddPinholeArgs[4].elt = "InternalClient"; - AddPinholeArgs[4].val = intClient; - } - AddPinholeArgs[5].elt = "LeaseTime"; - AddPinholeArgs[5].val = leaseTime; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "AddPinhole", AddPinholeArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "UniqueID"); - if(p) - { - strncpy(uniqueID, p, 8); - uniqueID[7] = '\0'; - } - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(AddPinholeArgs); - return ret; -} - -LIBSPEC int -UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, - const char * uniqueID, - const char * leaseTime) -{ - struct UPNParg * UpdatePinholeArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!uniqueID || !leaseTime) - return UPNPCOMMAND_INVALID_ARGS; - - UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); - UpdatePinholeArgs[0].elt = "UniqueID"; - UpdatePinholeArgs[0].val = uniqueID; - UpdatePinholeArgs[1].elt = "NewLeaseTime"; - UpdatePinholeArgs[1].val = leaseTime; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "UpdatePinhole", UpdatePinholeArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(UpdatePinholeArgs); - return ret; -} - -LIBSPEC int -UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) -{ - /*struct NameValueParserData pdata;*/ - struct UPNParg * DeletePinholeArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!uniqueID) - return UPNPCOMMAND_INVALID_ARGS; - - DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); - DeletePinholeArgs[0].elt = "UniqueID"; - DeletePinholeArgs[0].val = uniqueID; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "DeletePinhole", DeletePinholeArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(DeletePinholeArgs); - return ret; -} - -LIBSPEC int -UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, - const char * uniqueID, int * isWorking) -{ - struct NameValueParserData pdata; - struct UPNParg * CheckPinholeWorkingArgs; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!uniqueID) - return UPNPCOMMAND_INVALID_ARGS; - - CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); - CheckPinholeWorkingArgs[0].elt = "UniqueID"; - CheckPinholeWorkingArgs[0].val = uniqueID; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "IsWorking"); - if(p) - { - *isWorking=my_atoui(p); - ret = UPNPCOMMAND_SUCCESS; - } - else - *isWorking = 0; - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - free(CheckPinholeWorkingArgs); - return ret; -} - -LIBSPEC int -UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, - const char * uniqueID, int * packets) -{ - struct NameValueParserData pdata; - struct UPNParg * GetPinholePacketsArgs; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!uniqueID) - return UPNPCOMMAND_INVALID_ARGS; - - GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); - GetPinholePacketsArgs[0].elt = "UniqueID"; - GetPinholePacketsArgs[0].val = uniqueID; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetPinholePackets", GetPinholePacketsArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "PinholePackets"); - if(p) - { - *packets=my_atoui(p); - ret = UPNPCOMMAND_SUCCESS; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - free(GetPinholePacketsArgs); - return ret; -} - - diff --git a/third-party/miniupnp/upnpcommands.h b/third-party/miniupnp/upnpcommands.h deleted file mode 100644 index 93d9f3dd4..000000000 --- a/third-party/miniupnp/upnpcommands.h +++ /dev/null @@ -1,293 +0,0 @@ -/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */ -/* Miniupnp project : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2014 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided within this distribution */ -#ifndef UPNPCOMMANDS_H_INCLUDED -#define UPNPCOMMANDS_H_INCLUDED - -#include "upnpreplyparse.h" -#include "portlistingparse.h" -#include "declspec.h" -#include "miniupnpctypes.h" - -/* MiniUPnPc return codes : */ -#define UPNPCOMMAND_SUCCESS (0) -#define UPNPCOMMAND_UNKNOWN_ERROR (-1) -#define UPNPCOMMAND_INVALID_ARGS (-2) -#define UPNPCOMMAND_HTTP_ERROR (-3) - -#ifdef __cplusplus -extern "C" { -#endif - -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesSent(const char * controlURL, - const char * servicetype); - -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesReceived(const char * controlURL, - const char * servicetype); - -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsSent(const char * controlURL, - const char * servicetype); - -LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsReceived(const char * controlURL, - const char * servicetype); - -/* UPNP_GetStatusInfo() - * status and lastconnerror are 64 byte buffers - * Return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -LIBSPEC int -UPNP_GetStatusInfo(const char * controlURL, - const char * servicetype, - char * status, - unsigned int * uptime, - char * lastconnerror); - -/* UPNP_GetConnectionTypeInfo() - * argument connectionType is a 64 character buffer - * Return Values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -LIBSPEC int -UPNP_GetConnectionTypeInfo(const char * controlURL, - const char * servicetype, - char * connectionType); - -/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. - * if the third arg is not null the value is copied to it. - * at least 16 bytes must be available - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR Either an UPnP error code or an unknown error. - * - * possible UPnP Errors : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. */ -LIBSPEC int -UPNP_GetExternalIPAddress(const char * controlURL, - const char * servicetype, - char * extIpAdd); - -/* UPNP_GetLinkLayerMaxBitRates() - * call WANCommonInterfaceConfig:1#GetCommonLinkProperties - * - * return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. */ -LIBSPEC int -UPNP_GetLinkLayerMaxBitRates(const char* controlURL, - const char* servicetype, - unsigned int * bitrateDown, - unsigned int * bitrateUp); - -/* UPNP_AddPortMapping() - * if desc is NULL, it will be defaulted to "libminiupnpc" - * remoteHost is usually NULL because IGD don't support it. - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR. Either an UPnP error code or an unknown error. - * - * List of possible UPnP errors for AddPortMapping : - * errorCode errorDescription (short) - Description (long) - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization and - * the sender was not authorized. - * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be - * wild-carded - * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded - * 718 ConflictInMappingEntry - The port mapping entry specified conflicts - * with a mapping assigned previously to another client - * 724 SamePortValuesRequired - Internal and External port values - * must be the same - * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports - * permanent lease times on port mappings - * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard - * and cannot be a specific IP address or DNS name - * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and - * cannot be a specific port value - * 728 NoPortMapsAvailable - There are not enough free ports available to - * complete port mapping. - * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed - * due to conflict with other mechanisms. - * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded - */ -LIBSPEC int -UPNP_AddPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration); - -/* UPNP_DeletePortMapping() - * Use same argument values as what was used for AddPortMapping(). - * remoteHost is usually NULL because IGD don't support it. - * Return Values : - * 0 : SUCCESS - * NON ZERO : error. Either an UPnP error code or an undefined error. - * - * List of possible UPnP errors for DeletePortMapping : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array */ -LIBSPEC int -UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, - const char * extPort, const char * proto, - const char * remoteHost); - -/* UPNP_GetPortMappingNumberOfEntries() - * not supported by all routers */ -LIBSPEC int -UPNP_GetPortMappingNumberOfEntries(const char* controlURL, - const char* servicetype, - unsigned int * num); - -/* UPNP_GetSpecificPortMappingEntry() - * retrieves an existing port mapping - * params : - * in extPort - * in proto - * in remoteHost - * out intClient (16 bytes) - * out intPort (6 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out leaseDuration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * List of possible UPnP errors for _GetSpecificPortMappingEntry : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array. - */ -LIBSPEC int -UPNP_GetSpecificPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * extPort, - const char * proto, - const char * remoteHost, - char * intClient, - char * intPort, - char * desc, - char * enabled, - char * leaseDuration); - -/* UPNP_GetGenericPortMappingEntry() - * params : - * in index - * out extPort (6 bytes) - * out intClient (16 bytes) - * out intPort (6 bytes) - * out protocol (4 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out rHost (64 bytes) - * out duration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * Possible UPNP Error codes : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds - */ -LIBSPEC int -UPNP_GetGenericPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * index, - char * extPort, - char * intClient, - char * intPort, - char * protocol, - char * desc, - char * enabled, - char * rHost, - char * duration); - -/* UPNP_GetListOfPortMappings() Available in IGD v2 - * - * - * Possible UPNP Error codes : - * 606 Action not Authorized - * 730 PortMappingNotFound - no port mapping is found in the specified range. - * 733 InconsistantParameters - NewStartPort and NewEndPort values are not - * consistent. - */ -LIBSPEC int -UPNP_GetListOfPortMappings(const char * controlURL, - const char * servicetype, - const char * startPort, - const char * endPort, - const char * protocol, - const char * numberOfPorts, - struct PortMappingParserData * data); - -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -LIBSPEC int -UPNP_GetFirewallStatus(const char * controlURL, - const char * servicetype, - int * firewallEnabled, - int * inboundPinholeAllowed); - -LIBSPEC int -UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - int * opTimeout); - -LIBSPEC int -UPNP_AddPinhole(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - const char * leaseTime, - char * uniqueID); - -LIBSPEC int -UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, - const char * uniqueID, - const char * leaseTime); - -LIBSPEC int -UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); - -LIBSPEC int -UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, - const char * uniqueID, int * isWorking); - -LIBSPEC int -UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, - const char * uniqueID, int * packets); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/third-party/miniupnp/upnpreplyparse.c b/third-party/miniupnp/upnpreplyparse.c deleted file mode 100644 index dafa26313..000000000 --- a/third-party/miniupnp/upnpreplyparse.c +++ /dev/null @@ -1,183 +0,0 @@ -/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ - -#include -#include -#include - -#include "upnpreplyparse.h" -#include "minixml.h" - -static void -NameValueParserStartElt(void * d, const char * name, int l) -{ - struct NameValueParserData * data = (struct NameValueParserData *)d; - data->topelt = 1; - if(l>63) - l = 63; - memcpy(data->curelt, name, l); - data->curelt[l] = '\0'; - data->cdata = NULL; - data->cdatalen = 0; -} - -static void -NameValueParserEndElt(void * d, const char * name, int l) -{ - struct NameValueParserData * data = (struct NameValueParserData *)d; - struct NameValue * nv; - (void)name; - (void)l; - if(!data->topelt) - return; - if(strcmp(data->curelt, "NewPortListing") != 0) - { - int l; - /* standard case. Limited to n chars strings */ - l = data->cdatalen; - nv = malloc(sizeof(struct NameValue)); - if(l>=(int)sizeof(nv->value)) - l = sizeof(nv->value) - 1; - strncpy(nv->name, data->curelt, 64); - nv->name[63] = '\0'; - if(data->cdata != NULL) - { - memcpy(nv->value, data->cdata, l); - nv->value[l] = '\0'; - } - else - { - nv->value[0] = '\0'; - } - LIST_INSERT_HEAD( &(data->head), nv, entries); - } - data->cdata = NULL; - data->cdatalen = 0; - data->topelt = 0; -} - -static void -NameValueParserGetData(void * d, const char * datas, int l) -{ - struct NameValueParserData * data = (struct NameValueParserData *)d; - if(strcmp(data->curelt, "NewPortListing") == 0) - { - /* specific case for NewPortListing which is a XML Document */ - data->portListing = malloc(l + 1); - if(!data->portListing) - { - /* malloc error */ - return; - } - memcpy(data->portListing, datas, l); - data->portListing[l] = '\0'; - data->portListingLength = l; - } - else - { - /* standard case. */ - data->cdata = datas; - data->cdatalen = l; - } -} - -void -ParseNameValue(const char * buffer, int bufsize, - struct NameValueParserData * data) -{ - struct xmlparser parser; - LIST_INIT(&(data->head)); - data->portListing = NULL; - data->portListingLength = 0; - /* init xmlparser object */ - parser.xmlstart = buffer; - parser.xmlsize = bufsize; - parser.data = data; - parser.starteltfunc = NameValueParserStartElt; - parser.endeltfunc = NameValueParserEndElt; - parser.datafunc = NameValueParserGetData; - parser.attfunc = 0; - parsexml(&parser); -} - -void -ClearNameValueList(struct NameValueParserData * pdata) -{ - struct NameValue * nv; - if(pdata->portListing) - { - free(pdata->portListing); - pdata->portListing = NULL; - pdata->portListingLength = 0; - } - while((nv = pdata->head.lh_first) != NULL) - { - LIST_REMOVE(nv, entries); - free(nv); - } -} - -char * -GetValueFromNameValueList(struct NameValueParserData * pdata, - const char * Name) -{ - struct NameValue * nv; - char * p = NULL; - for(nv = pdata->head.lh_first; - (nv != NULL) && (p == NULL); - nv = nv->entries.le_next) - { - if(strcmp(nv->name, Name) == 0) - p = nv->value; - } - return p; -} - -#if 0 -/* useless now that minixml ignores namespaces by itself */ -char * -GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, - const char * Name) -{ - struct NameValue * nv; - char * p = NULL; - char * pname; - for(nv = pdata->head.lh_first; - (nv != NULL) && (p == NULL); - nv = nv->entries.le_next) - { - pname = strrchr(nv->name, ':'); - if(pname) - pname++; - else - pname = nv->name; - if(strcmp(pname, Name)==0) - p = nv->value; - } - return p; -} -#endif - -/* debug all-in-one function - * do parsing then display to stdout */ -#ifdef DEBUG -void -DisplayNameValueList(char * buffer, int bufsize) -{ - struct NameValueParserData pdata; - struct NameValue * nv; - ParseNameValue(buffer, bufsize, &pdata); - for(nv = pdata.head.lh_first; - nv != NULL; - nv = nv->entries.le_next) - { - printf("%s = %s\n", nv->name, nv->value); - } - ClearNameValueList(&pdata); -} -#endif - diff --git a/third-party/miniupnp/upnpreplyparse.h b/third-party/miniupnp/upnpreplyparse.h deleted file mode 100644 index d4e37576a..000000000 --- a/third-party/miniupnp/upnpreplyparse.h +++ /dev/null @@ -1,69 +0,0 @@ -/* $Id: upnpreplyparse.h,v 1.17 2013/06/06 21:36:40 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ - -#ifndef UPNPREPLYPARSE_H_INCLUDED -#define UPNPREPLYPARSE_H_INCLUDED - -#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__) -#include "bsdqueue.h" -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct NameValue { - LIST_ENTRY(NameValue) entries; - char name[64]; - char value[128]; -}; - -struct NameValueParserData { - LIST_HEAD(listhead, NameValue) head; - char curelt[64]; - char * portListing; - int portListingLength; - int topelt; - const char * cdata; - int cdatalen; -}; - -/* ParseNameValue() */ -void -ParseNameValue(const char * buffer, int bufsize, - struct NameValueParserData * data); - -/* ClearNameValueList() */ -void -ClearNameValueList(struct NameValueParserData * pdata); - -/* GetValueFromNameValueList() */ -char * -GetValueFromNameValueList(struct NameValueParserData * pdata, - const char * Name); - -#if 0 -/* GetValueFromNameValueListIgnoreNS() */ -char * -GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, - const char * Name); -#endif - -/* DisplayNameValueList() */ -#ifdef DEBUG -void -DisplayNameValueList(char * buffer, int bufsize); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -