mupnp 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,179 @@
1
+ /* $Id: upnpcommands.h,v 1.13 2008/02/18 13:27:24 nanard Exp $ */
2
+ /* Miniupnp project : http://miniupnp.free.fr/
3
+ * Author : Thomas Bernard
4
+ * Copyright (c) 2005-2006 Thomas Bernard
5
+ * This software is subject to the conditions detailed in the
6
+ * LICENCE file provided within this distribution */
7
+ #ifndef __UPNPCOMMANDS_H__
8
+ #define __UPNPCOMMANDS_H__
9
+
10
+ #include "upnpreplyparse.h"
11
+ #include "declspec.h"
12
+
13
+ /* MiniUPnPc return codes : */
14
+ #define UPNPCOMMAND_SUCCESS (0)
15
+ #define UPNPCOMMAND_UNKNOWN_ERROR (-1)
16
+ #define UPNPCOMMAND_INVALID_ARGS (-2)
17
+
18
+ #ifdef __cplusplus
19
+ extern "C" {
20
+ #endif
21
+
22
+ LIBSPEC unsigned int
23
+ UPNP_GetTotalBytesSent(const char * controlURL,
24
+ const char * servicetype);
25
+
26
+ LIBSPEC unsigned int
27
+ UPNP_GetTotalBytesReceived(const char * controlURL,
28
+ const char * servicetype);
29
+
30
+ LIBSPEC unsigned int
31
+ UPNP_GetTotalPacketsSent(const char * controlURL,
32
+ const char * servicetype);
33
+
34
+ LIBSPEC unsigned int
35
+ UPNP_GetTotalPacketsReceived(const char * controlURL,
36
+ const char * servicetype);
37
+
38
+ /* UPNP_GetStatusInfo()
39
+ * status and lastconnerror are 64 byte buffers
40
+ * Return values :
41
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
42
+ * or a UPnP Error code */
43
+ LIBSPEC int
44
+ UPNP_GetStatusInfo(const char * controlURL,
45
+ const char * servicetype,
46
+ char * status,
47
+ unsigned int * uptime,
48
+ char * lastconnerror);
49
+
50
+ /* UPNP_GetConnectionTypeInfo()
51
+ * argument connectionType is a 64 character buffer
52
+ * Return Values :
53
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
54
+ * or a UPnP Error code */
55
+ LIBSPEC int
56
+ UPNP_GetConnectionTypeInfo(const char * controlURL,
57
+ const char * servicetype,
58
+ char * connectionType);
59
+
60
+ /* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
61
+ * if the third arg is not null the value is copied to it.
62
+ * at least 16 bytes must be available
63
+ *
64
+ * Return values :
65
+ * 0 : SUCCESS
66
+ * NON ZERO : ERROR Either an UPnP error code or an unknown error.
67
+ *
68
+ * possible UPnP Errors :
69
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
70
+ * 501 Action Failed - See UPnP Device Architecture section on Control. */
71
+ LIBSPEC int
72
+ UPNP_GetExternalIPAddress(const char * controlURL,
73
+ const char * servicetype,
74
+ char * extIpAdd);
75
+
76
+ /* UPNP_GetLinkLayerMaxBitRates()
77
+ * call WANCommonInterfaceConfig:1#GetCommonLinkProperties
78
+ *
79
+ * return values :
80
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
81
+ * or a UPnP Error Code. */
82
+ LIBSPEC int
83
+ UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
84
+ const char* servicetype,
85
+ unsigned int * bitrateDown,
86
+ unsigned int * bitrateUp);
87
+
88
+ /* UPNP_AddPortMapping()
89
+ *
90
+ * Return values :
91
+ * 0 : SUCCESS
92
+ * NON ZERO : ERROR. Either an UPnP error code or an unknown error.
93
+ *
94
+ * List of possible UPnP errors for AddPortMapping :
95
+ * errorCode errorDescription (short) - Description (long)
96
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
97
+ * 501 Action Failed - See UPnP Device Architecture section on Control.
98
+ * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
99
+ * wild-carded
100
+ * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
101
+ * 718 ConflictInMappingEntry - The port mapping entry specified conflicts
102
+ * with a mapping assigned previously to another client
103
+ * 724 SamePortValuesRequired - Internal and External port values
104
+ * must be the same
105
+ * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports
106
+ * permanent lease times on port mappings
107
+ * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard
108
+ * and cannot be a specific IP address or DNS name
109
+ * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and
110
+ * cannot be a specific port value */
111
+ LIBSPEC int
112
+ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
113
+ const char * extPort,
114
+ const char * inPort,
115
+ const char * inClient,
116
+ const char * desc,
117
+ const char * proto);
118
+
119
+ /* UPNP_DeletePortMapping()
120
+ * Return Values :
121
+ * 0 : SUCCESS
122
+ * NON ZERO : error. Either an UPnP error code or an undefined error.
123
+ *
124
+ * List of possible UPnP errors for DeletePortMapping :
125
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
126
+ * 714 NoSuchEntryInArray - The specified value does not exist in the array */
127
+ LIBSPEC int
128
+ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
129
+ const char * extPort, const char * proto);
130
+
131
+ /* UPNP_GetPortMappingNumberOfEntries()
132
+ * not supported by all routers */
133
+ LIBSPEC int
134
+ UPNP_GetPortMappingNumberOfEntries(const char* controlURL, const char* servicetype, unsigned int * num);
135
+
136
+ /* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
137
+ * the result is returned in the intClient and intPort strings
138
+ * please provide 16 and 6 bytes of data
139
+ *
140
+ * return value :
141
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
142
+ * or a UPnP Error Code. */
143
+ LIBSPEC int
144
+ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
145
+ const char * servicetype,
146
+ const char * extPort,
147
+ const char * proto,
148
+ char * intClient,
149
+ char * intPort);
150
+
151
+ /* UPNP_GetGenericPortMappingEntry()
152
+ *
153
+ * return value :
154
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
155
+ * or a UPnP Error Code.
156
+ *
157
+ * Possible UPNP Error codes :
158
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
159
+ * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
160
+ */
161
+ LIBSPEC int
162
+ UPNP_GetGenericPortMappingEntry(const char * controlURL,
163
+ const char * servicetype,
164
+ const char * index,
165
+ char * extPort,
166
+ char * intClient,
167
+ char * intPort,
168
+ char * protocol,
169
+ char * desc,
170
+ char * enabled,
171
+ char * rHost,
172
+ char * duration);
173
+
174
+ #ifdef __cplusplus
175
+ }
176
+ #endif
177
+
178
+ #endif
179
+
data/ext/upnperrors.c ADDED
@@ -0,0 +1,55 @@
1
+ /* $Id: upnperrors.c,v 1.2 2008/02/05 12:50:22 nanard Exp $ */
2
+ /* Project : miniupnp
3
+ * Author : Thomas BERNARD
4
+ * copyright (c) 2007 Thomas Bernard
5
+ * All Right reserved.
6
+ * This software is subjet to the conditions detailed in the
7
+ * provided LICENCE file. */
8
+ #include <string.h>
9
+ #include "upnperrors.h"
10
+
11
+ const char * strupnperror(int err)
12
+ {
13
+ const char * s = NULL;
14
+ switch(err) {
15
+ case 401:
16
+ s = "Invalid Action";
17
+ break;
18
+ case 402:
19
+ s = "Invalid Args";
20
+ break;
21
+ case 501:
22
+ s = "Action Failed";
23
+ break;
24
+ case 713:
25
+ s = "SpecifiedArrayIndexInvalid";
26
+ break;
27
+ case 714:
28
+ s = "NoSuchEntryInArray";
29
+ break;
30
+ case 715:
31
+ s = "WildCardNotPermittedInSrcIP";
32
+ break;
33
+ case 716:
34
+ s = "WildCardNotPermittedInExtPort";
35
+ break;
36
+ case 718:
37
+ s = "ConflictInMappingEntry";
38
+ break;
39
+ case 724:
40
+ s = "SamePortValuesRequired";
41
+ break;
42
+ case 725:
43
+ s = "OnlyPermanentLeasesSupported";
44
+ break;
45
+ case 726:
46
+ s = "RemoteHostOnlySupportsWildcard";
47
+ break;
48
+ case 727:
49
+ s = "ExternalPortOnlySupportsWildcard";
50
+ break;
51
+ default:
52
+ s = NULL;
53
+ }
54
+ return s;
55
+ }
data/ext/upnperrors.h ADDED
@@ -0,0 +1,16 @@
1
+ /* $Id: upnperrors.h,v 1.1 2007/12/22 11:28:04 nanard Exp $ */
2
+ /* (c) 2007 Thomas Bernard
3
+ * All rights reserved.
4
+ * MiniUPnP Project.
5
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
6
+ * This software is subjet to the conditions detailed in the
7
+ * provided LICENCE file. */
8
+ #ifndef __UPNPERRORS_H__
9
+ #define __UPNPERRORS_H__
10
+
11
+ /* strupnperror()
12
+ * Return a string description of the UPnP error code
13
+ * or NULL for undefinded errors */
14
+ const char * strupnperror(int err);
15
+
16
+ #endif
@@ -0,0 +1,127 @@
1
+ /* $Id: upnpreplyparse.c,v 1.10 2008/02/21 13:05:27 nanard Exp $ */
2
+ /* MiniUPnP project
3
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4
+ * (c) 2006 Thomas Bernard
5
+ * This software is subject to the conditions detailed
6
+ * in the LICENCE file provided within the distribution */
7
+
8
+ #include <stdlib.h>
9
+ #include <string.h>
10
+ #include <stdio.h>
11
+
12
+ #include "upnpreplyparse.h"
13
+ #include "minixml.h"
14
+
15
+ static void
16
+ NameValueParserStartElt(void * d, const char * name, int l)
17
+ {
18
+ struct NameValueParserData * data = (struct NameValueParserData *)d;
19
+ if(l>63)
20
+ l = 63;
21
+ memcpy(data->curelt, name, l);
22
+ data->curelt[l] = '\0';
23
+ }
24
+
25
+ static void
26
+ NameValueParserGetData(void * d, const char * datas, int l)
27
+ {
28
+ struct NameValueParserData * data = (struct NameValueParserData *)d;
29
+ struct NameValue * nv;
30
+ nv = malloc(sizeof(struct NameValue));
31
+ if(l>63)
32
+ l = 63;
33
+ strncpy(nv->name, data->curelt, 64);
34
+ nv->name[63] = '\0';
35
+ memcpy(nv->value, datas, l);
36
+ nv->value[l] = '\0';
37
+ LIST_INSERT_HEAD( &(data->head), nv, entries);
38
+ }
39
+
40
+ void
41
+ ParseNameValue(const char * buffer, int bufsize,
42
+ struct NameValueParserData * data)
43
+ {
44
+ struct xmlparser parser;
45
+ LIST_INIT(&(data->head));
46
+ /* init xmlparser object */
47
+ parser.xmlstart = buffer;
48
+ parser.xmlsize = bufsize;
49
+ parser.data = data;
50
+ parser.starteltfunc = NameValueParserStartElt;
51
+ parser.endeltfunc = 0;
52
+ parser.datafunc = NameValueParserGetData;
53
+ parser.attfunc = 0;
54
+ parsexml(&parser);
55
+ }
56
+
57
+ void
58
+ ClearNameValueList(struct NameValueParserData * pdata)
59
+ {
60
+ struct NameValue * nv;
61
+ while((nv = pdata->head.lh_first) != NULL)
62
+ {
63
+ LIST_REMOVE(nv, entries);
64
+ free(nv);
65
+ }
66
+ }
67
+
68
+ char *
69
+ GetValueFromNameValueList(struct NameValueParserData * pdata,
70
+ const char * Name)
71
+ {
72
+ struct NameValue * nv;
73
+ char * p = NULL;
74
+ for(nv = pdata->head.lh_first;
75
+ (nv != NULL) && (p == NULL);
76
+ nv = nv->entries.le_next)
77
+ {
78
+ if(strcmp(nv->name, Name) == 0)
79
+ p = nv->value;
80
+ }
81
+ return p;
82
+ }
83
+
84
+ #if 0
85
+ /* useless now that minixml ignores namespaces by itself */
86
+ char *
87
+ GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
88
+ const char * Name)
89
+ {
90
+ struct NameValue * nv;
91
+ char * p = NULL;
92
+ char * pname;
93
+ for(nv = pdata->head.lh_first;
94
+ (nv != NULL) && (p == NULL);
95
+ nv = nv->entries.le_next)
96
+ {
97
+ pname = strrchr(nv->name, ':');
98
+ if(pname)
99
+ pname++;
100
+ else
101
+ pname = nv->name;
102
+ if(strcmp(pname, Name)==0)
103
+ p = nv->value;
104
+ }
105
+ return p;
106
+ }
107
+ #endif
108
+
109
+ /* debug all-in-one function
110
+ * do parsing then display to stdout */
111
+ #ifdef DEBUG
112
+ void
113
+ DisplayNameValueList(char * buffer, int bufsize)
114
+ {
115
+ struct NameValueParserData pdata;
116
+ struct NameValue * nv;
117
+ ParseNameValue(buffer, bufsize, &pdata);
118
+ for(nv = pdata.head.lh_first;
119
+ nv != NULL;
120
+ nv = nv->entries.le_next)
121
+ {
122
+ printf("%s = %s\n", nv->name, nv->value);
123
+ }
124
+ ClearNameValueList(&pdata);
125
+ }
126
+ #endif
127
+
@@ -0,0 +1,62 @@
1
+ /* $Id: upnpreplyparse.h,v 1.8 2008/02/21 13:05:27 nanard Exp $ */
2
+ /* MiniUPnP project
3
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4
+ * (c) 2006 Thomas Bernard
5
+ * This software is subject to the conditions detailed
6
+ * in the LICENCE file provided within the distribution */
7
+
8
+ #ifndef __UPNPREPLYPARSE_H__
9
+ #define __UPNPREPLYPARSE_H__
10
+
11
+ #if defined(NO_SYS_QUEUE_H) || defined(WIN32)
12
+ #include "bsdqueue.h"
13
+ #else
14
+ #include <sys/queue.h>
15
+ #endif
16
+
17
+ #ifdef __cplusplus
18
+ extern "C" {
19
+ #endif
20
+
21
+ struct NameValue {
22
+ LIST_ENTRY(NameValue) entries;
23
+ char name[64];
24
+ char value[64];
25
+ };
26
+
27
+ struct NameValueParserData {
28
+ LIST_HEAD(listhead, NameValue) head;
29
+ char curelt[64];
30
+ };
31
+
32
+ /* ParseNameValue() */
33
+ void
34
+ ParseNameValue(const char * buffer, int bufsize,
35
+ struct NameValueParserData * data);
36
+
37
+ /* ClearNameValueList() */
38
+ void
39
+ ClearNameValueList(struct NameValueParserData * pdata);
40
+
41
+ /* GetValueFromNameValueList() */
42
+ char *
43
+ GetValueFromNameValueList(struct NameValueParserData * pdata,
44
+ const char * Name);
45
+
46
+ /* GetValueFromNameValueListIgnoreNS() */
47
+ char *
48
+ GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
49
+ const char * Name);
50
+
51
+ /* DisplayNameValueList() */
52
+ #ifdef DEBUG
53
+ void
54
+ DisplayNameValueList(char * buffer, int bufsize);
55
+ #endif
56
+
57
+ #ifdef __cplusplus
58
+ }
59
+ #endif
60
+
61
+ #endif
62
+
data/lib/UPnP.rb ADDED
@@ -0,0 +1,400 @@
1
+ #! /usr/bin/ruby
2
+ # Author: Dario Meloni <mellon85@gmail.com>
3
+ # This module is a binding to the Thomas Bernard miniupnp library
4
+ # written in C. It supports the IGD specification and works with IPv4
5
+ # only. Every exception that comes from inside the library is report as
6
+ # UPnPException while wrong arguments are returned as ArgumentError.
7
+
8
+ require 'MiniUPnP'
9
+ include ObjectSpace
10
+
11
+ module UPnP
12
+
13
+ # Represent a port mapping decriptor received from the router.
14
+ class PortMapping
15
+ # Internal address.
16
+ attr_reader :client
17
+
18
+ # Internal port.
19
+ attr_reader :lport
20
+
21
+ # External port.
22
+ attr_reader :nport
23
+
24
+ # External protocol.
25
+ attr_reader :protocol
26
+
27
+ # Provided description.
28
+ attr_reader :description
29
+
30
+ # Is the mapping enabled?.
31
+ attr_reader :enabled
32
+
33
+ # Don't know ...
34
+ attr_reader :rhost
35
+
36
+ # Duration of the binding.
37
+ attr_reader :duration
38
+
39
+ def initialize(cl,lp,np,p,d,e,rh,du)
40
+ @client = cl
41
+ @lport = lp
42
+ @nport = np
43
+ @protocol = p
44
+ @description = d
45
+ @enabled = e
46
+ @rhost = rh
47
+ @duration = du
48
+ end
49
+
50
+ def to_s()
51
+ return "#{@nport}->#{@client}:#{@lport} #{@protocol} for #{@duration} -- #{@description}"
52
+ end
53
+ end
54
+
55
+
56
+ # Enumeration of protocol values to pass to the library.
57
+ class Protocol
58
+ # TCP protcol
59
+ TCP = "TCP"
60
+
61
+ # UDP protocol
62
+ UDP = "UDP"
63
+ end
64
+
65
+ # Represents an exception from inside the library.
66
+ class UPnPException < Exception
67
+ end
68
+
69
+
70
+ # The UPNP class represent the binding to the library. It exports
71
+ # all the functions the library itself exports.
72
+ class UPnP
73
+
74
+ # Max time to wait for a broadcast answer from the routers.
75
+ attr_reader :max_wait_time
76
+
77
+ # This will create a new UPnP instance. max_wait is the maximum
78
+ # time the instance will wait for an answer from the router
79
+ # while seaching or it autodiscover to true will start a thread
80
+ # on the background to scan the network. All the other
81
+ # functions are safe to be called in the meanwhile, they will
82
+ # just wait for the scan to end before operating.
83
+ def initialize(autodiscover=true,max_wait=1000)
84
+ if max_wait <= 0 then
85
+ raise ArgumentError, "Max wait time must be >= 1."
86
+ end
87
+ if !(autodiscover.is_a? TrueClass) &&
88
+ !(autodiscover.is_a? FalseClass) then
89
+ raise ArgumentError, "Autodiscover must be a boolean value."
90
+ end
91
+ @max_wait_time = max_wait
92
+ # start the discover process at the object initialization.
93
+ # until ruby2, this thread will block the ruby environment
94
+ # for the wait time.
95
+ if autodiscover then
96
+ @igd_thread = Thread.new { discoverIGD }
97
+ else
98
+ @igd_thread = nil
99
+ end
100
+ return nil
101
+ end
102
+
103
+ # This method will search for other routers in the network and
104
+ # will wait the specified number of milliseconds that can be
105
+ # ovveridden by the parameter. It has currently (ruby 1.9) a
106
+ # limitation. As long as thread are cooperative the upnpDiscover
107
+ # function will block the ruby implementation waiting for the
108
+ # library. If this will not be solved with ruby 2.0 the
109
+ # interface upnp_wrap.c needs to be hacked. You can avoid to
110
+ # call this function if autodiscover is true. If no router or
111
+ # no UPnP devices are found an UPnPException is thrown.
112
+ def discoverIGD(max_wait_time=@max_wait_time)
113
+ joinThread()
114
+ if max_wait_time <= 0 then
115
+ raise ArgumentError, "Max wait time must be >= 1"
116
+ end
117
+ @list = MiniUPnP.upnpDiscover(max_wait_time,nil,nil)
118
+ if @list == nil then
119
+ raise UPnPException.new,"No UPNP Device Found"
120
+ end
121
+ define_finalizer(@list,proc {|o| MiniUPnP.freeUPNPDevlist(o)})
122
+
123
+ @urls = MiniUPnP::UPNPUrls.new
124
+ define_finalizer(@urls,proc {|o| MiniUPnP.FreeUPNPUrls(o)})
125
+ @data = MiniUPnP::IGDdatas.new
126
+ @lan = getCString()
127
+
128
+ r = MiniUPnP.UPNP_GetValidIGD(@list,@urls,@data,@lan,64);
129
+ if r == 0 || r == 3 then
130
+ raise UPnPException.new, "No IGD Found"
131
+ end
132
+ @lan = @lan.rstrip()
133
+ return nil
134
+ end
135
+
136
+ # Returns the ip of this client
137
+ def lanIP()
138
+ joinThread()
139
+ return @lan
140
+ end
141
+
142
+ # Returns the external network ip
143
+ def externalIP()
144
+ joinThread()
145
+ external_ip = getCString()
146
+ r = MiniUPnP.UPNP_GetExternalIPAddress(@urls.controlURL,
147
+ @data.servicetype,external_ip)
148
+ if r != 0 then
149
+ raise UPnPException.new, "Error while retriving the external ip address. #{code2error(r)}."
150
+ end
151
+ return external_ip.rstrip()
152
+ end
153
+
154
+ # Returns the ip of the router
155
+ def routerIP()
156
+ joinThread()
157
+ @data.urlbase.sub(/^.*\//,"").sub(/\:.*/,"")
158
+ end
159
+
160
+ # Returns the status of the router which is an array of 3 elements.
161
+ # Connection status, Last error, Uptime.
162
+ def status()
163
+ joinThread()
164
+ lastconnerror = getCString()
165
+ status = getCString()
166
+ uptime = 0
167
+ begin
168
+ uptime_uint = MiniUPnP.new_uintp()
169
+ r = MiniUPnP.UPNP_GetStatusInfo(@urls.controlURL,
170
+ @data.servicetype, status, uptime_uint,
171
+ lastconnerror) != 0
172
+ if r != 0 then
173
+ raise UPnPException.new, "Error while retriving status info. #{code2error(r)}."
174
+ end
175
+ uptime = MiniUPnP.uintp_value(uptime_uint)
176
+ rescue
177
+ raise
178
+ ensure
179
+ MiniUPnP.delete_uintp(uptime_uint)
180
+ end
181
+ return status.rstrip,lastconnerror.rstrip,uptime
182
+ end
183
+
184
+ # Router connection information
185
+ def connectionType()
186
+ joinThread()
187
+ type = getCString()
188
+ if MiniUPnP.UPNP_GetConnectionTypeInfo(@urls.controlURL,
189
+ @data.servicetype,type) != 0 then
190
+ raise UPnPException.new, "Error while retriving connection info."
191
+ end
192
+ type.rstrip
193
+ end
194
+
195
+ # Total bytes sent from the router to external network
196
+ def totalBytesSent()
197
+ joinThread()
198
+ v = MiniUPnP.UPNP_GetTotalBytesSent(@urls.controlURL_CIF,
199
+ @data.servicetype_CIF)
200
+ if v < 0 then
201
+ raise UPnPException.new, "Error while retriving total bytes sent."
202
+ end
203
+ return v
204
+ end
205
+
206
+ # Total bytes received from the external network.
207
+ def totalBytesReceived()
208
+ joinThread()
209
+ v = MiniUPnP.UPNP_GetTotalBytesReceived(@urls.controlURL_CIF,
210
+ @data.servicetype_CIF)
211
+ if v < 0 then
212
+ raise UPnPException.new, "Error while retriving total bytes received."
213
+ end
214
+ return v
215
+ end
216
+
217
+ # Total packets sent from the router to the external network.
218
+ def totalPacketsSent()
219
+ joinThread()
220
+ v = MiniUPnP.UPNP_GetTotalPacketsSent(@urls.controlURL_CIF,
221
+ @data.servicetype_CIF);
222
+ if v < 0 then
223
+ raise UPnPException.new, "Error while retriving total packets sent."
224
+ end
225
+ return v
226
+ end
227
+
228
+ # Total packets received from the router from the external network.
229
+ def totalPacketsReceived()
230
+ joinThread()
231
+ v = MiniUPnP.UPNP_GetTotalBytesSent(@urls.controlURL_CIF,
232
+ @data.servicetype_CIF)
233
+ if v < 0 then
234
+ raise UPnPException.new, "Error while retriving total packets received."
235
+ end
236
+ return v
237
+ end
238
+
239
+ # Returns the maximum bitrates detected from the router (may be an
240
+ # ADSL router) The result is in bytes/s.
241
+ def maxLinkBitrates()
242
+ joinThread()
243
+ up, down = 0, 0
244
+ begin
245
+ up_p = MiniUPnP.new_uintp()
246
+ down_p = MiniUPnP.new_uintp()
247
+ if MiniUPnP.UPNP_GetLinkLayerMaxBitRates(@urls.controlURL_CIF,
248
+ @data.servicetype_CIF,
249
+ down_p,up_p) != 0 then
250
+ raise UPnPException.new, "Error while retriving maximum link bitrates."
251
+ end
252
+ up = MiniUPnP.uintp_value(up_p)
253
+ down = MiniUPnP.uintp_value(down_p)
254
+ rescue
255
+ raise
256
+ ensure
257
+ MiniUPnP.delete_uintp(up_p)
258
+ MiniUPnP.delete_uintp(down_p)
259
+ end
260
+ return down,up
261
+ end
262
+
263
+ # An array of mappings registered on the router
264
+ def portMappings()
265
+ joinThread()
266
+ i, r = 0, 0
267
+ mappings = Array.new
268
+ while r == 0
269
+ rhost = getCString()
270
+ enabled = getCString()
271
+ duration = getCString()
272
+ description = getCString()
273
+ nport = getCString()
274
+ lport = getCString()
275
+ duration = getCString()
276
+ client = getCString()
277
+ protocol = getCString()
278
+
279
+ r = MiniUPnP.UPNP_GetGenericPortMappingEntry(@urls.controlURL,
280
+ @data.servicetype,i.to_s,nport,client,lport,
281
+ protocol,description,enabled,rhost,duration)
282
+ if r != 0 then
283
+ break;
284
+ end
285
+ i = i+1
286
+ mappings << PortMapping.new(client.rstrip,lport.rstrip.to_i,
287
+ nport.rstrip.to_i,protocol.rstrip,
288
+ description.rstrip,enabled.rstrip,
289
+ rhost.rstrip,duration.rstrip)
290
+ end
291
+ return mappings
292
+ end
293
+
294
+ # Get the mapping registered for a specific port and protocol
295
+ def portMapping(nport,proto)
296
+ checkProto(proto)
297
+ checkPort(nport)
298
+ if nport.to_i == 0 then
299
+ raise ArgumentError, "Port must be an int value and greater then 0."
300
+ end
301
+ joinThread()
302
+ client = getCString()
303
+ lport = getCString()
304
+ if MiniUPnP.UPNP_GetSpecificPortMappingEntry(@urls.controlURL,
305
+ @data.servicetype, nport.to_s,proto,
306
+ client,lport) != 0 then
307
+ raise UPnPException.new, "Error while retriving the port mapping."
308
+ end
309
+ return client.rstrip, lport.rstrip.to_i
310
+ end
311
+
312
+ # Add a port mapping on the router. Parametes are: network
313
+ # port, local port, description, protocol, ip address to
314
+ # register (or do not specify it to register for yours).
315
+ # Protocol must be Protocol::TCP or Protocol::UDP
316
+ def addPortMapping(nport,lport,proto,desc,client=nil)
317
+ checkProto(proto)
318
+ checkPort(nport)
319
+ checkPort(lport)
320
+ joinThread()
321
+ client ||= @lan if client == nil
322
+ r = MiniUPnP.UPNP_AddPortMapping(@urls.controlURL,@data.servicetype,
323
+ nport.to_s,lport.to_s,client,desc,proto)
324
+ if r != 0 then
325
+ raise UPnPException.new , "Failed add mapping: #{code2error(r)}."
326
+ end
327
+ end
328
+
329
+ # Delete the port mapping for specified network port and protocol
330
+ def deletePortMapping(nport,proto)
331
+ checkProto(proto)
332
+ checkPort(nport)
333
+ joinThread()
334
+ r = MiniUPnP.UPNP_DeletePortMapping(@urls.controlURL,@data.servicetype,
335
+ nport.to_s,proto)
336
+ if r != 0 then
337
+ raise UPnPException.new , "Failed delete mapping: #{code2error(r)}."
338
+ end
339
+ end
340
+
341
+ private
342
+
343
+ # Generates an empty string to use with the library
344
+ def getCString(len=128)
345
+ "\0"*len
346
+ end
347
+
348
+ # Method to wait until the scan is complete
349
+ def joinThread()
350
+ if @igd_thread != nil && Thread.current != @igd_thread then
351
+ @igd_thread.join()
352
+ end
353
+ end
354
+
355
+ # Check that the protocol is a correct value
356
+ def checkProto(proto)
357
+ if proto != Protocol::UDP && proto != Protocol::TCP then
358
+ raise ArgumentError, "Unknown protocol #{proto}, only Protocol::TCP and Protocol::UDP are valid."
359
+ end
360
+ end
361
+
362
+ def checkPort(port)
363
+ iport = port.to_i
364
+ if port.to_i != port || iport < 1 || iport > 65535 then
365
+ raise ArgumentError, "Port must be an integer beetween 1 and 65535."
366
+ end
367
+ end
368
+
369
+ def code2error(code)
370
+ case code
371
+ when 402
372
+ "402 Invalid Args"
373
+ when 501
374
+ "501 Action Failed"
375
+ when 713
376
+ "713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds"
377
+ when 714
378
+ "714 NoSuchEntryInArray - The specified value does not exist in the array"
379
+ when 715
380
+ "715 WildCardNotPermittedInSrcIP - The source IP address cannot be wild-carded"
381
+ when 716
382
+ "716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded"
383
+ when 718
384
+ "718 ConflictInMappingEntry - The port mapping entry specified conflicts with a mapping assigned previously to another client"
385
+ when 724
386
+ "724 SamePortValuesRequired - Internal and External port values must be the same"
387
+ when 725
388
+ "725 OnlyPermanentLeasesSupported - The NAT implementation only supports permanent lease times on port mappings"
389
+ when 726
390
+ "726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard and cannot be a specific IP address or DNS name"
391
+ when 727
392
+ "727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and cannot be a specific port value"
393
+ else
394
+ "Unknown Error - #{code2error(r)}"
395
+ end
396
+ end
397
+
398
+ end
399
+ end
400
+