mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-20 17:00:49 +00:00
Clean out obsolete dependencies.
This commit is contained in:
parent
3c63f58532
commit
4df090469a
@ -1,68 +0,0 @@
|
||||
# Authors ordered by first contribution.
|
||||
Ryan Dahl <ry@tinyclouds.org>
|
||||
Jeremy Hinegardner <jeremy@hinegardner.org>
|
||||
Sergey Shepelev <temotor@gmail.com>
|
||||
Joe Damato <ice799@gmail.com>
|
||||
tomika <tomika_nospam@freemail.hu>
|
||||
Phoenix Sol <phoenix@burninglabs.com>
|
||||
Cliff Frey <cliff@meraki.com>
|
||||
Ewen Cheslack-Postava <ewencp@cs.stanford.edu>
|
||||
Santiago Gala <sgala@apache.org>
|
||||
Tim Becker <tim.becker@syngenio.de>
|
||||
Jeff Terrace <jterrace@gmail.com>
|
||||
Ben Noordhuis <info@bnoordhuis.nl>
|
||||
Nathan Rajlich <nathan@tootallnate.net>
|
||||
Mark Nottingham <mnot@mnot.net>
|
||||
Aman Gupta <aman@tmm1.net>
|
||||
Tim Becker <tim.becker@kuriositaet.de>
|
||||
Sean Cunningham <sean.cunningham@mandiant.com>
|
||||
Peter Griess <pg@std.in>
|
||||
Salman Haq <salman.haq@asti-usa.com>
|
||||
Cliff Frey <clifffrey@gmail.com>
|
||||
Jon Kolb <jon@b0g.us>
|
||||
Fouad Mardini <f.mardini@gmail.com>
|
||||
Paul Querna <pquerna@apache.org>
|
||||
Felix Geisendörfer <felix@debuggable.com>
|
||||
koichik <koichik@improvement.jp>
|
||||
Andre Caron <andre.l.caron@gmail.com>
|
||||
Ivo Raisr <ivosh@ivosh.net>
|
||||
James McLaughlin <jamie@lacewing-project.org>
|
||||
David Gwynne <loki@animata.net>
|
||||
Thomas LE ROUX <thomas@november-eleven.fr>
|
||||
Randy Rizun <rrizun@ortivawireless.com>
|
||||
Andre Louis Caron <andre.louis.caron@usherbrooke.ca>
|
||||
Simon Zimmermann <simonz05@gmail.com>
|
||||
Erik Dubbelboer <erik@dubbelboer.com>
|
||||
Martell Malone <martellmalone@gmail.com>
|
||||
Bertrand Paquet <bpaquet@octo.com>
|
||||
BogDan Vatra <bogdan@kde.org>
|
||||
Peter Faiman <peter@thepicard.org>
|
||||
Corey Richardson <corey@octayn.net>
|
||||
Tóth Tamás <tomika_nospam@freemail.hu>
|
||||
Cam Swords <cam.swords@gmail.com>
|
||||
Chris Dickinson <christopher.s.dickinson@gmail.com>
|
||||
Uli Köhler <ukoehler@btronik.de>
|
||||
Charlie Somerville <charlie@charliesomerville.com>
|
||||
Patrik Stutz <patrik.stutz@gmail.com>
|
||||
Fedor Indutny <fedor.indutny@gmail.com>
|
||||
runner <runner.mei@gmail.com>
|
||||
Alexis Campailla <alexis@janeasystems.com>
|
||||
David Wragg <david@wragg.org>
|
||||
Vinnie Falco <vinnie.falco@gmail.com>
|
||||
Alex Butum <alexbutum@linux.com>
|
||||
Rex Feng <rexfeng@gmail.com>
|
||||
Alex Kocharin <alex@kocharin.ru>
|
||||
Mark Koopman <markmontymark@yahoo.com>
|
||||
Helge Heß <me@helgehess.eu>
|
||||
Alexis La Goutte <alexis.lagoutte@gmail.com>
|
||||
George Miroshnykov <george.miroshnykov@gmail.com>
|
||||
Maciej Małecki <me@mmalecki.com>
|
||||
Marc O'Morain <github.com@marcomorain.com>
|
||||
Jeff Pinner <jpinner@twitter.com>
|
||||
Timothy J Fontaine <tjfontaine@gmail.com>
|
||||
Akagi201 <akagi201@gmail.com>
|
||||
Romain Giraud <giraud.romain@gmail.com>
|
||||
Jay Satiro <raysatiro@yahoo.com>
|
||||
Arne Steen <Arne.Steen@gmx.de>
|
||||
Kjell Schubert <kjell.schubert@gmail.com>
|
||||
Olivier Mengué <dolmen@cpan.org>
|
@ -1,23 +0,0 @@
|
||||
http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
|
||||
Igor Sysoev.
|
||||
|
||||
Additional changes are licensed under the same terms as NGINX and
|
||||
copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
||||
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.
|
@ -1,246 +0,0 @@
|
||||
HTTP Parser
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/nodejs/http-parser)
|
||||
|
||||
This is a parser for HTTP messages written in C. It parses both requests and
|
||||
responses. The parser is designed to be used in performance HTTP
|
||||
applications. It does not make any syscalls nor allocations, it does not
|
||||
buffer data, it can be interrupted at anytime. Depending on your
|
||||
architecture, it only requires about 40 bytes of data per message
|
||||
stream (in a web server that is per connection).
|
||||
|
||||
Features:
|
||||
|
||||
* No dependencies
|
||||
* Handles persistent streams (keep-alive).
|
||||
* Decodes chunked encoding.
|
||||
* Upgrade support
|
||||
* Defends against buffer overflow attacks.
|
||||
|
||||
The parser extracts the following information from HTTP messages:
|
||||
|
||||
* Header fields and values
|
||||
* Content-Length
|
||||
* Request method
|
||||
* Response status code
|
||||
* Transfer-Encoding
|
||||
* HTTP version
|
||||
* Request URL
|
||||
* Message body
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
One `http_parser` object is used per TCP connection. Initialize the struct
|
||||
using `http_parser_init()` and set the callbacks. That might look something
|
||||
like this for a request parser:
|
||||
```c
|
||||
http_parser_settings settings;
|
||||
settings.on_url = my_url_callback;
|
||||
settings.on_header_field = my_header_field_callback;
|
||||
/* ... */
|
||||
|
||||
http_parser *parser = malloc(sizeof(http_parser));
|
||||
http_parser_init(parser, HTTP_REQUEST);
|
||||
parser->data = my_socket;
|
||||
```
|
||||
|
||||
When data is received on the socket execute the parser and check for errors.
|
||||
|
||||
```c
|
||||
size_t len = 80*1024, nparsed;
|
||||
char buf[len];
|
||||
ssize_t recved;
|
||||
|
||||
recved = recv(fd, buf, len, 0);
|
||||
|
||||
if (recved < 0) {
|
||||
/* Handle error. */
|
||||
}
|
||||
|
||||
/* Start up / continue the parser.
|
||||
* Note we pass recved==0 to signal that EOF has been received.
|
||||
*/
|
||||
nparsed = http_parser_execute(parser, &settings, buf, recved);
|
||||
|
||||
if (parser->upgrade) {
|
||||
/* handle new protocol */
|
||||
} else if (nparsed != recved) {
|
||||
/* Handle error. Usually just close the connection. */
|
||||
}
|
||||
```
|
||||
|
||||
HTTP needs to know where the end of the stream is. For example, sometimes
|
||||
servers send responses without Content-Length and expect the client to
|
||||
consume input (for the body) until EOF. To tell http_parser about EOF, give
|
||||
`0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors
|
||||
can still be encountered during an EOF, so one must still be prepared
|
||||
to receive them.
|
||||
|
||||
Scalar valued message information such as `status_code`, `method`, and the
|
||||
HTTP version are stored in the parser structure. This data is only
|
||||
temporally stored in `http_parser` and gets reset on each new message. If
|
||||
this information is needed later, copy it out of the structure during the
|
||||
`headers_complete` callback.
|
||||
|
||||
The parser decodes the transfer-encoding for both requests and responses
|
||||
transparently. That is, a chunked encoding is decoded before being sent to
|
||||
the on_body callback.
|
||||
|
||||
|
||||
The Special Problem of Upgrade
|
||||
------------------------------
|
||||
|
||||
HTTP supports upgrading the connection to a different protocol. An
|
||||
increasingly common example of this is the WebSocket protocol which sends
|
||||
a request like
|
||||
|
||||
GET /demo HTTP/1.1
|
||||
Upgrade: WebSocket
|
||||
Connection: Upgrade
|
||||
Host: example.com
|
||||
Origin: http://example.com
|
||||
WebSocket-Protocol: sample
|
||||
|
||||
followed by non-HTTP data.
|
||||
|
||||
(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the
|
||||
WebSocket protocol.)
|
||||
|
||||
To support this, the parser will treat this as a normal HTTP message without a
|
||||
body, issuing both on_headers_complete and on_message_complete callbacks. However
|
||||
http_parser_execute() will stop parsing at the end of the headers and return.
|
||||
|
||||
The user is expected to check if `parser->upgrade` has been set to 1 after
|
||||
`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied
|
||||
offset by the return value of `http_parser_execute()`.
|
||||
|
||||
|
||||
Callbacks
|
||||
---------
|
||||
|
||||
During the `http_parser_execute()` call, the callbacks set in
|
||||
`http_parser_settings` will be executed. The parser maintains state and
|
||||
never looks behind, so buffering the data is not necessary. If you need to
|
||||
save certain data for later usage, you can do that from the callbacks.
|
||||
|
||||
There are two types of callbacks:
|
||||
|
||||
* notification `typedef int (*http_cb) (http_parser*);`
|
||||
Callbacks: on_message_begin, on_headers_complete, on_message_complete.
|
||||
* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
|
||||
Callbacks: (requests only) on_url,
|
||||
(common) on_header_field, on_header_value, on_body;
|
||||
|
||||
Callbacks must return 0 on success. Returning a non-zero value indicates
|
||||
error to the parser, making it exit immediately.
|
||||
|
||||
For cases where it is necessary to pass local information to/from a callback,
|
||||
the `http_parser` object's `data` field can be used.
|
||||
An example of such a case is when using threads to handle a socket connection,
|
||||
parse a request, and then give a response over that socket. By instantiation
|
||||
of a thread-local struct containing relevant data (e.g. accepted socket,
|
||||
allocated memory for callbacks to write into, etc), a parser's callbacks are
|
||||
able to communicate data between the scope of the thread and the scope of the
|
||||
callback in a threadsafe manner. This allows http-parser to be used in
|
||||
multi-threaded contexts.
|
||||
|
||||
Example:
|
||||
```c
|
||||
typedef struct {
|
||||
socket_t sock;
|
||||
void* buffer;
|
||||
int buf_len;
|
||||
} custom_data_t;
|
||||
|
||||
|
||||
int my_url_callback(http_parser* parser, const char *at, size_t length) {
|
||||
/* access to thread local custom_data_t struct.
|
||||
Use this access save parsed data for later use into thread local
|
||||
buffer, or communicate over socket
|
||||
*/
|
||||
parser->data;
|
||||
...
|
||||
return 0;
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
void http_parser_thread(socket_t sock) {
|
||||
int nparsed = 0;
|
||||
/* allocate memory for user data */
|
||||
custom_data_t *my_data = malloc(sizeof(custom_data_t));
|
||||
|
||||
/* some information for use by callbacks.
|
||||
* achieves thread -> callback information flow */
|
||||
my_data->sock = sock;
|
||||
|
||||
/* instantiate a thread-local parser */
|
||||
http_parser *parser = malloc(sizeof(http_parser));
|
||||
http_parser_init(parser, HTTP_REQUEST); /* initialise parser */
|
||||
/* this custom data reference is accessible through the reference to the
|
||||
parser supplied to callback functions */
|
||||
parser->data = my_data;
|
||||
|
||||
http_parser_settings settings; /* set up callbacks */
|
||||
settings.on_url = my_url_callback;
|
||||
|
||||
/* execute parser */
|
||||
nparsed = http_parser_execute(parser, &settings, buf, recved);
|
||||
|
||||
...
|
||||
/* parsed information copied from callback.
|
||||
can now perform action on data copied into thread-local memory from callbacks.
|
||||
achieves callback -> thread information flow */
|
||||
my_data->buffer;
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In case you parse HTTP message in chunks (i.e. `read()` request line
|
||||
from socket, parse, read half headers, parse, etc) your data callbacks
|
||||
may be called more than once. Http-parser guarantees that data pointer is only
|
||||
valid for the lifetime of callback. You can also `read()` into a heap allocated
|
||||
buffer to avoid copying memory around if this fits your application.
|
||||
|
||||
Reading headers may be a tricky task if you read/parse headers partially.
|
||||
Basically, you need to remember whether last header callback was field or value
|
||||
and apply the following logic:
|
||||
|
||||
(on_header_field and on_header_value shortened to on_h_*)
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| State (prev. callback) | Callback | Description/action |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| nothing (first call) | on_h_field | Allocate new buffer and copy callback data |
|
||||
| | | into it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| value | on_h_field | New header started. |
|
||||
| | | Copy current name,value buffers to headers |
|
||||
| | | list and allocate new buffer for new name |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| field | on_h_field | Previous name continues. Reallocate name |
|
||||
| | | buffer and append callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| field | on_h_value | Value for current header started. Allocate |
|
||||
| | | new buffer and copy callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| value | on_h_value | Value continues. Reallocate value buffer |
|
||||
| | | and append callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
|
||||
|
||||
Parsing URLs
|
||||
------------
|
||||
|
||||
A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
|
||||
Users of this library may wish to use it to parse URLs constructed from
|
||||
consecutive `on_url` callbacks.
|
||||
|
||||
See examples of reading in headers:
|
||||
|
||||
* [partial example](http://gist.github.com/155877) in C
|
||||
* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
|
||||
* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript
|
File diff suppressed because it is too large
Load Diff
@ -1,432 +0,0 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef http_parser_h
|
||||
#define http_parser_h
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Also update SONAME in the Makefile whenever you change these. */
|
||||
#define HTTP_PARSER_VERSION_MAJOR 2
|
||||
#define HTTP_PARSER_VERSION_MINOR 7
|
||||
#define HTTP_PARSER_VERSION_PATCH 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && \
|
||||
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
|
||||
#include <BaseTsd.h>
|
||||
#include <stddef.h>
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
|
||||
* faster
|
||||
*/
|
||||
#ifndef HTTP_PARSER_STRICT
|
||||
# define HTTP_PARSER_STRICT 1
|
||||
#endif
|
||||
|
||||
/* Maximium header size allowed. If the macro is not defined
|
||||
* before including this header then the default is used. To
|
||||
* change the maximum header size, define the macro in the build
|
||||
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
|
||||
* the effective limit on the size of the header, define the macro
|
||||
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
|
||||
*/
|
||||
#ifndef HTTP_MAX_HEADER_SIZE
|
||||
# define HTTP_MAX_HEADER_SIZE (80*1024)
|
||||
#endif
|
||||
|
||||
typedef struct http_parser http_parser;
|
||||
typedef struct http_parser_settings http_parser_settings;
|
||||
|
||||
|
||||
/* Callbacks should return non-zero to indicate an error. The parser will
|
||||
* then halt execution.
|
||||
*
|
||||
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
|
||||
* returning '1' from on_headers_complete will tell the parser that it
|
||||
* should not expect a body. This is used when receiving a response to a
|
||||
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
|
||||
* chunked' headers that indicate the presence of a body.
|
||||
*
|
||||
* Returning `2` from on_headers_complete will tell parser that it should not
|
||||
* expect neither a body nor any futher responses on this connection. This is
|
||||
* useful for handling responses to a CONNECT request which may not contain
|
||||
* `Upgrade` or `Connection: upgrade` headers.
|
||||
*
|
||||
* http_data_cb does not return data chunks. It will be called arbitrarily
|
||||
* many times for each string. E.G. you might get 10 callbacks for "on_url"
|
||||
* each providing just a few characters more data.
|
||||
*/
|
||||
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
|
||||
typedef int (*http_cb) (http_parser*);
|
||||
|
||||
|
||||
/* Status Codes */
|
||||
#define HTTP_STATUS_MAP(XX) \
|
||||
XX(100, CONTINUE, Continue) \
|
||||
XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
|
||||
XX(102, PROCESSING, Processing) \
|
||||
XX(200, OK, OK) \
|
||||
XX(201, CREATED, Created) \
|
||||
XX(202, ACCEPTED, Accepted) \
|
||||
XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
|
||||
XX(204, NO_CONTENT, No Content) \
|
||||
XX(205, RESET_CONTENT, Reset Content) \
|
||||
XX(206, PARTIAL_CONTENT, Partial Content) \
|
||||
XX(207, MULTI_STATUS, Multi-Status) \
|
||||
XX(208, ALREADY_REPORTED, Already Reported) \
|
||||
XX(226, IM_USED, IM Used) \
|
||||
XX(300, MULTIPLE_CHOICES, Multiple Choices) \
|
||||
XX(301, MOVED_PERMANENTLY, Moved Permanently) \
|
||||
XX(302, FOUND, Found) \
|
||||
XX(303, SEE_OTHER, See Other) \
|
||||
XX(304, NOT_MODIFIED, Not Modified) \
|
||||
XX(305, USE_PROXY, Use Proxy) \
|
||||
XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
|
||||
XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
|
||||
XX(400, BAD_REQUEST, Bad Request) \
|
||||
XX(401, UNAUTHORIZED, Unauthorized) \
|
||||
XX(402, PAYMENT_REQUIRED, Payment Required) \
|
||||
XX(403, FORBIDDEN, Forbidden) \
|
||||
XX(404, NOT_FOUND, Not Found) \
|
||||
XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
|
||||
XX(406, NOT_ACCEPTABLE, Not Acceptable) \
|
||||
XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
|
||||
XX(408, REQUEST_TIMEOUT, Request Timeout) \
|
||||
XX(409, CONFLICT, Conflict) \
|
||||
XX(410, GONE, Gone) \
|
||||
XX(411, LENGTH_REQUIRED, Length Required) \
|
||||
XX(412, PRECONDITION_FAILED, Precondition Failed) \
|
||||
XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
|
||||
XX(414, URI_TOO_LONG, URI Too Long) \
|
||||
XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
|
||||
XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
|
||||
XX(417, EXPECTATION_FAILED, Expectation Failed) \
|
||||
XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
|
||||
XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
|
||||
XX(423, LOCKED, Locked) \
|
||||
XX(424, FAILED_DEPENDENCY, Failed Dependency) \
|
||||
XX(426, UPGRADE_REQUIRED, Upgrade Required) \
|
||||
XX(428, PRECONDITION_REQUIRED, Precondition Required) \
|
||||
XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
|
||||
XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
|
||||
XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
|
||||
XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
|
||||
XX(501, NOT_IMPLEMENTED, Not Implemented) \
|
||||
XX(502, BAD_GATEWAY, Bad Gateway) \
|
||||
XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
|
||||
XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
|
||||
XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
|
||||
XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
|
||||
XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
|
||||
XX(508, LOOP_DETECTED, Loop Detected) \
|
||||
XX(510, NOT_EXTENDED, Not Extended) \
|
||||
XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
|
||||
|
||||
enum http_status
|
||||
{
|
||||
#define XX(num, name, string) HTTP_STATUS_##name = num,
|
||||
HTTP_STATUS_MAP(XX)
|
||||
#undef XX
|
||||
};
|
||||
|
||||
|
||||
/* Request Methods */
|
||||
#define HTTP_METHOD_MAP(XX) \
|
||||
XX(0, DELETE, DELETE) \
|
||||
XX(1, GET, GET) \
|
||||
XX(2, HEAD, HEAD) \
|
||||
XX(3, POST, POST) \
|
||||
XX(4, PUT, PUT) \
|
||||
/* pathological */ \
|
||||
XX(5, CONNECT, CONNECT) \
|
||||
XX(6, OPTIONS, OPTIONS) \
|
||||
XX(7, TRACE, TRACE) \
|
||||
/* WebDAV */ \
|
||||
XX(8, COPY, COPY) \
|
||||
XX(9, LOCK, LOCK) \
|
||||
XX(10, MKCOL, MKCOL) \
|
||||
XX(11, MOVE, MOVE) \
|
||||
XX(12, PROPFIND, PROPFIND) \
|
||||
XX(13, PROPPATCH, PROPPATCH) \
|
||||
XX(14, SEARCH, SEARCH) \
|
||||
XX(15, UNLOCK, UNLOCK) \
|
||||
XX(16, BIND, BIND) \
|
||||
XX(17, REBIND, REBIND) \
|
||||
XX(18, UNBIND, UNBIND) \
|
||||
XX(19, ACL, ACL) \
|
||||
/* subversion */ \
|
||||
XX(20, REPORT, REPORT) \
|
||||
XX(21, MKACTIVITY, MKACTIVITY) \
|
||||
XX(22, CHECKOUT, CHECKOUT) \
|
||||
XX(23, MERGE, MERGE) \
|
||||
/* upnp */ \
|
||||
XX(24, MSEARCH, M-SEARCH) \
|
||||
XX(25, NOTIFY, NOTIFY) \
|
||||
XX(26, SUBSCRIBE, SUBSCRIBE) \
|
||||
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
|
||||
/* RFC-5789 */ \
|
||||
XX(28, PATCH, PATCH) \
|
||||
XX(29, PURGE, PURGE) \
|
||||
/* CalDAV */ \
|
||||
XX(30, MKCALENDAR, MKCALENDAR) \
|
||||
/* RFC-2068, section 19.6.1.2 */ \
|
||||
XX(31, LINK, LINK) \
|
||||
XX(32, UNLINK, UNLINK) \
|
||||
|
||||
enum http_method
|
||||
{
|
||||
#define XX(num, name, string) HTTP_##name = num,
|
||||
HTTP_METHOD_MAP(XX)
|
||||
#undef XX
|
||||
};
|
||||
|
||||
|
||||
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
|
||||
|
||||
|
||||
/* Flag values for http_parser.flags field */
|
||||
enum flags
|
||||
{ F_CHUNKED = 1 << 0
|
||||
, F_CONNECTION_KEEP_ALIVE = 1 << 1
|
||||
, F_CONNECTION_CLOSE = 1 << 2
|
||||
, F_CONNECTION_UPGRADE = 1 << 3
|
||||
, F_TRAILING = 1 << 4
|
||||
, F_UPGRADE = 1 << 5
|
||||
, F_SKIPBODY = 1 << 6
|
||||
, F_CONTENTLENGTH = 1 << 7
|
||||
};
|
||||
|
||||
|
||||
/* Map for errno-related constants
|
||||
*
|
||||
* The provided argument should be a macro that takes 2 arguments.
|
||||
*/
|
||||
#define HTTP_ERRNO_MAP(XX) \
|
||||
/* No error */ \
|
||||
XX(OK, "success") \
|
||||
\
|
||||
/* Callback-related errors */ \
|
||||
XX(CB_message_begin, "the on_message_begin callback failed") \
|
||||
XX(CB_url, "the on_url callback failed") \
|
||||
XX(CB_header_field, "the on_header_field callback failed") \
|
||||
XX(CB_header_value, "the on_header_value callback failed") \
|
||||
XX(CB_headers_complete, "the on_headers_complete callback failed") \
|
||||
XX(CB_body, "the on_body callback failed") \
|
||||
XX(CB_message_complete, "the on_message_complete callback failed") \
|
||||
XX(CB_status, "the on_status callback failed") \
|
||||
XX(CB_chunk_header, "the on_chunk_header callback failed") \
|
||||
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
|
||||
\
|
||||
/* Parsing-related errors */ \
|
||||
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
||||
XX(HEADER_OVERFLOW, \
|
||||
"too many header bytes seen; overflow detected") \
|
||||
XX(CLOSED_CONNECTION, \
|
||||
"data received after completed connection: close message") \
|
||||
XX(INVALID_VERSION, "invalid HTTP version") \
|
||||
XX(INVALID_STATUS, "invalid HTTP status code") \
|
||||
XX(INVALID_METHOD, "invalid HTTP method") \
|
||||
XX(INVALID_URL, "invalid URL") \
|
||||
XX(INVALID_HOST, "invalid host") \
|
||||
XX(INVALID_PORT, "invalid port") \
|
||||
XX(INVALID_PATH, "invalid path") \
|
||||
XX(INVALID_QUERY_STRING, "invalid query string") \
|
||||
XX(INVALID_FRAGMENT, "invalid fragment") \
|
||||
XX(LF_EXPECTED, "LF character expected") \
|
||||
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
|
||||
XX(INVALID_CONTENT_LENGTH, \
|
||||
"invalid character in content-length header") \
|
||||
XX(UNEXPECTED_CONTENT_LENGTH, \
|
||||
"unexpected content-length header") \
|
||||
XX(INVALID_CHUNK_SIZE, \
|
||||
"invalid character in chunk size header") \
|
||||
XX(INVALID_CONSTANT, "invalid constant string") \
|
||||
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
|
||||
XX(STRICT, "strict mode assertion failed") \
|
||||
XX(PAUSED, "parser is paused") \
|
||||
XX(UNKNOWN, "an unknown error occurred")
|
||||
|
||||
|
||||
/* Define HPE_* values for each errno value above */
|
||||
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
|
||||
enum http_errno {
|
||||
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
|
||||
};
|
||||
#undef HTTP_ERRNO_GEN
|
||||
|
||||
|
||||
/* Get an http_errno value from an http_parser */
|
||||
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
|
||||
|
||||
|
||||
struct http_parser {
|
||||
/** PRIVATE **/
|
||||
unsigned int type : 2; /* enum http_parser_type */
|
||||
unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
|
||||
unsigned int state : 7; /* enum state from http_parser.c */
|
||||
unsigned int header_state : 7; /* enum header_state from http_parser.c */
|
||||
unsigned int index : 7; /* index into current matcher */
|
||||
unsigned int lenient_http_headers : 1;
|
||||
|
||||
uint32_t nread; /* # bytes read in various scenarios */
|
||||
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
|
||||
|
||||
/** READ-ONLY **/
|
||||
unsigned short http_major;
|
||||
unsigned short http_minor;
|
||||
unsigned int status_code : 16; /* responses only */
|
||||
unsigned int method : 8; /* requests only */
|
||||
unsigned int http_errno : 7;
|
||||
|
||||
/* 1 = Upgrade header was present and the parser has exited because of that.
|
||||
* 0 = No upgrade header present.
|
||||
* Should be checked when http_parser_execute() returns in addition to
|
||||
* error checking.
|
||||
*/
|
||||
unsigned int upgrade : 1;
|
||||
|
||||
/** PUBLIC **/
|
||||
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
||||
};
|
||||
|
||||
|
||||
struct http_parser_settings {
|
||||
http_cb on_message_begin;
|
||||
http_data_cb on_url;
|
||||
http_data_cb on_status;
|
||||
http_data_cb on_header_field;
|
||||
http_data_cb on_header_value;
|
||||
http_cb on_headers_complete;
|
||||
http_data_cb on_body;
|
||||
http_cb on_message_complete;
|
||||
/* When on_chunk_header is called, the current chunk length is stored
|
||||
* in parser->content_length.
|
||||
*/
|
||||
http_cb on_chunk_header;
|
||||
http_cb on_chunk_complete;
|
||||
};
|
||||
|
||||
|
||||
enum http_parser_url_fields
|
||||
{ UF_SCHEMA = 0
|
||||
, UF_HOST = 1
|
||||
, UF_PORT = 2
|
||||
, UF_PATH = 3
|
||||
, UF_QUERY = 4
|
||||
, UF_FRAGMENT = 5
|
||||
, UF_USERINFO = 6
|
||||
, UF_MAX = 7
|
||||
};
|
||||
|
||||
|
||||
/* Result structure for http_parser_parse_url().
|
||||
*
|
||||
* Callers should index into field_data[] with UF_* values iff field_set
|
||||
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
|
||||
* because we probably have padding left over), we convert any port to
|
||||
* a uint16_t.
|
||||
*/
|
||||
struct http_parser_url {
|
||||
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
|
||||
uint16_t port; /* Converted UF_PORT string */
|
||||
|
||||
struct {
|
||||
uint16_t off; /* Offset into buffer in which field starts */
|
||||
uint16_t len; /* Length of run in buffer */
|
||||
} field_data[UF_MAX];
|
||||
};
|
||||
|
||||
|
||||
/* Returns the library version. Bits 16-23 contain the major version number,
|
||||
* bits 8-15 the minor version number and bits 0-7 the patch level.
|
||||
* Usage example:
|
||||
*
|
||||
* unsigned long version = http_parser_version();
|
||||
* unsigned major = (version >> 16) & 255;
|
||||
* unsigned minor = (version >> 8) & 255;
|
||||
* unsigned patch = version & 255;
|
||||
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
|
||||
*/
|
||||
unsigned long http_parser_version(void);
|
||||
|
||||
void http_parser_init(http_parser *parser, enum http_parser_type type);
|
||||
|
||||
|
||||
/* Initialize http_parser_settings members to 0
|
||||
*/
|
||||
void http_parser_settings_init(http_parser_settings *settings);
|
||||
|
||||
|
||||
/* Executes the parser. Returns number of parsed bytes. Sets
|
||||
* `parser->http_errno` on error. */
|
||||
size_t http_parser_execute(http_parser *parser,
|
||||
const http_parser_settings *settings,
|
||||
const char *data,
|
||||
size_t len);
|
||||
|
||||
|
||||
/* If http_should_keep_alive() in the on_headers_complete or
|
||||
* on_message_complete callback returns 0, then this should be
|
||||
* the last message on the connection.
|
||||
* If you are the server, respond with the "Connection: close" header.
|
||||
* If you are the client, close the connection.
|
||||
*/
|
||||
int http_should_keep_alive(const http_parser *parser);
|
||||
|
||||
/* Returns a string version of the HTTP method. */
|
||||
const char *http_method_str(enum http_method m);
|
||||
|
||||
/* Return a string name of the given error */
|
||||
const char *http_errno_name(enum http_errno err);
|
||||
|
||||
/* Return a string description of the given error */
|
||||
const char *http_errno_description(enum http_errno err);
|
||||
|
||||
/* Initialize all http_parser_url members to 0 */
|
||||
void http_parser_url_init(struct http_parser_url *u);
|
||||
|
||||
/* Parse a URL; return nonzero on failure */
|
||||
int http_parser_parse_url(const char *buf, size_t buflen,
|
||||
int is_connect,
|
||||
struct http_parser_url *u);
|
||||
|
||||
/* Pause or un-pause the parser; a nonzero value pauses */
|
||||
void http_parser_pause(http_parser *parser, int paused);
|
||||
|
||||
/* Checks if this is the final chunk of the body. */
|
||||
int http_body_is_final(const http_parser *parser);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -1,98 +0,0 @@
|
||||
$Id: Changelog.txt,v 1.33 2013/11/26 08:47:36 nanard Exp $
|
||||
|
||||
2013/11/26:
|
||||
enforce strict aliasing rules.
|
||||
|
||||
2013/09/10:
|
||||
small patch for MSVC >= 16
|
||||
rename win32 implementation of gettimeofday() to natpmp_gettimeofday()
|
||||
|
||||
2012/08/21:
|
||||
Little change in Makefile
|
||||
removed warnings in testgetgateway.c
|
||||
Fixed bugs in command line argumentparsing in natpmpc.c
|
||||
|
||||
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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -1,21 +0,0 @@
|
||||
#ifndef DECLSPEC_H_INCLUDED
|
||||
#define DECLSPEC_H_INCLUDED
|
||||
|
||||
#if defined(WIN32) && !defined(STATICLIB)
|
||||
/* for windows dll */
|
||||
#ifdef NATPMP_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
|
||||
|
@ -1,573 +0,0 @@
|
||||
/* $Id: getgateway.c,v 1.25 2014/04/22 10:28:57 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
|
||||
Copyright (c) 2007-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 <stdio.h>
|
||||
#include <ctype.h>
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/param.h>
|
||||
#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
|
||||
#include <sys/sysctl.h>
|
||||
#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 <stdarg.h>
|
||||
#include <w32api/windef.h>
|
||||
#include <w32api/winbase.h>
|
||||
#include <w32api/winreg.h>
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/sockio.h>
|
||||
#define USE_HAIKU_CODE
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYSCTL_NET_ROUTE
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
#ifdef USE_SOCKET_ROUTE
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIN32_CODE
|
||||
#include <unknwn.h>
|
||||
#include <winreg.h>
|
||||
#define MAX_KEY_LENGTH 255
|
||||
#define MAX_VALUE_LENGTH 16383
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIN32_CODE_2
|
||||
#include <windows.h>
|
||||
#include <iphlpapi.h>
|
||||
#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; p<buf+l; p+=rt->rtm_msglen) {
|
||||
rt = (struct rt_msghdr *)p;
|
||||
sa = (struct sockaddr *)(rt + 1);
|
||||
for(i=0; i<RTAX_MAX; i++) {
|
||||
if(rt->rtm_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 */
|
||||
|
||||
#if !defined(USE_PROC_NET_ROUTE) && !defined(USE_SOCKET_ROUTE) && !defined(USE_SYSCTL_NET_ROUTE) && !defined(USE_WIN32_CODE) && !defined(USE_WIN32_CODE_2) && !defined(USE_HAIKU_CODE)
|
||||
int getdefaultgateway(in_addr_t * addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
@ -1,49 +0,0 @@
|
||||
/* $Id: getgateway.h,v 1.8 2014/04/22 09:15:40 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-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.
|
||||
*/
|
||||
#ifndef __GETGATEWAY_H__
|
||||
#define __GETGATEWAY_H__
|
||||
|
||||
#ifdef WIN32
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1600
|
||||
#include <stdint.h>
|
||||
#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
|
@ -1,383 +0,0 @@
|
||||
/* $Id: natpmp.c,v 1.20 2015/05/27 12:43:15 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2015, 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 <string.h>
|
||||
#include <time.h>
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <errno.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#ifndef EWOULDBLOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#endif
|
||||
#ifndef ECONNREFUSED
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#endif
|
||||
#include "wingettimeofday.h"
|
||||
#define gettimeofday natpmp_gettimeofday
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#define closesocket close
|
||||
#endif
|
||||
#include "natpmp.h"
|
||||
#include "getgateway.h"
|
||||
#include <stdio.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, (const char *)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 already 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;
|
||||
/* break strict-aliasing rules :
|
||||
*((uint16_t *)(p->pending_request + 4)) = htons(privateport); */
|
||||
p->pending_request[4] = (privateport >> 8) & 0xff;
|
||||
p->pending_request[5] = privateport & 0xff;
|
||||
/* break stric-aliasing rules :
|
||||
*((uint16_t *)(p->pending_request + 6)) = htons(publicport); */
|
||||
p->pending_request[6] = (publicport >> 8) & 0xff;
|
||||
p->pending_request[7] = publicport & 0xff;
|
||||
/* break stric-aliasing rules :
|
||||
*((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); */
|
||||
p->pending_request[8] = (lifetime >> 24) & 0xff;
|
||||
p->pending_request[9] = (lifetime >> 16) & 0xff;
|
||||
p->pending_request[10] = (lifetime >> 8) & 0xff;
|
||||
p->pending_request[11] = lifetime & 0xff;
|
||||
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, (char *)buf, sizeof(buf), 0,
|
||||
(struct sockaddr *)&addr, &addrlen);
|
||||
if(n<0)
|
||||
#ifdef WIN32
|
||||
switch(WSAGetLastError()) {
|
||||
#else
|
||||
switch(errno) {
|
||||
#endif
|
||||
/*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<<p->try_number); // ms
|
||||
/*for(i=0; i<p->try_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
|
||||
|
@ -1,219 +0,0 @@
|
||||
/* $Id: natpmp.h,v 1.20 2014/04/22 09:15:40 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-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.
|
||||
*/
|
||||
#ifndef __NATPMP_H__
|
||||
#define __NATPMP_H__
|
||||
|
||||
/* NAT-PMP Port as defined by the NAT-PMP draft */
|
||||
#define NATPMP_PORT (5351)
|
||||
|
||||
#include <time.h>
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/time.h>
|
||||
#endif /* !defined(_MSC_VER) */
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1600
|
||||
#include <stdint.h>
|
||||
#else /* !defined(_MSC_VER) || _MSC_VER >= 1600 */
|
||||
typedef unsigned long uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
#endif /* !defined(_MSC_VER) || _MSC_VER >= 1600 */
|
||||
#define in_addr_t uint32_t
|
||||
#include "declspec.h"
|
||||
#else /* WIN32 */
|
||||
#define LIBSPEC
|
||||
#include <netinet/in.h>
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* causes problem when installing. Maybe should it be inlined ? */
|
||||
/* #include "declspec.h" */
|
||||
|
||||
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
|
@ -1,60 +0,0 @@
|
||||
/* $Id: wingettimeofday.c,v 1.6 2013/09/10 20:13:26 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2013, 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 <sys/time.h>
|
||||
#endif
|
||||
|
||||
typedef struct _FILETIME {
|
||||
unsigned long dwLowDateTime;
|
||||
unsigned long dwHighDateTime;
|
||||
} FILETIME;
|
||||
|
||||
void __stdcall GetSystemTimeAsFileTime(FILETIME*);
|
||||
|
||||
int natpmp_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
|
||||
|
@ -1,39 +0,0 @@
|
||||
/* $Id: wingettimeofday.h,v 1.5 2013/09/11 07:22:25 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2013, 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 <time.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
int natpmp_gettimeofday(struct timeval* p, void* tz /* IGNORED */);
|
||||
#endif
|
||||
#endif
|
@ -1,691 +0,0 @@
|
||||
$Id: Changelog.txt,v 1.229 2017/12/12 11:26:25 nanard Exp $
|
||||
miniUPnP client Changelog.
|
||||
|
||||
2017/12/11:
|
||||
Fix buffer over run in minixml.c
|
||||
Fix uninitialized variable access in upnpreplyparse.c
|
||||
|
||||
2017/05/05:
|
||||
Fix CVE-2017-8798 Thanks to tin/Team OSTStrom
|
||||
|
||||
2016/11/11:
|
||||
check strlen before memcmp in XML parsing portlistingparse.c
|
||||
fix build under SOLARIS and CYGWIN
|
||||
|
||||
2016/10/11:
|
||||
Add python 3 compatibility to IGD test
|
||||
|
||||
VERSION 2.0 : released 2016/04/19
|
||||
|
||||
2016/01/24:
|
||||
change miniwget to return HTTP status code
|
||||
increments API_VERSION to 16
|
||||
|
||||
2016/01/22:
|
||||
Improve UPNPIGD_IsConnected() to check if WAN address is not private.
|
||||
parse HTTP response status line in miniwget.c
|
||||
|
||||
2015/10/26:
|
||||
snprintf() overflow check. check overflow in simpleUPnPcommand2()
|
||||
|
||||
2015/10/25:
|
||||
fix compilation with old macs
|
||||
fix compilation with mingw32 (for Appveyor)
|
||||
fix python module for python <= 2.3
|
||||
|
||||
2015/10/08:
|
||||
Change sameport to localport
|
||||
see https://github.com/miniupnp/miniupnp/pull/120
|
||||
increments API_VERSION to 15
|
||||
|
||||
2015/09/15:
|
||||
Fix buffer overflow in igd_desc_parse.c/IGDstartelt()
|
||||
Discovered by Aleksandar Nikolic of Cisco Talos
|
||||
|
||||
2015/08/28:
|
||||
move ssdpDiscoverDevices() to minissdpc.c
|
||||
|
||||
2015/08/27:
|
||||
avoid unix socket leak in getDevicesFromMiniSSDPD()
|
||||
|
||||
2015/08/16:
|
||||
Also accept "Up" as ConnectionStatus value
|
||||
|
||||
2015/07/23:
|
||||
split getDevicesFromMiniSSDPD
|
||||
add ttl argument to upnpDiscover() functions
|
||||
increments API_VERSION to 14
|
||||
|
||||
2015/07/22:
|
||||
Read USN from SSDP messages.
|
||||
|
||||
2015/07/15:
|
||||
Check malloc/calloc
|
||||
|
||||
2015/06/16:
|
||||
update getDevicesFromMiniSSDPD() to process longer minissdpd
|
||||
responses
|
||||
|
||||
2015/05/22:
|
||||
add searchalltypes param to upnpDiscoverDevices()
|
||||
increments API_VERSION to 13
|
||||
|
||||
2015/04/30:
|
||||
upnpc: output version on the terminal
|
||||
|
||||
2015/04/27:
|
||||
_BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE
|
||||
fix CMakeLists.txt COMPILE_DEFINITIONS
|
||||
fix getDevicesFromMiniSSDPD() not setting scope_id
|
||||
improve -r command of upnpc command line tool
|
||||
|
||||
2014/11/17:
|
||||
search all :
|
||||
upnpDiscoverDevices() / upnpDiscoverAll() functions
|
||||
listdevices executable
|
||||
increment API_VERSION to 12
|
||||
validate igd_desc_parse
|
||||
|
||||
2014/11/13:
|
||||
increment API_VERSION to 11
|
||||
|
||||
2014/11/05:
|
||||
simplified function GetUPNPUrls()
|
||||
|
||||
2014/09/11:
|
||||
use remoteHost arg of DeletePortMapping
|
||||
|
||||
2014/09/06:
|
||||
Fix python3 build
|
||||
|
||||
2014/07/01:
|
||||
Fix parsing of IGD2 root descriptions
|
||||
|
||||
2014/06/10:
|
||||
rename LIBSPEC to MINIUPNP_LIBSPEC
|
||||
|
||||
2014/05/15:
|
||||
Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange
|
||||
|
||||
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 <NewPortListing> 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
|
||||
|
@ -1,27 +0,0 @@
|
||||
MiniUPnPc
|
||||
Copyright (c) 2005-2016, 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.
|
||||
|
@ -1,63 +0,0 @@
|
||||
Project: miniupnp
|
||||
Project web page: http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
github: https://github.com/miniupnp/miniupnp
|
||||
Author: Thomas Bernard
|
||||
Copyright (c) 2005-2017 Thomas Bernard
|
||||
This software is subject to the conditions detailed in the
|
||||
LICENSE file provided within this distribution.
|
||||
|
||||
|
||||
* 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()
|
||||
- UPNP_GetValidIGD()
|
||||
- miniwget()
|
||||
- parserootdesc()
|
||||
- GetUPNPUrls()
|
||||
- UPNP_* (calling UPNP methods)
|
||||
|
||||
Note : use #include <miniupnpc/miniupnpc.h> 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 :
|
||||
https://miniupnp.tuxfamily.org/forum/
|
||||
|
||||
Bugs should be reported on github :
|
||||
https://github.com/miniupnp/miniupnp/issues
|
@ -1 +0,0 @@
|
||||
2.0
|
@ -1,54 +0,0 @@
|
||||
/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 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 */
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
*/
|
||||
#define DECODELENGTH(n, p) n = 0; \
|
||||
do { n = (n << 7) | (*p & 0x7f); } \
|
||||
while((*(p++)&0x80) && (n<(1<<25)));
|
||||
|
||||
/* n : unsigned
|
||||
* READ : function/macro to read one byte (unsigned char)
|
||||
*/
|
||||
#define DECODELENGTH_READ(n, READ) \
|
||||
n = 0; \
|
||||
do { \
|
||||
unsigned char c; \
|
||||
READ(c); \
|
||||
n = (n << 7) | (c & 0x07f); \
|
||||
if(!(c&0x80)) break; \
|
||||
} while(n<(1<<25));
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
* p_limit : unsigned char *
|
||||
*/
|
||||
#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)));
|
||||
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
*/
|
||||
#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 /* CODELENGTH_H_INCLUDED */
|
@ -1,262 +0,0 @@
|
||||
/* $Id: connecthostport.c,v 1.17 2017/04/21 09:58:30 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2010-2017 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#define snprintf _snprintf
|
||||
#define herror
|
||||
#define socklen_t int
|
||||
#else /* #ifdef _WIN32 */
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
#include <sys/time.h>
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
#include <sys/param.h>
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
|
||||
* during the connect() call */
|
||||
#define MINIUPNPC_IGNORE_EINTR
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#endif /* #else _WIN32 */
|
||||
|
||||
/* definition of PRINT_SOCKET_ERROR */
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) fprintf(stderr, "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 SO_RCVTIMEO");
|
||||
}
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO");
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -1,123 +0,0 @@
|
||||
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include "igd_desc_parse.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 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;
|
||||
if(l >= MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
/* 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(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
|
||||
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
|
||||
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:")
|
||||
|| COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:") ) {
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
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);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
@ -1,49 +0,0 @@
|
||||
/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* 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.
|
||||
* */
|
||||
#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);
|
||||
#ifdef DEBUG
|
||||
void printIGD(struct IGDdatas *);
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* IGD_DESC_PARSE_H_INCLUDED */
|
@ -1,110 +0,0 @@
|
||||
/* $Id: listdevices.c,v 1.7 2015/10/08 16:15:47 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2013-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#endif /* _WIN32 */
|
||||
#include "miniupnpc.h"
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
const char * searched_device = NULL;
|
||||
const char * * searched_devices = NULL;
|
||||
const char * multicastif = 0;
|
||||
const char * minissdpdpath = 0;
|
||||
int ipv6 = 0;
|
||||
unsigned char ttl = 2;
|
||||
int error = 0;
|
||||
struct UPNPDev * devlist = 0;
|
||||
struct UPNPDev * dev;
|
||||
int i;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if(nResult != NO_ERROR)
|
||||
{
|
||||
fprintf(stderr, "WSAStartup() failed.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(i = 1; i < argc; i++) {
|
||||
if(strcmp(argv[i], "-6") == 0)
|
||||
ipv6 = 1;
|
||||
else if(strcmp(argv[i], "-d") == 0) {
|
||||
if(++i >= argc) {
|
||||
fprintf(stderr, "%s option needs one argument\n", "-d");
|
||||
return 1;
|
||||
}
|
||||
searched_device = argv[i];
|
||||
} else if(strcmp(argv[i], "-t") == 0) {
|
||||
if(++i >= argc) {
|
||||
fprintf(stderr, "%s option needs one argument\n", "-t");
|
||||
return 1;
|
||||
}
|
||||
ttl = (unsigned char)atoi(argv[i]);
|
||||
} else if(strcmp(argv[i], "-l") == 0) {
|
||||
if(++i >= argc) {
|
||||
fprintf(stderr, "-l option needs at least one argument\n");
|
||||
return 1;
|
||||
}
|
||||
searched_devices = (const char * *)(argv + i);
|
||||
break;
|
||||
} else if(strcmp(argv[i], "-m") == 0) {
|
||||
if(++i >= argc) {
|
||||
fprintf(stderr, "-m option needs one argument\n");
|
||||
return 1;
|
||||
}
|
||||
multicastif = argv[i];
|
||||
} else {
|
||||
printf("usage : %s [options] [-l <device1> <device2> ...]\n", argv[0]);
|
||||
printf("options :\n");
|
||||
printf(" -6 : use IPv6\n");
|
||||
printf(" -m address/ifname : network interface to use for multicast\n");
|
||||
printf(" -d <device string> : search only for this type of device\n");
|
||||
printf(" -l <device1> <device2> ... : search only for theses types of device\n");
|
||||
printf(" -t ttl : set multicast TTL. Default value is 2.\n");
|
||||
printf(" -h : this help\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(searched_device) {
|
||||
printf("searching UPnP device type %s\n", searched_device);
|
||||
devlist = upnpDiscoverDevice(searched_device,
|
||||
2000, multicastif, minissdpdpath,
|
||||
0/*localport*/, ipv6, ttl, &error);
|
||||
} else if(searched_devices) {
|
||||
printf("searching UPnP device types :\n");
|
||||
for(i = 0; searched_devices[i]; i++)
|
||||
printf("\t%s\n", searched_devices[i]);
|
||||
devlist = upnpDiscoverDevices(searched_devices,
|
||||
2000, multicastif, minissdpdpath,
|
||||
0/*localport*/, ipv6, ttl, &error, 1);
|
||||
} else {
|
||||
printf("searching all UPnP devices\n");
|
||||
devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath,
|
||||
0/*localport*/, ipv6, ttl, &error);
|
||||
}
|
||||
if(devlist) {
|
||||
for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) {
|
||||
printf("%3d: %-48s\n", i, dev->st);
|
||||
printf(" %s\n", dev->descURL);
|
||||
printf(" %s\n", dev->usn);
|
||||
}
|
||||
freeUPNPDevlist(devlist);
|
||||
} else {
|
||||
printf("no device found.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,134 +0,0 @@
|
||||
/* $Id: minisoap.c,v 1.25 2017/04/21 10:03:24 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2015 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <winsock2.h>
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include "minisoap.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define OS_STRING "Win32"
|
||||
#define MINIUPNPC_VERSION_STRING "2.0"
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define OS_STRING "Android"
|
||||
#define MINIUPNPC_VERSION_STRING "2.0"
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
/* only for malloc */
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) fprintf(stderr, "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, we could use writev() for that */
|
||||
p = malloc(headerssize+bodysize);
|
||||
if(!p)
|
||||
return -1;
|
||||
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_VERSION_STRING ", 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);
|
||||
if ((unsigned int)headerssize >= sizeof(headerbuf))
|
||||
return -1;
|
||||
#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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,893 +0,0 @@
|
||||
/* $Id: minissdpc.c,v 1.35 2017/11/02 15:34:36 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2017 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
/*#include <syslog.h>*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#if defined (__NetBSD__)
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <winsock.h>
|
||||
#define snprintf _snprintf
|
||||
#if !defined(_MSC_VER)
|
||||
#include <stdint.h>
|
||||
#else /* !defined(_MSC_VER) */
|
||||
typedef unsigned short uint16_t;
|
||||
#endif /* !defined(_MSC_VER) */
|
||||
#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 */
|
||||
#endif /* _WIN32 */
|
||||
#if defined(__amigaos__) || defined(__amigaos4__)
|
||||
#include <sys/socket.h>
|
||||
#endif /* defined(__amigaos__) || defined(__amigaos4__) */
|
||||
#if defined(__amigaos__)
|
||||
#define uint16_t unsigned short
|
||||
#endif /* defined(__amigaos__) */
|
||||
/* Hack */
|
||||
#define UNIX_PATH_LEN 108
|
||||
struct sockaddr_un {
|
||||
uint16_t sun_family;
|
||||
char sun_path[UNIX_PATH_LEN];
|
||||
};
|
||||
#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#define closesocket close
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError());
|
||||
#else
|
||||
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||
#endif
|
||||
|
||||
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
|
||||
#define HAS_IP_MREQN
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_IP_MREQN) && !defined(_WIN32)
|
||||
#include <sys/ioctl.h>
|
||||
#if defined(__sun)
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
#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
|
||||
|
||||
#if defined(__amigaos__) || defined(__amigaos4__)
|
||||
/* Amiga OS specific stuff */
|
||||
#define TIMEVAL struct timeval
|
||||
#endif
|
||||
|
||||
#include "minissdpc.h"
|
||||
#include "miniupnpc.h"
|
||||
#include "receivedata.h"
|
||||
|
||||
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
|
||||
|
||||
#include "codelength.h"
|
||||
|
||||
struct UPNPDev *
|
||||
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
|
||||
{
|
||||
struct UPNPDev * devlist = NULL;
|
||||
int s;
|
||||
int res;
|
||||
|
||||
s = connectToMiniSSDPD(socketpath);
|
||||
if (s < 0) {
|
||||
if (error)
|
||||
*error = s;
|
||||
return NULL;
|
||||
}
|
||||
res = requestDevicesFromMiniSSDPD(s, devtype);
|
||||
if (res < 0) {
|
||||
if (error)
|
||||
*error = res;
|
||||
} else {
|
||||
devlist = receiveDevicesFromMiniSSDPD(s, error);
|
||||
}
|
||||
disconnectFromMiniSSDPD(s);
|
||||
return devlist;
|
||||
}
|
||||
|
||||
/* macros used to read from unix socket */
|
||||
#define READ_BYTE_BUFFER(c) \
|
||||
if((int)bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
c = buffer[bufferindex++];
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
#define READ_COPY_BUFFER(dst, len) \
|
||||
for(l = len, p = (unsigned char *)dst; l > 0; ) { \
|
||||
unsigned int lcopy; \
|
||||
if((int)bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
lcopy = MIN(l, (n - bufferindex)); \
|
||||
memcpy(p, buffer + bufferindex, lcopy); \
|
||||
l -= lcopy; \
|
||||
p += lcopy; \
|
||||
bufferindex += lcopy; \
|
||||
}
|
||||
|
||||
#define READ_DISCARD_BUFFER(len) \
|
||||
for(l = len; l > 0; ) { \
|
||||
unsigned int lcopy; \
|
||||
if(bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
lcopy = MIN(l, (n - bufferindex)); \
|
||||
l -= lcopy; \
|
||||
bufferindex += lcopy; \
|
||||
}
|
||||
|
||||
int
|
||||
connectToMiniSSDPD(const char * socketpath)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_un addr;
|
||||
#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
|
||||
struct timeval timeout;
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(s < 0)
|
||||
{
|
||||
/*syslog(LOG_ERR, "socket(unix): %m");*/
|
||||
perror("socket(unix)");
|
||||
return MINISSDPC_SOCKET_ERROR;
|
||||
}
|
||||
#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
|
||||
/* setting a 3 seconds timeout */
|
||||
/* not supported for AF_UNIX sockets under Solaris */
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
perror("setsockopt SO_RCVTIMEO unix");
|
||||
}
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
perror("setsockopt SO_SNDTIMEO unix");
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
if(!socketpath)
|
||||
socketpath = "/var/run/minissdpd.sock";
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
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 MINISSDPC_SOCKET_ERROR;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
disconnectFromMiniSSDPD(int s)
|
||||
{
|
||||
if (close(s) < 0)
|
||||
return MINISSDPC_SOCKET_ERROR;
|
||||
return MINISSDPC_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
requestDevicesFromMiniSSDPD(int s, const char * devtype)
|
||||
{
|
||||
unsigned char buffer[256];
|
||||
unsigned char * p;
|
||||
unsigned int stsize, l;
|
||||
|
||||
stsize = strlen(devtype);
|
||||
if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
|
||||
{
|
||||
buffer[0] = 3; /* request type 3 : everything */
|
||||
}
|
||||
else
|
||||
{
|
||||
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 ! */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
|
||||
stsize, (unsigned)sizeof(buffer));
|
||||
#endif /* DEBUG */
|
||||
return MINISSDPC_INVALID_INPUT;
|
||||
}
|
||||
memcpy(p, devtype, stsize);
|
||||
p += stsize;
|
||||
if(write(s, buffer, p - buffer) < 0)
|
||||
{
|
||||
/*syslog(LOG_ERR, "write(): %m");*/
|
||||
perror("minissdpc.c: write()");
|
||||
return MINISSDPC_SOCKET_ERROR;
|
||||
}
|
||||
return MINISSDPC_SUCCESS;
|
||||
}
|
||||
|
||||
struct UPNPDev *
|
||||
receiveDevicesFromMiniSSDPD(int s, int * error)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = NULL;
|
||||
unsigned char buffer[256];
|
||||
ssize_t n;
|
||||
unsigned char * p;
|
||||
unsigned char * url;
|
||||
unsigned char * st;
|
||||
unsigned int bufferindex;
|
||||
unsigned int i, ndev;
|
||||
unsigned int urlsize, stsize, usnsize, l;
|
||||
|
||||
n = read(s, buffer, sizeof(buffer));
|
||||
if(n<=0)
|
||||
{
|
||||
perror("minissdpc.c: read()");
|
||||
if (error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
ndev = buffer[0];
|
||||
bufferindex = 1;
|
||||
for(i = 0; i < ndev; i++)
|
||||
{
|
||||
DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
return devlist;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf(" urlsize=%u", urlsize);
|
||||
#endif /* DEBUG */
|
||||
url = malloc(urlsize);
|
||||
if(url == NULL) {
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
return devlist;
|
||||
}
|
||||
READ_COPY_BUFFER(url, urlsize);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_return;
|
||||
}
|
||||
DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf(" stsize=%u", stsize);
|
||||
#endif /* DEBUG */
|
||||
st = malloc(stsize);
|
||||
if (st == NULL) {
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto free_url_and_return;
|
||||
}
|
||||
READ_COPY_BUFFER(st, stsize);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_st_and_return;
|
||||
}
|
||||
DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_st_and_return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf(" usnsize=%u\n", usnsize);
|
||||
#endif /* DEBUG */
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
|
||||
if(tmp == NULL) {
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto free_url_and_st_and_return;
|
||||
}
|
||||
tmp->pNext = devlist;
|
||||
tmp->descURL = tmp->buffer;
|
||||
tmp->st = tmp->buffer + 1 + urlsize;
|
||||
memcpy(tmp->buffer, url, urlsize);
|
||||
tmp->buffer[urlsize] = '\0';
|
||||
memcpy(tmp->st, st, stsize);
|
||||
tmp->buffer[urlsize+1+stsize] = '\0';
|
||||
free(url);
|
||||
free(st);
|
||||
url = NULL;
|
||||
st = NULL;
|
||||
tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
|
||||
READ_COPY_BUFFER(tmp->usn, usnsize);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_tmp_and_return;
|
||||
}
|
||||
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
|
||||
tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
|
||||
devlist = tmp;
|
||||
}
|
||||
if (error)
|
||||
*error = MINISSDPC_SUCCESS;
|
||||
return devlist;
|
||||
|
||||
free_url_and_st_and_return:
|
||||
free(st);
|
||||
free_url_and_return:
|
||||
free(url);
|
||||
return devlist;
|
||||
|
||||
free_tmp_and_return:
|
||||
free(tmp);
|
||||
return devlist;
|
||||
}
|
||||
|
||||
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
|
||||
|
||||
/* 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,
|
||||
const char * * usn, int * usnsize)
|
||||
{
|
||||
int a, b, i;
|
||||
i = 0;
|
||||
a = i; /* start of the line */
|
||||
b = 0; /* end of the "header" (position of the colon) */
|
||||
while(i<size)
|
||||
{
|
||||
switch(reply[i])
|
||||
{
|
||||
case ':':
|
||||
if(b==0)
|
||||
{
|
||||
b = i; /* end of the "header" */
|
||||
/*for(j=a; j<b; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
case '\x0d':
|
||||
if(b!=0)
|
||||
{
|
||||
/*for(j=b+1; j<i; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
putchar('\n');*/
|
||||
/* skip the colon and white spaces */
|
||||
do { b++; } while(reply[b]==' ');
|
||||
if(0==strncasecmp(reply+a, "location", 8))
|
||||
{
|
||||
*location = reply+b;
|
||||
*locationsize = i-b;
|
||||
}
|
||||
else if(0==strncasecmp(reply+a, "st", 2))
|
||||
{
|
||||
*st = reply+b;
|
||||
*stsize = i-b;
|
||||
}
|
||||
else if(0==strncasecmp(reply+a, "usn", 3))
|
||||
{
|
||||
*usn = reply+b;
|
||||
*usnsize = i-b;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
a = i+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* port upnp discover : SSDP protocol */
|
||||
#define SSDP_PORT 1900
|
||||
#define XSTR(s) STR(s)
|
||||
#define STR(s) #s
|
||||
#define UPNP_MCAST_ADDR "239.255.255.250"
|
||||
/* for IPv6 */
|
||||
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
|
||||
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
|
||||
|
||||
/* direct discovery if minissdpd responses are not sufficient */
|
||||
/* ssdpDiscoverDevices() :
|
||||
* return a chained list of all devices found or NULL if
|
||||
* no devices was found.
|
||||
* It is up to the caller to free the chained list
|
||||
* delay is in millisecond (poll).
|
||||
* UDA v1.1 says :
|
||||
* The TTL for the IP packet SHOULD default to 2 and
|
||||
* SHOULD be configurable. */
|
||||
struct UPNPDev *
|
||||
ssdpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = 0;
|
||||
unsigned int scope_id = 0;
|
||||
int opt = 1;
|
||||
static const char MSearchMsgFmt[] =
|
||||
"M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST: %s:" XSTR(SSDP_PORT) "\r\n"
|
||||
"ST: %s\r\n"
|
||||
"MAN: \"ssdp:discover\"\r\n"
|
||||
"MX: %u\r\n"
|
||||
"\r\n";
|
||||
int deviceIndex;
|
||||
char bufr[1536]; /* reception and emission buffer */
|
||||
int sudp;
|
||||
int n;
|
||||
struct sockaddr_storage sockudp_r;
|
||||
unsigned int mx;
|
||||
#ifdef NO_GETADDRINFO
|
||||
struct sockaddr_storage sockudp_w;
|
||||
#else
|
||||
int rv;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
MIB_IPFORWARDROW ip_forward;
|
||||
unsigned long _ttl = (unsigned long)ttl;
|
||||
#endif
|
||||
int linklocal = 1;
|
||||
int sentok;
|
||||
|
||||
if(error)
|
||||
*error = MINISSDPC_UNKNOWN_ERROR;
|
||||
|
||||
if(localport==UPNP_LOCAL_PORT_SAME)
|
||||
localport = SSDP_PORT;
|
||||
|
||||
#ifdef _WIN32
|
||||
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
#else
|
||||
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
if(sudp < 0)
|
||||
{
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("socket");
|
||||
return NULL;
|
||||
}
|
||||
/* reception */
|
||||
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
|
||||
if(ipv6) {
|
||||
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
|
||||
p->sin6_family = AF_INET6;
|
||||
if(localport > 0 && localport < 65536)
|
||||
p->sin6_port = htons((unsigned short)localport);
|
||||
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
|
||||
} else {
|
||||
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
|
||||
p->sin_family = AF_INET;
|
||||
if(localport > 0 && localport < 65536)
|
||||
p->sin_port = htons((unsigned short)localport);
|
||||
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(pIPAddrTable) {
|
||||
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
free(pIPAddrTable);
|
||||
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
|
||||
}
|
||||
}
|
||||
if(pIPAddrTable) {
|
||||
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
|
||||
if (dwRetVal == NO_ERROR) {
|
||||
#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 /* _WIN32 */
|
||||
|
||||
#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 = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ipv6) {
|
||||
#ifdef _WIN32
|
||||
DWORD mcastHops = ttl;
|
||||
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&mcastHops, sizeof(mcastHops)) < 0)
|
||||
#else /* _WIN32 */
|
||||
int mcastHops = ttl;
|
||||
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastHops, sizeof(mcastHops)) < 0)
|
||||
#endif /* _WIN32 */
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt(IPV6_MULTICAST_HOPS,...)");
|
||||
}
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
|
||||
#else /* _WIN32 */
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
|
||||
#endif /* _WIN32 */
|
||||
{
|
||||
/* not a fatal error */
|
||||
PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
|
||||
}
|
||||
}
|
||||
|
||||
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 IPV6_MULTICAST_IF");
|
||||
}
|
||||
#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 IP_MULTICAST_IF");
|
||||
}
|
||||
} 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 IP_MULTICAST_IF");
|
||||
}
|
||||
#elif !defined(_WIN32)
|
||||
struct ifreq ifr;
|
||||
int ifrlen = sizeof(ifr);
|
||||
strncpy(ifr.ifr_name, multicastif, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ-1] = '\0';
|
||||
if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)");
|
||||
}
|
||||
mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
|
||||
}
|
||||
#else /* _WIN32 */
|
||||
#ifdef DEBUG
|
||||
printf("Setting of multicast interface not supported with interface name.\n");
|
||||
#endif
|
||||
#endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("bind");
|
||||
closesocket(sudp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(error)
|
||||
*error = MINISSDPC_SUCCESS;
|
||||
/* Calculating maximum response time in seconds */
|
||||
mx = ((unsigned int)delay) / 1000u;
|
||||
if(mx == 0) {
|
||||
mx = 1;
|
||||
delay = 1000;
|
||||
}
|
||||
/* receiving SSDP response packet */
|
||||
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
|
||||
sentok = 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,
|
||||
deviceTypes[deviceIndex], mx);
|
||||
if ((unsigned int)n >= sizeof(bufr)) {
|
||||
if(error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
/*printf("Sending %s", bufr);*/
|
||||
printf("Sending M-SEARCH request to %s with ST: %s\n",
|
||||
ipv6 ?
|
||||
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
|
||||
: UPNP_MCAST_ADDR,
|
||||
deviceTypes[deviceIndex]);
|
||||
#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(SSDP_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(SSDP_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 = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("sendto");
|
||||
} else {
|
||||
sentok = 1;
|
||||
}
|
||||
#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(SSDP_PORT), &hints, &servinfo)) != 0) {
|
||||
if(error)
|
||||
*error = MINISSDPC_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;
|
||||
} else {
|
||||
sentok = 1;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(servinfo);
|
||||
if(!sentok) {
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
}
|
||||
#endif /* #ifdef NO_GETADDRINFO */
|
||||
/* Waiting for SSDP REPLY packet to M-SEARCH
|
||||
* if searchalltypes is set, enter the loop only
|
||||
* when the last deviceType is reached */
|
||||
if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) do {
|
||||
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
|
||||
if (n < 0) {
|
||||
/* error */
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
goto error;
|
||||
} else if (n == 0) {
|
||||
/* no data or Time Out */
|
||||
#ifdef DEBUG
|
||||
printf("NODATA or TIMEOUT\n");
|
||||
#endif /* DEBUG */
|
||||
if (devlist && !searchalltypes) {
|
||||
/* found some devices, stop now*/
|
||||
if(error)
|
||||
*error = MINISSDPC_SUCCESS;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
const char * descURL=NULL;
|
||||
int urlsize=0;
|
||||
const char * st=NULL;
|
||||
int stsize=0;
|
||||
const char * usn=NULL;
|
||||
int usnsize=0;
|
||||
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
|
||||
if(st&&descURL) {
|
||||
#ifdef DEBUG
|
||||
printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
|
||||
stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
|
||||
#endif /* DEBUG */
|
||||
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' &&
|
||||
(usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
|
||||
tmp->usn[usnsize] == '\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+usnsize);
|
||||
if(!tmp) {
|
||||
/* memory allocation error */
|
||||
if(error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
tmp->pNext = devlist;
|
||||
tmp->descURL = tmp->buffer;
|
||||
tmp->st = tmp->buffer + 1 + urlsize;
|
||||
tmp->usn = tmp->st + 1 + stsize;
|
||||
memcpy(tmp->buffer, descURL, urlsize);
|
||||
tmp->buffer[urlsize] = '\0';
|
||||
memcpy(tmp->st, st, stsize);
|
||||
tmp->buffer[urlsize+1+stsize] = '\0';
|
||||
if(usn != NULL)
|
||||
memcpy(tmp->usn, usn, usnsize);
|
||||
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
|
||||
tmp->scope_id = scope_id;
|
||||
devlist = tmp;
|
||||
}
|
||||
}
|
||||
} while(n > 0);
|
||||
if(ipv6) {
|
||||
/* switch linklocal flag */
|
||||
if(linklocal) {
|
||||
linklocal = 0;
|
||||
--deviceIndex;
|
||||
} else {
|
||||
linklocal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
error:
|
||||
closesocket(sudp);
|
||||
return devlist;
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
/* $Id: minissdpc.h,v 1.7 2015/10/08 16:15:47 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2015 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
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* error codes : */
|
||||
#define MINISSDPC_SUCCESS (0)
|
||||
#define MINISSDPC_UNKNOWN_ERROR (-1)
|
||||
#define MINISSDPC_SOCKET_ERROR (-101)
|
||||
#define MINISSDPC_MEMORY_ERROR (-102)
|
||||
#define MINISSDPC_INVALID_INPUT (-103)
|
||||
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
connectToMiniSSDPD(const char * socketpath);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
disconnectFromMiniSSDPD(int fd);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
requestDevicesFromMiniSSDPD(int fd, const char * devtype);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
receiveDevicesFromMiniSSDPD(int fd, int * error);
|
||||
|
||||
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
ssdpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,722 +0,0 @@
|
||||
/* $Id: miniupnpc.c,v 1.149 2016/02/09 09:50:46 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2016 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
/* Win32 Specific includes and defines */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#include <iphlpapi.h>
|
||||
#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 <unistd.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* Amiga OS 3 specific stuff */
|
||||
#define socklen_t int
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#if !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#endif /* #else _WIN32 */
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
|
||||
#include "miniupnpc.h"
|
||||
#include "minissdpc.h"
|
||||
#include "miniwget.h"
|
||||
#include "minisoap.h"
|
||||
#include "minixml.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "connecthostport.h"
|
||||
|
||||
/* compare the begining of a string with a constant string */
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
#define SOAPPREFIX "s"
|
||||
#define SERVICEPREFIX "u"
|
||||
#define SERVICEPREFIX2 'u'
|
||||
|
||||
/* check if an ip address is a private (LAN) address
|
||||
* see https://tools.ietf.org/html/rfc1918 */
|
||||
static int is_rfc1918addr(const char * addr)
|
||||
{
|
||||
/* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
|
||||
if(COMPARE(addr, "192.168."))
|
||||
return 1;
|
||||
/* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
|
||||
if(COMPARE(addr, "10."))
|
||||
return 1;
|
||||
/* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
|
||||
if(COMPARE(addr, "172.")) {
|
||||
int i = atoi(addr + 4);
|
||||
if((16 <= i) && (i <= 31))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* root description parsing */
|
||||
MINIUPNP_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 */
|
||||
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];
|
||||
int soapbodylen;
|
||||
char * buf;
|
||||
int n;
|
||||
int status_code;
|
||||
|
||||
*bufsize = 0;
|
||||
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
|
||||
if(args==NULL)
|
||||
{
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\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\">"
|
||||
"</" SERVICEPREFIX ":%s>"
|
||||
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
|
||||
"\r\n", action, service, action);
|
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char * p;
|
||||
const char * pe, * pv;
|
||||
const char * const pend = soapbody + sizeof(soapbody);
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\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);
|
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody))
|
||||
return NULL;
|
||||
p = soapbody + soapbodylen;
|
||||
while(args->elt)
|
||||
{
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
|
||||
pe = args->elt;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '>';
|
||||
|
||||
if((pv = args->val))
|
||||
{
|
||||
while(p < pend && *pv)
|
||||
*(p++) = *(pv++);
|
||||
}
|
||||
|
||||
if((p+2) > pend) /* check for space to write next 2 bytes */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
|
||||
pe = args->elt;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '>';
|
||||
|
||||
args++;
|
||||
}
|
||||
if((p+4) > pend) /* check for space to write next 4 bytes */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
*(p++) = SERVICEPREFIX2;
|
||||
*(p++) = ':';
|
||||
|
||||
pe = action;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
|
||||
pend - p);
|
||||
if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
|
||||
return NULL;
|
||||
}
|
||||
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, &status_code);
|
||||
#ifdef DEBUG
|
||||
if(*bufsize > 0 && buf)
|
||||
{
|
||||
printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize);
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
/* upnpDiscoverDevices() :
|
||||
* return a chained list of all devices found or NULL if
|
||||
* no devices was found.
|
||||
* It is up to the caller to free the chained list
|
||||
* delay is in millisecond (poll).
|
||||
* UDA v1.1 says :
|
||||
* The TTL for the IP packet SHOULD default to 2 and
|
||||
* SHOULD be configurable. */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = 0;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
int deviceIndex;
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
|
||||
if(error)
|
||||
*error = UPNPDISCOVER_UNKNOWN_ERROR;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* first try to get infos from minissdpd ! */
|
||||
if(!minissdpdsock)
|
||||
minissdpdsock = "/var/run/minissdpd.sock";
|
||||
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
|
||||
struct UPNPDev * minissdpd_devlist;
|
||||
int only_rootdevice = 1;
|
||||
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
|
||||
minissdpdsock, 0);
|
||||
if(minissdpd_devlist) {
|
||||
#ifdef DEBUG
|
||||
printf("returned by MiniSSDPD: %s\t%s\n",
|
||||
minissdpd_devlist->st, minissdpd_devlist->descURL);
|
||||
#endif /* DEBUG */
|
||||
if(!strstr(minissdpd_devlist->st, "rootdevice"))
|
||||
only_rootdevice = 0;
|
||||
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
|
||||
#ifdef DEBUG
|
||||
printf("returned by MiniSSDPD: %s\t%s\n",
|
||||
tmp->pNext->st, tmp->pNext->descURL);
|
||||
#endif /* DEBUG */
|
||||
if(!strstr(tmp->st, "rootdevice"))
|
||||
only_rootdevice = 0;
|
||||
}
|
||||
tmp->pNext = devlist;
|
||||
devlist = minissdpd_devlist;
|
||||
if(!searchalltypes && !only_rootdevice)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
|
||||
/* We return what we have found if it was not only a rootdevice */
|
||||
if(!strstr(tmp->st, "rootdevice")) {
|
||||
if(error)
|
||||
*error = UPNPDISCOVER_SUCCESS;
|
||||
return devlist;
|
||||
}
|
||||
}
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
|
||||
/* direct discovery if minissdpd responses are not sufficient */
|
||||
{
|
||||
struct UPNPDev * discovered_devlist;
|
||||
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
|
||||
ipv6, ttl, error, searchalltypes);
|
||||
if(devlist == NULL)
|
||||
devlist = discovered_devlist;
|
||||
else {
|
||||
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
|
||||
tmp->pNext = discovered_devlist;
|
||||
}
|
||||
}
|
||||
return devlist;
|
||||
}
|
||||
|
||||
/* upnpDiscover() Discover IGD device */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
static const char * const deviceList[] = {
|
||||
#if 0
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:2",
|
||||
#endif
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
||||
"upnp:rootdevice",
|
||||
/*"ssdp:all",*/
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
/* upnpDiscoverAll() Discover all UPnP devices */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverAll(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
static const char * const deviceList[] = {
|
||||
/*"upnp:rootdevice",*/
|
||||
"ssdp:all",
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
/* upnpDiscoverDevice() Discover a specific device */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
const char * const deviceList[] = {
|
||||
device,
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
static char *
|
||||
build_absolute_url(const char * baseurl, const char * descURL,
|
||||
const char * url, unsigned int scope_id)
|
||||
{
|
||||
int l, n;
|
||||
char * s;
|
||||
const char * base;
|
||||
char * p;
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
char ifname[IF_NAMESIZE];
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
char scope_str[8];
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
|
||||
if( (url[0] == 'h')
|
||||
&&(url[1] == 't')
|
||||
&&(url[2] == 't')
|
||||
&&(url[3] == 'p')
|
||||
&&(url[4] == ':')
|
||||
&&(url[5] == '/')
|
||||
&&(url[6] == '/'))
|
||||
return strdup(url);
|
||||
base = (baseurl[0] == '\0') ? descURL : baseurl;
|
||||
n = strlen(base);
|
||||
if(n > 7) {
|
||||
p = strchr(base + 7, '/');
|
||||
if(p)
|
||||
n = p - base;
|
||||
}
|
||||
l = n + strlen(url) + 1;
|
||||
if(url[0] != '/')
|
||||
l++;
|
||||
if(scope_id != 0) {
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
if(if_indextoname(scope_id, ifname)) {
|
||||
l += 3 + strlen(ifname); /* 3 == strlen(%25) */
|
||||
}
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
/* under windows, scope is numerical */
|
||||
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
}
|
||||
s = malloc(l);
|
||||
if(s == NULL) return NULL;
|
||||
memcpy(s, base, n);
|
||||
if(scope_id != 0) {
|
||||
s[n] = '\0';
|
||||
if(0 == memcmp(s, "http://[fe80:", 13)) {
|
||||
/* this is a linklocal IPv6 address */
|
||||
p = strchr(s, ']');
|
||||
if(p) {
|
||||
/* insert %25<scope> into URL */
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, ifname, strlen(ifname));
|
||||
n += 3 + strlen(ifname);
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, scope_str, strlen(scope_str));
|
||||
n += 3 + strlen(scope_str);
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
}
|
||||
}
|
||||
}
|
||||
if(url[0] != '/')
|
||||
s[n++] = '/';
|
||||
memcpy(s + n, url, l - n);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Prepare the Urls for usage...
|
||||
*/
|
||||
MINIUPNP_LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * descURL, unsigned int scope_id)
|
||||
{
|
||||
/* strdup descURL */
|
||||
urls->rootdescURL = strdup(descURL);
|
||||
|
||||
/* get description of WANIPConnection */
|
||||
urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.scpdurl, scope_id);
|
||||
urls->controlURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.controlurl, scope_id);
|
||||
urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
|
||||
data->CIF.controlurl, scope_id);
|
||||
urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
|
||||
data->IPv6FC.controlurl, scope_id);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
|
||||
printf("urls->controlURL='%s'\n", urls->controlURL);
|
||||
printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
|
||||
printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
|
||||
#endif
|
||||
}
|
||||
|
||||
MINIUPNP_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 if(0 == strcmp("Up", status)) /* Also accept "Up" */
|
||||
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. Dont forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
MINIUPNP_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];
|
||||
char myLanAddr[40];
|
||||
int status_code = -1;
|
||||
|
||||
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),
|
||||
myLanAddr, sizeof(myLanAddr),
|
||||
dev->scope_id, &status_code);
|
||||
#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(COMPARE(data->CIF.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
|
||||
{
|
||||
desc[i].is_igd = 1;
|
||||
n_igd++;
|
||||
if(lanaddr)
|
||||
strncpy(lanaddr, myLanAddr, lanaddrlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 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 )
|
||||
{
|
||||
int is_connected;
|
||||
|
||||
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;
|
||||
is_connected = UPNPIGD_IsConnected(urls, data);
|
||||
#ifdef DEBUG
|
||||
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||
urls->controlURL, is_connected);
|
||||
#endif
|
||||
/* checks that status is connected AND there is a external IP address assigned */
|
||||
if(is_connected &&
|
||||
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
|
||||
if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
|
||||
&& (0 != strcmp(extIpAddr, "0.0.0.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);
|
||||
is_connected = UPNPIGD_IsConnected(urls, data);
|
||||
#ifdef DEBUG
|
||||
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||
urls->controlURL, is_connected);
|
||||
#endif
|
||||
if(is_connected &&
|
||||
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
|
||||
if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
|
||||
&& (0 != strcmp(extIpAddr, "0.0.0.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, NULL);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
LIBRARY
|
||||
; miniupnpc library
|
||||
miniupnpc
|
||||
|
||||
EXPORTS
|
||||
; miniupnpc
|
||||
upnpDiscover
|
||||
freeUPNPDevlist
|
||||
parserootdesc
|
||||
UPNP_GetValidIGD
|
||||
UPNP_GetIGDFromUrl
|
||||
GetUPNPUrls
|
||||
FreeUPNPUrls
|
||||
; miniwget
|
||||
miniwget
|
||||
miniwget_getaddr
|
||||
; upnpcommands
|
||||
UPNP_GetTotalBytesSent
|
||||
UPNP_GetTotalBytesReceived
|
||||
UPNP_GetTotalPacketsSent
|
||||
UPNP_GetTotalPacketsReceived
|
||||
UPNP_GetStatusInfo
|
||||
UPNP_GetConnectionTypeInfo
|
||||
UPNP_GetExternalIPAddress
|
||||
UPNP_GetLinkLayerMaxBitRates
|
||||
UPNP_AddPortMapping
|
||||
UPNP_AddAnyPortMapping
|
||||
UPNP_DeletePortMapping
|
||||
UPNP_DeletePortMappingRange
|
||||
UPNP_GetPortMappingNumberOfEntries
|
||||
UPNP_GetSpecificPortMappingEntry
|
||||
UPNP_GetGenericPortMappingEntry
|
||||
UPNP_GetListOfPortMappings
|
||||
UPNP_AddPinhole
|
||||
UPNP_CheckPinholeWorking
|
||||
UPNP_UpdatePinhole
|
||||
UPNP_GetPinholePackets
|
||||
UPNP_DeletePinhole
|
||||
UPNP_GetFirewallStatus
|
||||
UPNP_GetOutboundPinholeTimeout
|
||||
; upnperrors
|
||||
strupnperror
|
||||
; portlistingparse
|
||||
ParsePortListing
|
||||
FreePortListing
|
@ -1,152 +0,0 @@
|
||||
/* $Id: miniupnpc.h,v 1.50 2016/04/19 21:06:21 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2016 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 "miniupnpc_declspec.h"
|
||||
#include "igd_desc_parse.h"
|
||||
#include "upnpdev.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 "2.0.20171212"
|
||||
#define MINIUPNPC_API_VERSION 16
|
||||
|
||||
/* Source port:
|
||||
Using "1" as an alias for 1900 for backwards compatability
|
||||
(presuming one would have used that for the "sameport" parameter) */
|
||||
#define UPNP_LOCAL_PORT_ANY 0
|
||||
#define UPNP_LOCAL_PORT_SAME 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structures definitions : */
|
||||
struct UPNParg { const char * elt; const char * val; };
|
||||
|
||||
char *
|
||||
simpleUPnPcommand(int, const char *, const char *,
|
||||
const char *, struct UPNParg *,
|
||||
int *);
|
||||
|
||||
/* 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 localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
|
||||
* from the source port 1900 (same as destination port), if set to
|
||||
* UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
|
||||
* be attempted as the source port.
|
||||
* "searchalltypes" parameter is useful when searching several types,
|
||||
* if 0, the discovery will stop with the first type returning results.
|
||||
* TTL should default to 2. */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverAll(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes);
|
||||
|
||||
/* parserootdesc() :
|
||||
* parse root XML description of a UPnP device and fill the IGDdatas
|
||||
* structure. */
|
||||
MINIUPNP_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.
|
||||
*/
|
||||
MINIUPNP_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.
|
||||
* When succeding, urls, data, and lanaddr arguments are set.
|
||||
* return value :
|
||||
* 0 - Not ok
|
||||
* 1 - OK */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen);
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *,
|
||||
const char *, unsigned int);
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreeUPNPUrls(struct UPNPUrls *);
|
||||
|
||||
/* return 0 or 1 */
|
||||
MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,21 +0,0 @@
|
||||
#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
|
||||
#define MINIUPNPC_DECLSPEC_H_INCLUDED
|
||||
|
||||
#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
|
||||
/* for windows dll */
|
||||
#ifdef MINIUPNP_EXPORTS
|
||||
#define MINIUPNP_LIBSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define MINIUPNP_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 MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define MINIUPNP_LIBSPEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */
|
||||
|
@ -1,703 +0,0 @@
|
||||
/* $Id: miniupnpcmodule.c,v 1.31 2017/11/02 15:37:28 nanard Exp $*/
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* website : http://miniupnp.tuxfamily.org/
|
||||
* copyright (c) 2007-2016 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#include <Python.h>
|
||||
#define MINIUPNP_STATICLIB
|
||||
#include "structmember.h"
|
||||
#include "miniupnpc.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "upnperrors.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
/* for compatibility with Python < 2.4 */
|
||||
#ifndef Py_RETURN_NONE
|
||||
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
|
||||
#endif
|
||||
|
||||
#ifndef Py_RETURN_TRUE
|
||||
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
|
||||
#endif
|
||||
|
||||
#ifndef Py_RETURN_FALSE
|
||||
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
|
||||
#endif
|
||||
|
||||
/* for compatibility with Python < 3.0 */
|
||||
#ifndef PyVarObject_HEAD_INIT
|
||||
#define PyVarObject_HEAD_INIT(type, size) \
|
||||
PyObject_HEAD_INIT(type) size,
|
||||
#endif
|
||||
|
||||
#ifndef Py_TYPE
|
||||
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
/* Type-specific fields go here. */
|
||||
struct UPNPDev * devlist;
|
||||
struct UPNPUrls urls;
|
||||
struct IGDdatas data;
|
||||
unsigned int discoverdelay; /* value passed to upnpDiscover() */
|
||||
unsigned int localport; /* value passed to upnpDiscover() */
|
||||
char lanaddr[40]; /* our ip address on the LAN */
|
||||
char * multicastif;
|
||||
char * minissdpdsocket;
|
||||
} UPnPObject;
|
||||
|
||||
static PyMemberDef UPnP_members[] = {
|
||||
{"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
|
||||
READONLY, "ip address on the LAN"
|
||||
},
|
||||
{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
|
||||
0/*READWRITE*/, "value in ms used to wait for SSDP responses"
|
||||
},
|
||||
{"localport", T_UINT, offsetof(UPnPObject, localport),
|
||||
0/*READWRITE*/,
|
||||
"If localport is set to UPNP_LOCAL_PORT_SAME(1) "
|
||||
"SSDP packets will be sent from the source port "
|
||||
"1900 (same as destination port), if set to "
|
||||
"UPNP_LOCAL_PORT_ANY(0) system assign a source "
|
||||
"port, any other value will be attempted as the "
|
||||
"source port"
|
||||
},
|
||||
/* T_STRING is allways readonly :( */
|
||||
{"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
|
||||
0, "IP of the network interface to be used for multicast operations"
|
||||
},
|
||||
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
|
||||
0, "path of the MiniSSDPd unix socket"
|
||||
},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char* multicastif = NULL;
|
||||
char* minissdpdsocket = NULL;
|
||||
static char *kwlist[] = {
|
||||
"multicastif", "minissdpdsocket", "discoverdelay",
|
||||
"localport", NULL
|
||||
};
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
|
||||
&multicastif,
|
||||
&minissdpdsocket,
|
||||
&self->discoverdelay,
|
||||
&self->localport))
|
||||
return -1;
|
||||
|
||||
if(self->localport>1 &&
|
||||
(self->localport>65534||self->localport<1024)) {
|
||||
PyErr_SetString(PyExc_Exception, "Invalid localport value");
|
||||
return -1;
|
||||
}
|
||||
if(multicastif)
|
||||
self->multicastif = strdup(multicastif);
|
||||
if(minissdpdsocket)
|
||||
self->minissdpdsocket = strdup(minissdpdsocket);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
UPnPObject_dealloc(UPnPObject *self)
|
||||
{
|
||||
freeUPNPDevlist(self->devlist);
|
||||
FreeUPNPUrls(&self->urls);
|
||||
free(self->multicastif);
|
||||
free(self->minissdpdsocket);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_discover(UPnPObject *self)
|
||||
{
|
||||
struct UPNPDev * dev;
|
||||
int i;
|
||||
PyObject *res = NULL;
|
||||
if(self->devlist)
|
||||
{
|
||||
freeUPNPDevlist(self->devlist);
|
||||
self->devlist = 0;
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
|
||||
self->multicastif,
|
||||
self->minissdpdsocket,
|
||||
(int)self->localport,
|
||||
0/*ip v6*/,
|
||||
2/* TTL */,
|
||||
0/*error */);
|
||||
Py_END_ALLOW_THREADS
|
||||
/* Py_RETURN_NONE ??? */
|
||||
for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
|
||||
i++;
|
||||
res = Py_BuildValue("i", i);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_selectigd(UPnPObject *self)
|
||||
{
|
||||
int r;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
|
||||
self->lanaddr, sizeof(self->lanaddr));
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r)
|
||||
{
|
||||
return Py_BuildValue("s", self->urls.controlURL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_totalbytesent(UPnPObject *self)
|
||||
{
|
||||
UNSIGNED_INTEGER i;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
|
||||
self->data.CIF.servicetype);
|
||||
Py_END_ALLOW_THREADS
|
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
|
||||
return Py_BuildValue("I", i);
|
||||
#else
|
||||
return Py_BuildValue("i", (int)i);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_totalbytereceived(UPnPObject *self)
|
||||
{
|
||||
UNSIGNED_INTEGER i;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
|
||||
self->data.CIF.servicetype);
|
||||
Py_END_ALLOW_THREADS
|
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
|
||||
return Py_BuildValue("I", i);
|
||||
#else
|
||||
return Py_BuildValue("i", (int)i);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_totalpacketsent(UPnPObject *self)
|
||||
{
|
||||
UNSIGNED_INTEGER i;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
|
||||
self->data.CIF.servicetype);
|
||||
Py_END_ALLOW_THREADS
|
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
|
||||
return Py_BuildValue("I", i);
|
||||
#else
|
||||
return Py_BuildValue("i", (int)i);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_totalpacketreceived(UPnPObject *self)
|
||||
{
|
||||
UNSIGNED_INTEGER i;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
|
||||
self->data.CIF.servicetype);
|
||||
Py_END_ALLOW_THREADS
|
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
|
||||
return Py_BuildValue("I", i);
|
||||
#else
|
||||
return Py_BuildValue("i", (int)i);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_statusinfo(UPnPObject *self)
|
||||
{
|
||||
char status[64];
|
||||
char lastconnerror[64];
|
||||
unsigned int uptime = 0;
|
||||
int r;
|
||||
status[0] = '\0';
|
||||
lastconnerror[0] = '\0';
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
|
||||
status, &uptime, lastconnerror);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
|
||||
return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
|
||||
#else
|
||||
return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);
|
||||
#endif
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_connectiontype(UPnPObject *self)
|
||||
{
|
||||
char connectionType[64];
|
||||
int r;
|
||||
connectionType[0] = '\0';
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
|
||||
self->data.first.servicetype,
|
||||
connectionType);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
return Py_BuildValue("s", connectionType);
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_externalipaddress(UPnPObject *self)
|
||||
{
|
||||
char externalIPAddress[40];
|
||||
int r;
|
||||
externalIPAddress[0] = '\0';
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
r = UPNP_GetExternalIPAddress(self->urls.controlURL,
|
||||
self->data.first.servicetype,
|
||||
externalIPAddress);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
return Py_BuildValue("s", externalIPAddress);
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
|
||||
* remoteHost)
|
||||
* protocol is 'UDP' or 'TCP' */
|
||||
static PyObject *
|
||||
UPnP_addportmapping(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
char extPort[6];
|
||||
unsigned short ePort;
|
||||
char inPort[6];
|
||||
unsigned short iPort;
|
||||
const char * proto;
|
||||
const char * host;
|
||||
const char * desc;
|
||||
const char * remoteHost;
|
||||
const char * leaseDuration = "0";
|
||||
int r;
|
||||
if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto,
|
||||
&host, &iPort, &desc, &remoteHost))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sprintf(extPort, "%hu", ePort);
|
||||
sprintf(inPort, "%hu", iPort);
|
||||
r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
|
||||
extPort, inPort, host, desc, proto,
|
||||
remoteHost, leaseDuration);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: RAISE an Exception. See upnpcommands.h for errors codes.
|
||||
// upnperrors.c
|
||||
//Py_RETURN_FALSE;
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
|
||||
* remoteHost)
|
||||
* protocol is 'UDP' or 'TCP' */
|
||||
static PyObject *
|
||||
UPnP_addanyportmapping(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
char extPort[6];
|
||||
unsigned short ePort;
|
||||
char inPort[6];
|
||||
unsigned short iPort;
|
||||
char reservedPort[6];
|
||||
const char * proto;
|
||||
const char * host;
|
||||
const char * desc;
|
||||
const char * remoteHost;
|
||||
const char * leaseDuration = "0";
|
||||
int r;
|
||||
if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto, &host, &iPort, &desc, &remoteHost))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sprintf(extPort, "%hu", ePort);
|
||||
sprintf(inPort, "%hu", iPort);
|
||||
r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,
|
||||
extPort, inPort, host, desc, proto,
|
||||
remoteHost, leaseDuration, reservedPort);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
return Py_BuildValue("i", atoi(reservedPort));
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* DeletePortMapping(extPort, proto, removeHost='')
|
||||
* proto = 'UDP', 'TCP' */
|
||||
static PyObject *
|
||||
UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
char extPort[6];
|
||||
unsigned short ePort;
|
||||
const char * proto;
|
||||
const char * remoteHost = "";
|
||||
int r;
|
||||
if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sprintf(extPort, "%hu", ePort);
|
||||
r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
|
||||
extPort, proto, remoteHost);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
Py_RETURN_TRUE;
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* DeletePortMappingRange(extPort, proto, removeHost='')
|
||||
* proto = 'UDP', 'TCP' */
|
||||
static PyObject *
|
||||
UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
char extPortStart[6];
|
||||
unsigned short ePortStart;
|
||||
char extPortEnd[6];
|
||||
unsigned short ePortEnd;
|
||||
const char * proto;
|
||||
unsigned char manage;
|
||||
char manageStr[1];
|
||||
int r;
|
||||
if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sprintf(extPortStart, "%hu", ePortStart);
|
||||
sprintf(extPortEnd, "%hu", ePortEnd);
|
||||
sprintf(manageStr, "%hhu", manage);
|
||||
r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,
|
||||
extPortStart, extPortEnd, proto, manageStr);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
Py_RETURN_TRUE;
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_getportmappingnumberofentries(UPnPObject *self)
|
||||
{
|
||||
unsigned int n = 0;
|
||||
int r;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
|
||||
self->data.first.servicetype,
|
||||
&n);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
|
||||
return Py_BuildValue("I", n);
|
||||
#else
|
||||
return Py_BuildValue("i", (int)n);
|
||||
#endif
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* GetSpecificPortMapping(ePort, proto, remoteHost='')
|
||||
* proto = 'UDP' or 'TCP' */
|
||||
static PyObject *
|
||||
UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
char extPort[6];
|
||||
unsigned short ePort;
|
||||
const char * proto;
|
||||
const char * remoteHost = "";
|
||||
char intClient[40];
|
||||
char intPort[6];
|
||||
unsigned short iPort;
|
||||
char desc[80];
|
||||
char enabled[4];
|
||||
char leaseDuration[16];
|
||||
if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
|
||||
return NULL;
|
||||
extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
|
||||
desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sprintf(extPort, "%hu", ePort);
|
||||
UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
|
||||
self->data.first.servicetype,
|
||||
extPort, proto, remoteHost,
|
||||
intClient, intPort,
|
||||
desc, enabled, leaseDuration);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(intClient[0])
|
||||
{
|
||||
iPort = (unsigned short)atoi(intPort);
|
||||
return Py_BuildValue("(s,H,s,O,i)",
|
||||
intClient, iPort, desc,
|
||||
PyBool_FromLong(atoi(enabled)),
|
||||
atoi(leaseDuration));
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* GetGenericPortMapping(index) */
|
||||
static PyObject *
|
||||
UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
int i, r;
|
||||
char index[8];
|
||||
char intClient[40];
|
||||
char intPort[6];
|
||||
unsigned short iPort;
|
||||
char extPort[6];
|
||||
unsigned short ePort;
|
||||
char protocol[4];
|
||||
char desc[80];
|
||||
char enabled[6];
|
||||
char rHost[64];
|
||||
char duration[16]; /* lease duration */
|
||||
unsigned int dur;
|
||||
if(!PyArg_ParseTuple(args, "i", &i))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
snprintf(index, sizeof(index), "%d", i);
|
||||
rHost[0] = '\0'; enabled[0] = '\0';
|
||||
duration[0] = '\0'; desc[0] = '\0';
|
||||
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
|
||||
r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
|
||||
self->data.first.servicetype,
|
||||
index,
|
||||
extPort, intClient, intPort,
|
||||
protocol, desc, enabled, rHost,
|
||||
duration);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
ePort = (unsigned short)atoi(extPort);
|
||||
iPort = (unsigned short)atoi(intPort);
|
||||
dur = (unsigned int)strtoul(duration, 0, 0);
|
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
|
||||
return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
|
||||
ePort, protocol, intClient, iPort,
|
||||
desc, enabled, rHost, dur);
|
||||
#else
|
||||
return Py_BuildValue("(i,s,(s,i),s,s,s,i)",
|
||||
(int)ePort, protocol, intClient, (int)iPort,
|
||||
desc, enabled, rHost, (int)dur);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* miniupnpc.UPnP object Method Table */
|
||||
static PyMethodDef UPnP_methods[] = {
|
||||
{"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
|
||||
"discover UPnP IGD devices on the network"
|
||||
},
|
||||
{"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
|
||||
"select a valid UPnP IGD among discovered devices"
|
||||
},
|
||||
{"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
|
||||
"return the total number of bytes sent by UPnP IGD"
|
||||
},
|
||||
{"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
|
||||
"return the total number of bytes received by UPnP IGD"
|
||||
},
|
||||
{"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
|
||||
"return the total number of packets sent by UPnP IGD"
|
||||
},
|
||||
{"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
|
||||
"return the total number of packets received by UPnP IGD"
|
||||
},
|
||||
{"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
|
||||
"return status and uptime"
|
||||
},
|
||||
{"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
|
||||
"return IGD WAN connection type"
|
||||
},
|
||||
{"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
|
||||
"return external IP address"
|
||||
},
|
||||
{"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
|
||||
"add a port mapping"
|
||||
},
|
||||
{"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,
|
||||
"add a port mapping, IGD to select alternative if necessary"
|
||||
},
|
||||
{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
|
||||
"delete a port mapping"
|
||||
},
|
||||
{"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,
|
||||
"delete a range of port mappings"
|
||||
},
|
||||
{"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
|
||||
"-- non standard --"
|
||||
},
|
||||
{"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
|
||||
"get details about a specific port mapping entry"
|
||||
},
|
||||
{"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
|
||||
"get all details about the port mapping at index"
|
||||
},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject UPnPType = {
|
||||
PyVarObject_HEAD_INIT(NULL,
|
||||
0) /*ob_size*/
|
||||
"miniupnpc.UPnP", /*tp_name*/
|
||||
sizeof(UPnPObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
(destructor)UPnPObject_dealloc,/*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash */
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
"UPnP objects", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
UPnP_methods, /* tp_methods */
|
||||
UPnP_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)UPnP_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
#ifndef _WIN32
|
||||
PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* module methods */
|
||||
static PyMethodDef miniupnpc_methods[] = {
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"miniupnpc", /* m_name */
|
||||
"miniupnpc module.", /* m_doc */
|
||||
-1, /* m_size */
|
||||
miniupnpc_methods, /* m_methods */
|
||||
NULL, /* m_reload */
|
||||
NULL, /* m_traverse */
|
||||
NULL, /* m_clear */
|
||||
NULL, /* m_free */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
|
||||
#define PyMODINIT_FUNC void
|
||||
#endif
|
||||
|
||||
PyMODINIT_FUNC
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyInit_miniupnpc(void)
|
||||
#else
|
||||
initminiupnpc(void)
|
||||
#endif
|
||||
{
|
||||
PyObject* m;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* initialize Winsock. */
|
||||
WSADATA wsaData;
|
||||
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
|
||||
UPnPType.tp_new = PyType_GenericNew;
|
||||
#endif
|
||||
if (PyType_Ready(&UPnPType) < 0)
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return 0;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
m = PyModule_Create(&moduledef);
|
||||
#else
|
||||
m = Py_InitModule3("miniupnpc", miniupnpc_methods,
|
||||
"miniupnpc module.");
|
||||
#endif
|
||||
|
||||
Py_INCREF(&UPnPType);
|
||||
PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2014 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"
|
||||
|
||||
#if 0
|
||||
/* according to "UPnP Device Architecture 1.0" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.0"
|
||||
#else
|
||||
/* according to "UPnP Device Architecture 1.1" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
|
@ -1,673 +0,0 @@
|
||||
/* $Id: miniwget.c,v 1.77 2017/05/09 10:04:57 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2017 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#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 <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#define socklen_t int
|
||||
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/select.h>
|
||||
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#define closesocket close
|
||||
#include <strings.h>
|
||||
#endif /* #else _WIN32 */
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif /* __GNU__ */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#endif /* MIN */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define OS_STRING "Win32"
|
||||
#define MINIUPNPC_VERSION_STRING "2.0"
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define OS_STRING "Android"
|
||||
#define MINIUPNPC_VERSION_STRING "2.0"
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#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, int * status_code)
|
||||
{
|
||||
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;
|
||||
#ifdef DEBUG
|
||||
char * reason_phrase = NULL;
|
||||
int reason_phrase_len = 0;
|
||||
#endif
|
||||
|
||||
if(status_code) *status_code = -1;
|
||||
header_buf = malloc(header_buf_len);
|
||||
if(header_buf == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
|
||||
#endif /* DEBUG */
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = malloc(content_buf_len);
|
||||
if(content_buf == NULL)
|
||||
{
|
||||
free(header_buf);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
|
||||
#endif /* DEBUG */
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
chunksize_buf[0] = '\0';
|
||||
chunksize_buf_index = 0;
|
||||
|
||||
while((n = receivedata(s, buf, sizeof(buf), 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) {
|
||||
char * tmp = realloc(header_buf, header_buf_used + n);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(header_buf);
|
||||
free(content_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
header_buf = tmp;
|
||||
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(linestart > 0 && 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(linestart == 0 && status_code)
|
||||
{
|
||||
/* Status line
|
||||
* HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
|
||||
int sp;
|
||||
for(sp = 0; sp < i; sp++)
|
||||
if(header_buf[sp] == ' ')
|
||||
{
|
||||
if(*status_code < 0)
|
||||
*status_code = atoi(header_buf + sp + 1);
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
reason_phrase = header_buf + sp + 1;
|
||||
reason_phrase_len = i - sp - 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("HTTP status code = %d, Reason phrase = %.*s\n",
|
||||
*status_code, reason_phrase_len, reason_phrase);
|
||||
#endif
|
||||
}
|
||||
else 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<n && buf[i] == '\r') i++;
|
||||
if(i<n && buf[i] == '\n') i++;
|
||||
}
|
||||
while(i<n && isxdigit(buf[i])
|
||||
&& chunksize_buf_index < (sizeof(chunksize_buf)-1))
|
||||
{
|
||||
chunksize_buf[chunksize_buf_index++] = buf[i];
|
||||
chunksize_buf[chunksize_buf_index] = '\0';
|
||||
i++;
|
||||
}
|
||||
while(i<n && buf[i] != '\r' && buf[i] != '\n')
|
||||
i++; /* discarding chunk-extension */
|
||||
if(i<n && buf[i] == '\r') i++;
|
||||
if(i<n && buf[i] == '\n') {
|
||||
unsigned int j;
|
||||
for(j = 0; j < chunksize_buf_index; j++) {
|
||||
if(chunksize_buf[j] >= '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;
|
||||
}
|
||||
}
|
||||
/* it is guaranteed that (n >= i) */
|
||||
bytestocopy = (chunksize < (unsigned int)(n - i))?chunksize:(unsigned int)(n - i);
|
||||
if((content_buf_used + bytestocopy) > content_buf_len)
|
||||
{
|
||||
char * tmp;
|
||||
if((content_length >= 0) && ((unsigned int)content_length >= (content_buf_used + bytestocopy))) {
|
||||
content_buf_len = content_length;
|
||||
} else {
|
||||
content_buf_len = content_buf_used + bytestocopy;
|
||||
}
|
||||
tmp = realloc(content_buf, content_buf_len);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(content_buf);
|
||||
free(header_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = tmp;
|
||||
}
|
||||
memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
|
||||
content_buf_used += bytestocopy;
|
||||
i += bytestocopy;
|
||||
chunksize -= bytestocopy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not chunked */
|
||||
if(content_length > 0
|
||||
&& (content_buf_used + n) > (unsigned int)content_length) {
|
||||
/* skipping additional bytes */
|
||||
n = content_length - content_buf_used;
|
||||
}
|
||||
if(content_buf_used + n > content_buf_len)
|
||||
{
|
||||
char * tmp;
|
||||
if(content_length >= 0
|
||||
&& (unsigned int)content_length >= (content_buf_used + n)) {
|
||||
content_buf_len = content_length;
|
||||
} else {
|
||||
content_buf_len = content_buf_used + n;
|
||||
}
|
||||
tmp = realloc(content_buf, content_buf_len);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(content_buf);
|
||||
free(header_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = tmp;
|
||||
}
|
||||
memcpy(content_buf + content_buf_used, buf, n);
|
||||
content_buf_used += n;
|
||||
}
|
||||
}
|
||||
/* use the Content-Length header value if available */
|
||||
if(content_length > 0 && content_buf_used >= (unsigned int)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,
|
||||
int * status_code)
|
||||
{
|
||||
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_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
|
||||
"\r\n",
|
||||
path, httpversion, host, port);
|
||||
if ((unsigned int)len >= sizeof(buf))
|
||||
{
|
||||
closesocket(s);
|
||||
return NULL;
|
||||
}
|
||||
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, status_code);
|
||||
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, int * status_code)
|
||||
{
|
||||
char * respbuffer;
|
||||
|
||||
#if 1
|
||||
respbuffer = miniwget3(host, port, path, size,
|
||||
addr_str, addr_str_len, "1.1",
|
||||
scope_id, status_code);
|
||||
#else
|
||||
respbuffer = miniwget3(host, port, path, size,
|
||||
addr_str, addr_str_len, "1.0",
|
||||
scope_id, status_code);
|
||||
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, status_code);
|
||||
}
|
||||
#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, int * status_code)
|
||||
{
|
||||
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, status_code);
|
||||
}
|
||||
|
||||
void *
|
||||
miniwget_getaddr(const char * url, int * size,
|
||||
char * addr, int addrlen, unsigned int scope_id,
|
||||
int * status_code)
|
||||
{
|
||||
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, status_code);
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2016 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 "miniupnpc_declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size, int * status_code);
|
||||
|
||||
MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *);
|
||||
|
||||
MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *);
|
||||
|
||||
int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,231 +0,0 @@
|
||||
/* $Id: minixml.c,v 1.12 2017/12/12 11:17:40 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* 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-2017, 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 <string.h>
|
||||
#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, "<!--", 4)))
|
||||
{
|
||||
p->xml += 3;
|
||||
/* ignore comments */
|
||||
do
|
||||
{
|
||||
p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
while(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;
|
||||
}
|
||||
/* CDATA are at least 9 + 3 characters long : <![CDATA[ ]]> */
|
||||
if((p->xmlend >= (p->xml + (9 + 3))) && (memcmp(p->xml, "<![CDATA[", 9) == 0))
|
||||
{
|
||||
/* CDATA handling */
|
||||
p->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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,163 +0,0 @@
|
||||
/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */
|
||||
/* MiniUPnP Project
|
||||
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||
* minixmlvalid.c :
|
||||
* validation program for the minixml parser
|
||||
*
|
||||
* (c) 2006-2011 Thomas Bernard */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* xml event structure */
|
||||
struct event {
|
||||
enum { ELTSTART, ELTEND, ATT, CHARDATA } type;
|
||||
const char * data;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct eventlist {
|
||||
int n;
|
||||
struct event * events;
|
||||
};
|
||||
|
||||
/* compare 2 xml event lists
|
||||
* return 0 if the two lists are equals */
|
||||
int evtlistcmp(struct eventlist * a, struct eventlist * b)
|
||||
{
|
||||
int i;
|
||||
struct event * ae, * be;
|
||||
if(a->n != b->n)
|
||||
{
|
||||
printf("event number not matching : %d != %d\n", a->n, b->n);
|
||||
/*return 1;*/
|
||||
}
|
||||
for(i=0; i<a->n; i++)
|
||||
{
|
||||
ae = a->events + i;
|
||||
be = b->events + i;
|
||||
if( (ae->type != be->type)
|
||||
||(ae->len != be->len)
|
||||
||memcmp(ae->data, be->data, ae->len))
|
||||
{
|
||||
printf("Found a difference : %d '%.*s' != %d '%.*s'\n",
|
||||
ae->type, ae->len, ae->data,
|
||||
be->type, be->len, be->data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test data */
|
||||
static const char xmldata[] =
|
||||
"<xmlroot>\n"
|
||||
" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">"
|
||||
"character data"
|
||||
"</elt1> \n \t"
|
||||
"<elt1b/>"
|
||||
"<elt1>\n<![CDATA[ <html>stuff !\n ]]> \n</elt1>\n"
|
||||
"<elt2a> \t<elt2b>chardata1</elt2b><elt2b> chardata2 </elt2b></elt2a>"
|
||||
"</xmlroot>";
|
||||
|
||||
static const struct event evtref[] =
|
||||
{
|
||||
{ELTSTART, "xmlroot", 7},
|
||||
{ELTSTART, "elt1", 4},
|
||||
/* attributes */
|
||||
{CHARDATA, "character data", 14},
|
||||
{ELTEND, "elt1", 4},
|
||||
{ELTSTART, "elt1b", 5},
|
||||
{ELTSTART, "elt1", 4},
|
||||
{CHARDATA, " <html>stuff !\n ", 16},
|
||||
{ELTEND, "elt1", 4},
|
||||
{ELTSTART, "elt2a", 5},
|
||||
{ELTSTART, "elt2b", 5},
|
||||
{CHARDATA, "chardata1", 9},
|
||||
{ELTEND, "elt2b", 5},
|
||||
{ELTSTART, "elt2b", 5},
|
||||
{CHARDATA, " chardata2 ", 11},
|
||||
{ELTEND, "elt2b", 5},
|
||||
{ELTEND, "elt2a", 5},
|
||||
{ELTEND, "xmlroot", 7}
|
||||
};
|
||||
|
||||
void startelt(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("startelt : %.*s\n", l, p);*/
|
||||
evt->type = ELTSTART;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
void endelt(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("endelt : %.*s\n", l, p);*/
|
||||
evt->type = ELTEND;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
void chardata(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("chardata : '%.*s'\n", l, p);*/
|
||||
evt->type = CHARDATA;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
int testxmlparser(const char * xml, int size)
|
||||
{
|
||||
int r;
|
||||
struct eventlist evtlist;
|
||||
struct eventlist evtlistref;
|
||||
struct xmlparser parser;
|
||||
evtlist.n = 0;
|
||||
evtlist.events = malloc(sizeof(struct event)*100);
|
||||
if(evtlist.events == NULL)
|
||||
{
|
||||
fprintf(stderr, "Memory allocation error.\n");
|
||||
return -1;
|
||||
}
|
||||
memset(&parser, 0, sizeof(parser));
|
||||
parser.xmlstart = xml;
|
||||
parser.xmlsize = size;
|
||||
parser.data = &evtlist;
|
||||
parser.starteltfunc = startelt;
|
||||
parser.endeltfunc = endelt;
|
||||
parser.datafunc = chardata;
|
||||
parsexml(&parser);
|
||||
printf("%d events\n", evtlist.n);
|
||||
/* compare */
|
||||
evtlistref.n = sizeof(evtref)/sizeof(struct event);
|
||||
evtlistref.events = (struct event *)evtref;
|
||||
r = evtlistcmp(&evtlistref, &evtlist);
|
||||
free(evtlist.events);
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
int r;
|
||||
(void)argc; (void)argv;
|
||||
|
||||
r = testxmlparser(xmldata, sizeof(xmldata)-1);
|
||||
if(r)
|
||||
printf("minixml validation test failed\n");
|
||||
return r;
|
||||
}
|
||||
|
@ -1,172 +0,0 @@
|
||||
/* $Id: portlistingparse.c,v 1.10 2016/12/16 08:53:21 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2016 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif /* DEBUG */
|
||||
#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(strlen(elements[i].str) == (size_t)l && 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));
|
||||
if(pm == NULL)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"startelt");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
pm->l_next = pdata->l_head; /* insert in list */
|
||||
pdata->l_head = pm;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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->l_head;
|
||||
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));
|
||||
/* 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->l_head) != NULL)
|
||||
{
|
||||
/* remove from list */
|
||||
pdata->l_head = pm->l_next;
|
||||
free(pm);
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2015 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 "miniupnpc_declspec.h"
|
||||
/* for the definition of UNSIGNED_INTEGER */
|
||||
#include "miniupnpctypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* sample of PortMappingEntry :
|
||||
<p:PortMappingEntry>
|
||||
<p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
|
||||
<p:NewExternalPort>2345</p:NewExternalPort>
|
||||
<p:NewProtocol>TCP</p:NewProtocol>
|
||||
<p:NewInternalPort>2345</p:NewInternalPort>
|
||||
<p:NewInternalClient>192.168.1.137</p:NewInternalClient>
|
||||
<p:NewEnabled>1</p:NewEnabled>
|
||||
<p:NewDescription>dooom</p:NewDescription>
|
||||
<p:NewLeaseTime>345</p:NewLeaseTime>
|
||||
</p:PortMappingEntry>
|
||||
*/
|
||||
typedef enum { PortMappingEltNone,
|
||||
PortMappingEntry, NewRemoteHost,
|
||||
NewExternalPort, NewProtocol,
|
||||
NewInternalPort, NewInternalClient,
|
||||
NewEnabled, NewDescription,
|
||||
NewLeaseTime } portMappingElt;
|
||||
|
||||
struct PortMapping {
|
||||
struct PortMapping * l_next; /* list next element */
|
||||
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 {
|
||||
struct PortMapping * l_head; /* list head */
|
||||
portMappingElt curelt;
|
||||
};
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
ParsePortListing(const char * buffer, int bufsize,
|
||||
struct PortMappingParserData * pdata);
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreePortListing(struct PortMappingParserData * pdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,105 +0,0 @@
|
||||
/* $Id: receivedata.c,v 1.8 2017/04/21 10:16:45 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2011-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else /* _WIN32 */
|
||||
#include <unistd.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#define socklen_t int
|
||||
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/select.h>
|
||||
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#if !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#include <poll.h>
|
||||
#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <errno.h>
|
||||
#define MINIUPNPC_IGNORE_EINTR
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) fprintf(stderr, "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
|
||||
struct sockaddr_storage src_addr;
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
int n;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* using poll */
|
||||
struct pollfd fds[1]; /* for the poll */
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
do {
|
||||
#endif /* MINIUPNPC_IGNORE_EINTR */
|
||||
fds[0].fd = socket;
|
||||
fds[0].events = POLLIN;
|
||||
n = poll(fds, 1, timeout);
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
} while(n < 0 && errno == EINTR);
|
||||
#endif /* MINIUPNPC_IGNORE_EINTR */
|
||||
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 /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#ifdef MINIUPNPC_GET_SRC_ADDR
|
||||
memset(&src_addr, 0, sizeof(src_addr));
|
||||
n = recvfrom(socket, data, length, 0,
|
||||
(struct sockaddr *)&src_addr, &src_addr_len);
|
||||
#else /* MINIUPNPC_GET_SRC_ADDR */
|
||||
n = recv(socket, data, length, 0);
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
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 /* DEBUG */
|
||||
if(scope_id)
|
||||
*scope_id = src_addr6->sin6_scope_id;
|
||||
}
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
return n;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -1,53 +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
|
||||
|
||||
FILE=miniupnpcstrings.h
|
||||
TMPFILE=miniupnpcstrings.h.tmp
|
||||
TEMPLATE_FILE=${FILE}.in
|
||||
|
||||
# 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`
|
||||
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
|
||||
|
@ -1,857 +0,0 @@
|
||||
/* $Id: upnpc.c,v 1.117 2017/05/26 15:26:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2017 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
/* for IPPROTO_TCP / IPPROTO_UDP */
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include "miniwget.h"
|
||||
#include "miniupnpc.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "upnperrors.h"
|
||||
#include "miniupnpcstrings.h"
|
||||
|
||||
/* protofix() checks if protocol is "UDP" or "TCP"
|
||||
* returns NULL if not */
|
||||
const char * protofix(const char * proto)
|
||||
{
|
||||
static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
|
||||
static const char proto_udp[4] = { 'U', 'D', 'P', 0};
|
||||
int i, b;
|
||||
for(i=0, b=1; i<4; i++)
|
||||
b = b && ( (proto[i] == proto_tcp[i])
|
||||
|| (proto[i] == (proto_tcp[i] | 32)) );
|
||||
if(b)
|
||||
return proto_tcp;
|
||||
for(i=0, b=1; i<4; i++)
|
||||
b = b && ( (proto[i] == proto_udp[i])
|
||||
|| (proto[i] == (proto_udp[i] | 32)) );
|
||||
if(b)
|
||||
return proto_udp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* is_int() checks if parameter is an integer or not
|
||||
* 1 for integer
|
||||
* 0 for not an integer */
|
||||
int is_int(char const* s)
|
||||
{
|
||||
if(s == NULL)
|
||||
return 0;
|
||||
while(*s) {
|
||||
/* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
|
||||
if(!isdigit(*s))
|
||||
return 0;
|
||||
s++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void DisplayInfos(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data)
|
||||
{
|
||||
char externalIPAddress[40];
|
||||
char connectionType[64];
|
||||
char status[64];
|
||||
char lastconnerr[64];
|
||||
unsigned int uptime = 0;
|
||||
unsigned int brUp, brDown;
|
||||
time_t timenow, timestarted;
|
||||
int r;
|
||||
if(UPNP_GetConnectionTypeInfo(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
connectionType) != UPNPCOMMAND_SUCCESS)
|
||||
printf("GetConnectionTypeInfo failed.\n");
|
||||
else
|
||||
printf("Connection Type : %s\n", connectionType);
|
||||
if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
|
||||
status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
|
||||
printf("GetStatusInfo failed.\n");
|
||||
else
|
||||
printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
|
||||
status, uptime, lastconnerr);
|
||||
if(uptime > 0) {
|
||||
timenow = time(NULL);
|
||||
timestarted = timenow - uptime;
|
||||
printf(" Time started : %s", ctime(×tarted));
|
||||
}
|
||||
if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
|
||||
&brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
|
||||
printf("GetLinkLayerMaxBitRates failed.\n");
|
||||
} else {
|
||||
printf("MaxBitRateDown : %u bps", brDown);
|
||||
if(brDown >= 1000000) {
|
||||
printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10);
|
||||
} else if(brDown >= 1000) {
|
||||
printf(" (%u Kbps)", brDown / 1000);
|
||||
}
|
||||
printf(" MaxBitRateUp %u bps", brUp);
|
||||
if(brUp >= 1000000) {
|
||||
printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10);
|
||||
} else if(brUp >= 1000) {
|
||||
printf(" (%u Kbps)", brUp / 1000);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
r = UPNP_GetExternalIPAddress(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
externalIPAddress);
|
||||
if(r != UPNPCOMMAND_SUCCESS) {
|
||||
printf("GetExternalIPAddress failed. (errorcode=%d)\n", r);
|
||||
} else {
|
||||
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||
}
|
||||
}
|
||||
|
||||
static void GetConnectionStatus(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data)
|
||||
{
|
||||
unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
|
||||
DisplayInfos(urls, data);
|
||||
bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
|
||||
printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
|
||||
}
|
||||
|
||||
static void ListRedirections(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data)
|
||||
{
|
||||
int r;
|
||||
int i = 0;
|
||||
char index[6];
|
||||
char intClient[40];
|
||||
char intPort[6];
|
||||
char extPort[6];
|
||||
char protocol[4];
|
||||
char desc[80];
|
||||
char enabled[6];
|
||||
char rHost[64];
|
||||
char duration[16];
|
||||
/*unsigned int num=0;
|
||||
UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
|
||||
printf("PortMappingNumberOfEntries : %u\n", num);*/
|
||||
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
|
||||
do {
|
||||
snprintf(index, 6, "%d", i);
|
||||
rHost[0] = '\0'; enabled[0] = '\0';
|
||||
duration[0] = '\0'; desc[0] = '\0';
|
||||
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
|
||||
r = UPNP_GetGenericPortMappingEntry(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
index,
|
||||
extPort, intClient, intPort,
|
||||
protocol, desc, enabled,
|
||||
rHost, duration);
|
||||
if(r==0)
|
||||
/*
|
||||
printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
|
||||
" desc='%s' rHost='%s'\n",
|
||||
i, protocol, extPort, intClient, intPort,
|
||||
enabled, duration,
|
||||
desc, rHost);
|
||||
*/
|
||||
printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n",
|
||||
i, protocol, extPort, intClient, intPort,
|
||||
desc, rHost, duration);
|
||||
else
|
||||
printf("GetGenericPortMappingEntry() returned %d (%s)\n",
|
||||
r, strupnperror(r));
|
||||
i++;
|
||||
} while(r==0);
|
||||
}
|
||||
|
||||
static void NewListRedirections(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data)
|
||||
{
|
||||
int r;
|
||||
int i = 0;
|
||||
struct PortMappingParserData pdata;
|
||||
struct PortMapping * pm;
|
||||
|
||||
memset(&pdata, 0, sizeof(struct PortMappingParserData));
|
||||
r = UPNP_GetListOfPortMappings(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
"0",
|
||||
"65535",
|
||||
"TCP",
|
||||
"1000",
|
||||
&pdata);
|
||||
if(r == UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
|
||||
for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
|
||||
{
|
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
|
||||
i, pm->protocol, pm->externalPort, pm->internalClient,
|
||||
pm->internalPort,
|
||||
pm->description, pm->remoteHost,
|
||||
(unsigned)pm->leaseTime);
|
||||
i++;
|
||||
}
|
||||
FreePortListing(&pdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("GetListOfPortMappings() returned %d (%s)\n",
|
||||
r, strupnperror(r));
|
||||
}
|
||||
r = UPNP_GetListOfPortMappings(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
"0",
|
||||
"65535",
|
||||
"UDP",
|
||||
"1000",
|
||||
&pdata);
|
||||
if(r == UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
|
||||
{
|
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
|
||||
i, pm->protocol, pm->externalPort, pm->internalClient,
|
||||
pm->internalPort,
|
||||
pm->description, pm->remoteHost,
|
||||
(unsigned)pm->leaseTime);
|
||||
i++;
|
||||
}
|
||||
FreePortListing(&pdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("GetListOfPortMappings() returned %d (%s)\n",
|
||||
r, strupnperror(r));
|
||||
}
|
||||
}
|
||||
|
||||
/* Test function
|
||||
* 1 - get connection type
|
||||
* 2 - get extenal ip address
|
||||
* 3 - Add port mapping
|
||||
* 4 - get this port mapping from the IGD */
|
||||
static int SetRedirectAndTest(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * iaddr,
|
||||
const char * iport,
|
||||
const char * eport,
|
||||
const char * proto,
|
||||
const char * leaseDuration,
|
||||
const char * description,
|
||||
int addAny)
|
||||
{
|
||||
char externalIPAddress[40];
|
||||
char intClient[40];
|
||||
char intPort[6];
|
||||
char reservedPort[6];
|
||||
char duration[16];
|
||||
int r;
|
||||
|
||||
if(!iaddr || !iport || !eport || !proto)
|
||||
{
|
||||
fprintf(stderr, "Wrong arguments\n");
|
||||
return -1;
|
||||
}
|
||||
proto = protofix(proto);
|
||||
if(!proto)
|
||||
{
|
||||
fprintf(stderr, "invalid protocol\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = UPNP_GetExternalIPAddress(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
externalIPAddress);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("GetExternalIPAddress failed.\n");
|
||||
else
|
||||
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||
|
||||
if (addAny) {
|
||||
r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype,
|
||||
eport, iport, iaddr, description,
|
||||
proto, 0, leaseDuration, reservedPort);
|
||||
if(r==UPNPCOMMAND_SUCCESS)
|
||||
eport = reservedPort;
|
||||
else
|
||||
printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n",
|
||||
eport, iport, iaddr, r, strupnperror(r));
|
||||
} else {
|
||||
r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
|
||||
eport, iport, iaddr, description,
|
||||
proto, 0, leaseDuration);
|
||||
if(r!=UPNPCOMMAND_SUCCESS) {
|
||||
printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
|
||||
eport, iport, iaddr, r, strupnperror(r));
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
eport, proto, NULL/*remoteHost*/,
|
||||
intClient, intPort, NULL/*desc*/,
|
||||
NULL/*enabled*/, duration);
|
||||
if(r!=UPNPCOMMAND_SUCCESS) {
|
||||
printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
|
||||
r, strupnperror(r));
|
||||
return -2;
|
||||
} else {
|
||||
printf("InternalIP:Port = %s:%s\n", intClient, intPort);
|
||||
printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
|
||||
externalIPAddress, eport, proto, intClient, intPort, duration);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
RemoveRedirect(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * eport,
|
||||
const char * proto,
|
||||
const char * remoteHost)
|
||||
{
|
||||
int r;
|
||||
if(!proto || !eport)
|
||||
{
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return -1;
|
||||
}
|
||||
proto = protofix(proto);
|
||||
if(!proto)
|
||||
{
|
||||
fprintf(stderr, "protocol invalid\n");
|
||||
return -1;
|
||||
}
|
||||
r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
|
||||
if(r!=UPNPCOMMAND_SUCCESS) {
|
||||
printf("UPNP_DeletePortMapping() failed with code : %d\n", r);
|
||||
return -2;
|
||||
}else {
|
||||
printf("UPNP_DeletePortMapping() returned : %d\n", r);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
RemoveRedirectRange(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * ePortStart, char const * ePortEnd,
|
||||
const char * proto, const char * manage)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!manage)
|
||||
manage = "0";
|
||||
|
||||
if(!proto || !ePortStart || !ePortEnd)
|
||||
{
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return -1;
|
||||
}
|
||||
proto = protofix(proto);
|
||||
if(!proto)
|
||||
{
|
||||
fprintf(stderr, "protocol invalid\n");
|
||||
return -1;
|
||||
}
|
||||
r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
|
||||
if(r!=UPNPCOMMAND_SUCCESS) {
|
||||
printf("UPNP_DeletePortMappingRange() failed with code : %d\n", r);
|
||||
return -2;
|
||||
}else {
|
||||
printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
|
||||
static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
|
||||
{
|
||||
unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
|
||||
int firewallEnabled = 0, inboundPinholeAllowed = 0;
|
||||
|
||||
UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
|
||||
printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
|
||||
printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
|
||||
|
||||
bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||
printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
|
||||
printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
|
||||
}
|
||||
|
||||
/* Test function
|
||||
* 1 - Add pinhole
|
||||
* 2 - Check if pinhole is working from the IGD side */
|
||||
static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * remoteaddr, const char * eport,
|
||||
const char * intaddr, const char * iport,
|
||||
const char * proto, const char * lease_time)
|
||||
{
|
||||
char uniqueID[8];
|
||||
/*int isWorking = 0;*/
|
||||
int r;
|
||||
char proto_tmp[8];
|
||||
|
||||
if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
|
||||
{
|
||||
fprintf(stderr, "Wrong arguments\n");
|
||||
return;
|
||||
}
|
||||
if(atoi(proto) == 0)
|
||||
{
|
||||
const char * protocol;
|
||||
protocol = protofix(proto);
|
||||
if(protocol && (strcmp("TCP", protocol) == 0))
|
||||
{
|
||||
snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
|
||||
proto = proto_tmp;
|
||||
}
|
||||
else if(protocol && (strcmp("UDP", protocol) == 0))
|
||||
{
|
||||
snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
|
||||
proto = proto_tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "invalid protocol\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
|
||||
remoteaddr, eport, intaddr, iport, r, strupnperror(r));
|
||||
else
|
||||
{
|
||||
printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
|
||||
remoteaddr, eport, intaddr, iport, uniqueID);
|
||||
/*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
|
||||
printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Test function
|
||||
* 1 - Check if pinhole is working from the IGD side
|
||||
* 2 - Update pinhole */
|
||||
static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * uniqueID, const char * lease_time)
|
||||
{
|
||||
int isWorking = 0;
|
||||
int r;
|
||||
|
||||
if(!uniqueID || !lease_time)
|
||||
{
|
||||
fprintf(stderr, "Wrong arguments\n");
|
||||
return;
|
||||
}
|
||||
r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
|
||||
printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
|
||||
if(isWorking || r==709)
|
||||
{
|
||||
r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
|
||||
printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
|
||||
}
|
||||
}
|
||||
|
||||
/* Test function
|
||||
* Get pinhole timeout
|
||||
*/
|
||||
static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * remoteaddr, const char * eport,
|
||||
const char * intaddr, const char * iport,
|
||||
const char * proto)
|
||||
{
|
||||
int timeout = 0;
|
||||
int r;
|
||||
|
||||
if(!intaddr || !remoteaddr || !iport || !eport || !proto)
|
||||
{
|
||||
fprintf(stderr, "Wrong arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
|
||||
intaddr, iport, remoteaddr, eport, r, strupnperror(r));
|
||||
else
|
||||
printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
|
||||
}
|
||||
|
||||
static void
|
||||
GetPinholePackets(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data, const char * uniqueID)
|
||||
{
|
||||
int r, pinholePackets = 0;
|
||||
if(!uniqueID)
|
||||
{
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return;
|
||||
}
|
||||
r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
|
||||
else
|
||||
printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
|
||||
}
|
||||
|
||||
static void
|
||||
CheckPinhole(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data, const char * uniqueID)
|
||||
{
|
||||
int r, isWorking = 0;
|
||||
if(!uniqueID)
|
||||
{
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return;
|
||||
}
|
||||
r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
|
||||
else
|
||||
printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
|
||||
}
|
||||
|
||||
static void
|
||||
RemovePinhole(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data, const char * uniqueID)
|
||||
{
|
||||
int r;
|
||||
if(!uniqueID)
|
||||
{
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return;
|
||||
}
|
||||
r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
|
||||
printf("UPNP_DeletePinhole() returned : %d\n", r);
|
||||
}
|
||||
|
||||
|
||||
/* sample upnp client program */
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
char command = 0;
|
||||
char ** commandargv = 0;
|
||||
int commandargc = 0;
|
||||
struct UPNPDev * devlist = 0;
|
||||
char lanaddr[64] = "unset"; /* my ip address on the LAN */
|
||||
int i;
|
||||
const char * rootdescurl = 0;
|
||||
const char * multicastif = 0;
|
||||
const char * minissdpdpath = 0;
|
||||
int localport = UPNP_LOCAL_PORT_ANY;
|
||||
int retcode = 0;
|
||||
int error = 0;
|
||||
int ipv6 = 0;
|
||||
unsigned char ttl = 2; /* defaulting to 2 */
|
||||
const char * description = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if(nResult != NO_ERROR)
|
||||
{
|
||||
fprintf(stderr, "WSAStartup() failed.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
|
||||
printf(" (c) 2005-2017 Thomas Bernard.\n");
|
||||
printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n"
|
||||
"for more information.\n");
|
||||
/* command line processing */
|
||||
for(i=1; i<argc; i++)
|
||||
{
|
||||
if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
|
||||
{
|
||||
command = 0;
|
||||
break;
|
||||
}
|
||||
if(argv[i][0] == '-')
|
||||
{
|
||||
if(argv[i][1] == 'u')
|
||||
rootdescurl = argv[++i];
|
||||
else if(argv[i][1] == 'm')
|
||||
multicastif = argv[++i];
|
||||
else if(argv[i][1] == 'z')
|
||||
{
|
||||
char junk;
|
||||
if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
|
||||
localport<0 || localport>65535 ||
|
||||
(localport >1 && localport < 1024))
|
||||
{
|
||||
fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
|
||||
localport = UPNP_LOCAL_PORT_ANY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(argv[i][1] == 'p')
|
||||
minissdpdpath = argv[++i];
|
||||
else if(argv[i][1] == '6')
|
||||
ipv6 = 1;
|
||||
else if(argv[i][1] == 'e')
|
||||
description = argv[++i];
|
||||
else if(argv[i][1] == 't')
|
||||
ttl = (unsigned char)atoi(argv[++i]);
|
||||
else
|
||||
{
|
||||
command = argv[i][1];
|
||||
i++;
|
||||
commandargv = argv + i;
|
||||
commandargc = argc - i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "option '%s' invalid\n", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!command
|
||||
|| (command == 'a' && commandargc<4)
|
||||
|| (command == 'd' && argc<2)
|
||||
|| (command == 'r' && argc<2)
|
||||
|| (command == 'A' && commandargc<6)
|
||||
|| (command == 'U' && commandargc<2)
|
||||
|| (command == 'D' && commandargc<1))
|
||||
{
|
||||
fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -d external_port protocol <remote host>\n\t\tDelete port redirection\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
|
||||
fprintf(stderr, "\nprotocol is UDP or TCP\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -e description : set description for port mapping.\n");
|
||||
fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
|
||||
fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
|
||||
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
|
||||
fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
|
||||
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
|
||||
fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( rootdescurl
|
||||
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
|
||||
localport, ipv6, ttl, &error)))
|
||||
{
|
||||
struct UPNPDev * device;
|
||||
struct UPNPUrls urls;
|
||||
struct IGDdatas data;
|
||||
if(devlist)
|
||||
{
|
||||
printf("List of UPNP devices found on the network :\n");
|
||||
for(device = devlist; device; device = device->pNext)
|
||||
{
|
||||
printf(" desc: %s\n st: %s\n\n",
|
||||
device->descURL, device->st);
|
||||
}
|
||||
}
|
||||
else if(!rootdescurl)
|
||||
{
|
||||
printf("upnpDiscover() error code=%d\n", error);
|
||||
}
|
||||
i = 1;
|
||||
if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
|
||||
|| (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
|
||||
{
|
||||
switch(i) {
|
||||
case 1:
|
||||
printf("Found valid IGD : %s\n", urls.controlURL);
|
||||
break;
|
||||
case 2:
|
||||
printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
|
||||
printf("Trying to continue anyway\n");
|
||||
break;
|
||||
case 3:
|
||||
printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
|
||||
printf("Trying to continue anyway\n");
|
||||
break;
|
||||
default:
|
||||
printf("Found device (igd ?) : %s\n", urls.controlURL);
|
||||
printf("Trying to continue anyway\n");
|
||||
}
|
||||
printf("Local LAN ip address : %s\n", lanaddr);
|
||||
#if 0
|
||||
printf("getting \"%s\"\n", urls.ipcondescURL);
|
||||
descXML = miniwget(urls.ipcondescURL, &descXMLsize);
|
||||
if(descXML)
|
||||
{
|
||||
/*fwrite(descXML, 1, descXMLsize, stdout);*/
|
||||
free(descXML); descXML = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case 'l':
|
||||
DisplayInfos(&urls, &data);
|
||||
ListRedirections(&urls, &data);
|
||||
break;
|
||||
case 'L':
|
||||
NewListRedirections(&urls, &data);
|
||||
break;
|
||||
case 'a':
|
||||
if (SetRedirectAndTest(&urls, &data,
|
||||
commandargv[0], commandargv[1],
|
||||
commandargv[2], commandargv[3],
|
||||
(commandargc > 4)?commandargv[4]:"0",
|
||||
description, 0) < 0)
|
||||
retcode = 2;
|
||||
break;
|
||||
case 'd':
|
||||
if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
|
||||
commandargc > 2 ? commandargv[2] : NULL) < 0)
|
||||
retcode = 2;
|
||||
break;
|
||||
case 'n': /* aNy */
|
||||
if (SetRedirectAndTest(&urls, &data,
|
||||
commandargv[0], commandargv[1],
|
||||
commandargv[2], commandargv[3],
|
||||
(commandargc > 4)?commandargv[4]:"0",
|
||||
description, 1) < 0)
|
||||
retcode = 2;
|
||||
break;
|
||||
case 'N':
|
||||
if (commandargc < 3)
|
||||
fprintf(stderr, "too few arguments\n");
|
||||
|
||||
if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
|
||||
commandargc > 3 ? commandargv[3] : NULL) < 0)
|
||||
retcode = 2;
|
||||
break;
|
||||
case 's':
|
||||
GetConnectionStatus(&urls, &data);
|
||||
break;
|
||||
case 'r':
|
||||
i = 0;
|
||||
while(i<commandargc)
|
||||
{
|
||||
if(!is_int(commandargv[i])) {
|
||||
/* 1st parameter not an integer : error */
|
||||
fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
|
||||
retcode = 1;
|
||||
break;
|
||||
} else if(is_int(commandargv[i+1])){
|
||||
/* 2nd parameter is an integer : <port> <external_port> <protocol> */
|
||||
if (SetRedirectAndTest(&urls, &data,
|
||||
lanaddr, commandargv[i],
|
||||
commandargv[i+1], commandargv[i+2], "0",
|
||||
description, 0) < 0)
|
||||
retcode = 2;
|
||||
i+=3; /* 3 parameters parsed */
|
||||
} else {
|
||||
/* 2nd parameter not an integer : <port> <protocol> */
|
||||
if (SetRedirectAndTest(&urls, &data,
|
||||
lanaddr, commandargv[i],
|
||||
commandargv[i], commandargv[i+1], "0",
|
||||
description, 0) < 0)
|
||||
retcode = 2;
|
||||
i+=2; /* 2 parameters parsed */
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
SetPinholeAndTest(&urls, &data,
|
||||
commandargv[0], commandargv[1],
|
||||
commandargv[2], commandargv[3],
|
||||
commandargv[4], commandargv[5]);
|
||||
break;
|
||||
case 'U':
|
||||
GetPinholeAndUpdate(&urls, &data,
|
||||
commandargv[0], commandargv[1]);
|
||||
break;
|
||||
case 'C':
|
||||
for(i=0; i<commandargc; i++)
|
||||
{
|
||||
CheckPinhole(&urls, &data, commandargv[i]);
|
||||
}
|
||||
break;
|
||||
case 'K':
|
||||
for(i=0; i<commandargc; i++)
|
||||
{
|
||||
GetPinholePackets(&urls, &data, commandargv[i]);
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
for(i=0; i<commandargc; i++)
|
||||
{
|
||||
RemovePinhole(&urls, &data, commandargv[i]);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
GetFirewallStatus(&urls, &data);
|
||||
break;
|
||||
case 'G':
|
||||
GetPinholeOutboundTimeout(&urls, &data,
|
||||
commandargv[0], commandargv[1],
|
||||
commandargv[2], commandargv[3],
|
||||
commandargv[4]);
|
||||
break;
|
||||
case 'P':
|
||||
printf("Presentation URL found:\n");
|
||||
printf(" %s\n", data.presentationurl);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown switch -%c\n", command);
|
||||
retcode = 1;
|
||||
}
|
||||
|
||||
FreeUPNPUrls(&urls);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
|
||||
retcode = 1;
|
||||
}
|
||||
freeUPNPDevlist(devlist); devlist = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "No IGD UPnP Device found on the network !\n");
|
||||
retcode = 1;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
nResult = WSACleanup();
|
||||
if(nResult != NO_ERROR) {
|
||||
fprintf(stderr, "WSACleanup() failed.\n");
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
return retcode;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,348 +0,0 @@
|
||||
/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */
|
||||
/* Miniupnp project : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2015 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 "miniupnpc_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)
|
||||
#define UPNPCOMMAND_INVALID_RESPONSE (-4)
|
||||
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
MINIUPNP_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 */
|
||||
MINIUPNP_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 */
|
||||
MINIUPNP_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. */
|
||||
MINIUPNP_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. */
|
||||
MINIUPNP_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
|
||||
*/
|
||||
MINIUPNP_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_AddAnyPortMapping()
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddAnyPortMapping(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,
|
||||
char * reservedPort);
|
||||
|
||||
/* 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 */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort, const char * proto,
|
||||
const char * remoteHost);
|
||||
|
||||
/* UPNP_DeletePortRangeMapping()
|
||||
* 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 :
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||
* and the sender was not authorized.
|
||||
* 730 PortMappingNotFound - This error message is returned if no port
|
||||
* mapping is found in the specified range.
|
||||
* 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
|
||||
const char * extPortStart, const char * extPortEnd,
|
||||
const char * proto,
|
||||
const char * manage);
|
||||
|
||||
/* UPNP_GetPortMappingNumberOfEntries()
|
||||
* not supported by all routers */
|
||||
MINIUPNP_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.
|
||||
*/
|
||||
MINIUPNP_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
|
||||
*/
|
||||
MINIUPNP_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.
|
||||
*/
|
||||
MINIUPNP_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 */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetFirewallStatus(const char * controlURL,
|
||||
const char * servicetype,
|
||||
int * firewallEnabled,
|
||||
int * inboundPinholeAllowed);
|
||||
|
||||
MINIUPNP_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);
|
||||
|
||||
MINIUPNP_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);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID,
|
||||
const char * leaseTime);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * isWorking);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * packets);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#include <stdlib.h>
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* freeUPNPDevlist() should be used to
|
||||
* free the chained list returned by upnpDiscover() */
|
||||
void freeUPNPDevlist(struct UPNPDev * devlist)
|
||||
{
|
||||
struct UPNPDev * next;
|
||||
while(devlist)
|
||||
{
|
||||
next = devlist->pNext;
|
||||
free(devlist);
|
||||
devlist = next;
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#ifndef UPNPDEV_H_INCLUDED
|
||||
#define UPNPDEV_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct UPNPDev {
|
||||
struct UPNPDev * pNext;
|
||||
char * descURL;
|
||||
char * st;
|
||||
unsigned int scope_id;
|
||||
char * usn;
|
||||
char buffer[3];
|
||||
};
|
||||
|
||||
/* freeUPNPDevlist()
|
||||
* free list returned by upnpDiscover() */
|
||||
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPNPDEV_H_INCLUDED */
|
@ -1,107 +0,0 @@
|
||||
/* $Id: upnperrors.c,v 1.8 2014/06/10 09:41:48 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2007 Thomas Bernard
|
||||
* All Right reserved.
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#include <string.h>
|
||||
#include "upnperrors.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "miniupnpc.h"
|
||||
|
||||
const char * strupnperror(int err)
|
||||
{
|
||||
const char * s = NULL;
|
||||
switch(err) {
|
||||
case UPNPCOMMAND_SUCCESS:
|
||||
s = "Success";
|
||||
break;
|
||||
case UPNPCOMMAND_UNKNOWN_ERROR:
|
||||
s = "Miniupnpc Unknown Error";
|
||||
break;
|
||||
case UPNPCOMMAND_INVALID_ARGS:
|
||||
s = "Miniupnpc Invalid Arguments";
|
||||
break;
|
||||
case UPNPCOMMAND_INVALID_RESPONSE:
|
||||
s = "Miniupnpc Invalid response";
|
||||
break;
|
||||
case UPNPDISCOVER_SOCKET_ERROR:
|
||||
s = "Miniupnpc Socket error";
|
||||
break;
|
||||
case UPNPDISCOVER_MEMORY_ERROR:
|
||||
s = "Miniupnpc Memory allocation error";
|
||||
break;
|
||||
case 401:
|
||||
s = "Invalid Action";
|
||||
break;
|
||||
case 402:
|
||||
s = "Invalid Args";
|
||||
break;
|
||||
case 501:
|
||||
s = "Action Failed";
|
||||
break;
|
||||
case 606:
|
||||
s = "Action not authorized";
|
||||
break;
|
||||
case 701:
|
||||
s = "PinholeSpaceExhausted";
|
||||
break;
|
||||
case 702:
|
||||
s = "FirewallDisabled";
|
||||
break;
|
||||
case 703:
|
||||
s = "InboundPinholeNotAllowed";
|
||||
break;
|
||||
case 704:
|
||||
s = "NoSuchEntry";
|
||||
break;
|
||||
case 705:
|
||||
s = "ProtocolNotSupported";
|
||||
break;
|
||||
case 706:
|
||||
s = "InternalPortWildcardingNotAllowed";
|
||||
break;
|
||||
case 707:
|
||||
s = "ProtocolWildcardingNotAllowed";
|
||||
break;
|
||||
case 708:
|
||||
s = "WildcardNotPermittedInSrcIP";
|
||||
break;
|
||||
case 709:
|
||||
s = "NoPacketSent";
|
||||
break;
|
||||
case 713:
|
||||
s = "SpecifiedArrayIndexInvalid";
|
||||
break;
|
||||
case 714:
|
||||
s = "NoSuchEntryInArray";
|
||||
break;
|
||||
case 715:
|
||||
s = "WildCardNotPermittedInSrcIP";
|
||||
break;
|
||||
case 716:
|
||||
s = "WildCardNotPermittedInExtPort";
|
||||
break;
|
||||
case 718:
|
||||
s = "ConflictInMappingEntry";
|
||||
break;
|
||||
case 724:
|
||||
s = "SamePortValuesRequired";
|
||||
break;
|
||||
case 725:
|
||||
s = "OnlyPermanentLeasesSupported";
|
||||
break;
|
||||
case 726:
|
||||
s = "RemoteHostOnlySupportsWildcard";
|
||||
break;
|
||||
case 727:
|
||||
s = "ExternalPortOnlySupportsWildcard";
|
||||
break;
|
||||
default:
|
||||
s = "UnknownError";
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */
|
||||
/* (c) 2007-2015 Thomas Bernard
|
||||
* All rights reserved.
|
||||
* MiniUPnP Project.
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#ifndef UPNPERRORS_H_INCLUDED
|
||||
#define UPNPERRORS_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* strupnperror()
|
||||
* Return a string description of the UPnP error code
|
||||
* or NULL for undefinded errors */
|
||||
MINIUPNP_LIBSPEC const char * strupnperror(int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,196 +0,0 @@
|
||||
/* $Id: upnpreplyparse.c,v 1.20 2017/12/12 11:26:25 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2017 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 namelen)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
struct NameValue * nv;
|
||||
(void)name;
|
||||
(void)namelen;
|
||||
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(nv == NULL)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"NameValueParserEndElt");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
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';
|
||||
}
|
||||
nv->l_next = data->l_head; /* insert in list */
|
||||
data->l_head = nv;
|
||||
}
|
||||
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 */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"NameValueParserGetData");
|
||||
#endif /* DEBUG */
|
||||
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;
|
||||
memset(data, 0, sizeof(struct NameValueParserData));
|
||||
/* 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->l_head) != NULL)
|
||||
{
|
||||
pdata->l_head = nv->l_next;
|
||||
free(nv);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
for(nv = pdata->l_head;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->l_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.l_head;
|
||||
nv != NULL;
|
||||
nv = nv->l_next)
|
||||
{
|
||||
printf("%s = %s\n", nv->name, nv->value);
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
@ -1,63 +0,0 @@
|
||||
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 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
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct NameValue {
|
||||
struct NameValue * l_next;
|
||||
char name[64];
|
||||
char value[128];
|
||||
};
|
||||
|
||||
struct NameValueParserData {
|
||||
struct NameValue * l_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
|
||||
|
@ -1,83 +0,0 @@
|
||||
/* $Id: wingenminiupnpcstrings.c,v 1.4 2015/02/08 08:46:06 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENSE file provided within this distribution */
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
/* This program display the Windows version and is used to
|
||||
* generate the miniupnpcstrings.h
|
||||
* wingenminiupnpcstrings miniupnpcstrings.h.in miniupnpcstrings.h
|
||||
*/
|
||||
int main(int argc, char * * argv) {
|
||||
char buffer[256];
|
||||
OSVERSIONINFO osvi;
|
||||
FILE * fin;
|
||||
FILE * fout;
|
||||
int n;
|
||||
char miniupnpcVersion[32];
|
||||
/* dwMajorVersion :
|
||||
The major version number of the operating system. For more information, see Remarks.
|
||||
dwMinorVersion :
|
||||
The minor version number of the operating system. For more information, see Remarks.
|
||||
dwBuildNumber :
|
||||
The build number of the operating system.
|
||||
dwPlatformId
|
||||
The operating system platform. This member can be the following value.
|
||||
szCSDVersion
|
||||
A null-terminated string, such as "Service Pack 3", that indicates the
|
||||
latest Service Pack installed on the system. If no Service Pack has
|
||||
been installed, the string is empty.
|
||||
*/
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
printf("Windows %lu.%lu Build %lu %s\n",
|
||||
osvi.dwMajorVersion, osvi.dwMinorVersion,
|
||||
osvi.dwBuildNumber, (const char *)&(osvi.szCSDVersion));
|
||||
|
||||
fin = fopen("VERSION", "r");
|
||||
fgets(miniupnpcVersion, sizeof(miniupnpcVersion), fin);
|
||||
fclose(fin);
|
||||
for(n = 0; n < sizeof(miniupnpcVersion); n++) {
|
||||
if(miniupnpcVersion[n] < ' ')
|
||||
miniupnpcVersion[n] = '\0';
|
||||
}
|
||||
printf("MiniUPnPc version %s\n", miniupnpcVersion);
|
||||
|
||||
if(argc >= 3) {
|
||||
fin = fopen(argv[1], "r");
|
||||
if(!fin) {
|
||||
fprintf(stderr, "Cannot open %s for reading.\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
fout = fopen(argv[2], "w");
|
||||
if(!fout) {
|
||||
fprintf(stderr, "Cannot open %s for writing.\n", argv[2]);
|
||||
fclose(fin);
|
||||
return 1;
|
||||
}
|
||||
n = 0;
|
||||
while(fgets(buffer, sizeof(buffer), fin)) {
|
||||
if(0 == memcmp(buffer, "#define OS_STRING \"OS/version\"", 30)) {
|
||||
sprintf(buffer, "#define OS_STRING \"MSWindows/%ld.%ld.%ld\"\n",
|
||||
osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
|
||||
} else if(0 == memcmp(buffer, "#define MINIUPNPC_VERSION_STRING \"version\"", 42)) {
|
||||
sprintf(buffer, "#define MINIUPNPC_VERSION_STRING \"%s\"\n",
|
||||
miniupnpcVersion);
|
||||
}
|
||||
/*fputs(buffer, stdout);*/
|
||||
fputs(buffer, fout);
|
||||
n++;
|
||||
}
|
||||
fclose(fin);
|
||||
fclose(fout);
|
||||
printf("%d lines written to %s.\n", n, argv[2]);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -67,7 +67,10 @@ const (
|
||||
// PlatformDefaultHomePath is the default location of ZeroTier's working path on this system
|
||||
PlatformDefaultHomePath string = C.GoString(C.ZT_PLATFORM_DEFAULT_HOMEPATH)
|
||||
|
||||
AFInet = C.AF_INET
|
||||
// AFInet is the address family for IPv4
|
||||
AFInet = C.AF_INET
|
||||
|
||||
// AFInet6 is the address family for IPv6
|
||||
AFInet6 = C.AF_INET6
|
||||
|
||||
defaultVirtualNetworkMTU = C.ZT_DEFAULT_MTU
|
||||
|
Loading…
x
Reference in New Issue
Block a user