5using System.Net.NetworkInformation;
7using System.Threading.Tasks;
20 private static readonly
object upnpClientLock =
new object();
22 private static int upnpClientRefCount = 0;
25 internal IPAddress localAddress;
26 internal IPAddress externalAddress;
28 private readonly
ISniffer[] sniffers;
29 private HashSet<string> deviceUrlsProcessed =
new HashSet<string>();
32 private ManualResetEvent ready =
new ManualResetEvent(
false);
33 private ManualResetEvent error =
new ManualResetEvent(
false);
34 private Timer searchTimer =
null;
35 private bool upnpHandlerRegistered =
false;
36 internal bool disposed =
false;
46 this.sniffers = Sniffers;
48 NetworkChange.NetworkAddressChanged += this.NetworkChange_NetworkAddressChanged;
51 private async
void NetworkChange_NetworkAddressChanged(
object Sender, EventArgs e)
74 public virtual async Task
Start()
77 this.localAddress = this.externalAddress;
88 foreach (NetworkInterface Interface
in NetworkInterface.GetAllNetworkInterfaces())
90 if (Interface.OperationalStatus != OperationalStatus.Up)
93 IPInterfaceProperties Properties = Interface.GetIPProperties();
95 foreach (UnicastIPAddressInformation UnicastAddress
in Properties.UnicastAddresses)
100 this.externalAddress = UnicastAddress.Address;
115 if (Address.AddressFamily == AddressFamily.InterNetwork && Socket.OSSupportsIPv4)
117 byte[] Addr = Address.GetAddressBytes();
130 return (Addr[1] & 0xc0) != 64;
136 return Addr[1] != 254;
139 return (Addr[1] & 0xf0) != 16;
158 return Addr[2] != 99;
177 if (this.disposed || this.deviceUrlsProcessed is
null)
182 this.searchTimer?.Dispose();
183 this.searchTimer =
null;
185 if (!this.upnpHandlerRegistered)
187 lock (upnpClientLock)
189 upnpClientRefCount++;
192 upnpClient.OnDeviceFound += this.UpnpClient_OnDeviceFound;
193 this.upnpHandlerRegistered =
true;
197 lock (this.deviceUrlsProcessed)
199 this.deviceUrlsProcessed.Clear();
204 await upnpClient.
StartSearch(
"urn:schemas-upnp-org:service:WANIPConnection:1", 1);
205 await upnpClient.
StartSearch(
"urn:schemas-upnp-org:service:WANIPConnection:2", 1);
206 await upnpClient.
StartSearch(
"urn:schemas-upnp-org:service:WANPPPConnection:1", 1);
208 this.searchTimer =
new Timer(this.SearchTimeout,
null, 10000, Timeout.Infinite);
217 private async
void SearchTimeout(
object State)
221 this.searchTimer?.Dispose();
222 this.searchTimer =
null;
224 await this.UnregisterUPnPClient();
233 private async Task UnregisterUPnPClient()
237 lock (upnpClientLock)
239 if (this.upnpHandlerRegistered)
241 upnpClient.OnDeviceFound -= this.UpnpClient_OnDeviceFound;
242 this.upnpHandlerRegistered =
false;
244 if (--upnpClientRefCount == 0)
246 ToDispose = upnpClient;
252 if (!(ToDispose is
null))
256 private void Reinitialize(
object State)
258 this.searchTimer?.Dispose();
259 this.searchTimer =
null;
261 this.NetworkChange_NetworkAddressChanged(
this, EventArgs.Empty);
268 lock (this.deviceUrlsProcessed)
280 if (!(Service is
null))
288 Service = Doc.
GetService(
"urn:schemas-upnp-org:service:WANIPConnection:2");
289 if (!(Service is
null))
296 Service = Doc.
GetService(
"urn:schemas-upnp-org:service:WANPPPConnection:1");
297 if (!(Service is
null))
312 private async Task ServiceRetrieved(
IInternetGateway Gateway, IPEndPoint LocalEndPoint)
316 Dictionary<ushort, bool> TcpPortMapped =
new Dictionary<ushort, bool>();
317 Dictionary<ushort, bool> UdpPortMapped =
new Dictionary<ushort, bool>();
318 ushort PortMappingIndex;
320 this.internetGateway = Gateway;
324 this.externalAddress = IPAddress.Parse(NewExternalIPAddress);
330 Log.
Warning(
"External IP Address not a public IP address.");
334 PortMappingIndex = 0;
343 out ushort NewExternalPort, out
string NewProtocol, out ushort NewInternalPort, out
string NewInternalClient,
344 out
bool NewEnabled, out
string NewPortMappingDescription, out uint NewLeaseDuration);
354 foreach (InternetGatewayRegistration Registration
in this.ports)
356 if ((Registration.ExternalPort != 0 && NewExternalPort == Registration.ExternalPort) ||
357 (Registration.ExternalPort == 0 && NewPortMappingDescription == Registration.ApplicationName))
359 if (NewProtocol ==
"TCP")
362 Registration.TcpRegistered =
true;
365 else if (NewProtocol ==
"UDP")
368 Registration.UdpRegistered =
true;
372 Log.
Notice(
"Deleting Internet Gateway port mapping.",
373 new KeyValuePair<string, object>(
"Host", NewRemoteHost),
374 new KeyValuePair<string, object>(
"External Port", NewExternalPort),
375 new KeyValuePair<string, object>(
"Protocol", NewProtocol),
376 new KeyValuePair<string, object>(
"Local Port", NewInternalPort),
377 new KeyValuePair<string, object>(
"Local Address", NewInternalClient),
378 new KeyValuePair<string, object>(
"Application", NewPortMappingDescription));
380 this.internetGateway.
DeletePortMapping(NewRemoteHost, NewExternalPort, NewProtocol);
394 TcpPortMapped[NewExternalPort] =
true;
398 UdpPortMapped[NewExternalPort] =
true;
406 catch (AggregateException ex)
409 System.
Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw();
416 this.localAddress = LocalEndPoint.Address;
418 foreach (InternetGatewayRegistration Registration
in this.ports)
422 if ((Registration.TcpRegistered || !Registration.Tcp) &&
423 (Registration.UdpRegistered || !Registration.Udp))
428 if (Registration.Tcp && !Registration.TcpRegistered)
430 Log.
Notice(
"Adding Internet Gateway port mapping.",
431 new KeyValuePair<string, object>(
"Host",
string.Empty),
432 new KeyValuePair<string, object>(
"External Port", Registration.ExternalPort),
433 new KeyValuePair<string, object>(
"Protocol",
"TCP"),
434 new KeyValuePair<string, object>(
"Local Port", Registration.LocalPort),
435 new KeyValuePair<string, object>(
"Local Address",
this.LocalAddress.ToString()),
436 new KeyValuePair<string, object>(
"Application", Registration.ApplicationName));
440 this.internetGateway.
AddPortMapping(
string.Empty, Registration.ExternalPort,
441 "TCP", Registration.LocalPort,
this.LocalAddress.ToString(),
true, Registration.ApplicationName, 0);
443 Registration.TcpRegistered =
true;
447 Log.
Error(
"Unable to register port in Internet Gateway: " + ex.Message,
448 new KeyValuePair<string, object>(
"External Port", Registration.ExternalPort),
449 new KeyValuePair<string, object>(
"Protocol",
"TCP"),
450 new KeyValuePair<string, object>(
"Local Port", Registration.LocalPort),
451 new KeyValuePair<string, object>(
"Local Address",
this.LocalAddress.ToString()),
452 new KeyValuePair<string, object>(
"Application", Registration.ApplicationName));
456 if (Registration.Udp && !Registration.UdpRegistered)
458 Log.
Notice(
"Adding Internet Gateway port mapping.",
459 new KeyValuePair<string, object>(
"Host",
string.Empty),
460 new KeyValuePair<string, object>(
"External Port", Registration.ExternalPort),
461 new KeyValuePair<string, object>(
"Protocol",
"UDP"),
462 new KeyValuePair<string, object>(
"Local Port", Registration.LocalPort),
463 new KeyValuePair<string, object>(
"Local Address",
this.LocalAddress.ToString()),
464 new KeyValuePair<string, object>(
"Application", Registration.ApplicationName));
468 this.internetGateway.
AddPortMapping(
string.Empty, Registration.ExternalPort,
469 "UDP", Registration.LocalPort,
this.LocalAddress.ToString(),
true, Registration.ApplicationName, 0);
471 Registration.UdpRegistered =
true;
475 Log.
Error(
"Unable to register port in Internet Gateway: " + ex.Message,
476 new KeyValuePair<string, object>(
"External Port", Registration.ExternalPort),
477 new KeyValuePair<string, object>(
"Protocol",
"UDP"),
478 new KeyValuePair<string, object>(
"Local Port", Registration.LocalPort),
479 new KeyValuePair<string, object>(
"Local Address",
this.LocalAddress.ToString()),
480 new KeyValuePair<string, object>(
"Application", Registration.ApplicationName));
503 Dictionary<ushort, bool> TcpPortMapped, Dictionary<ushort, bool> UdpPortMapped)
505 return Task.CompletedTask;
515 if (this.state != NewState)
517 this.state = NewState;
522 this.searchTimer?.Dispose();
523 this.searchTimer =
null;
528 this.searchTimer?.Dispose();
529 this.searchTimer =
null;
532 this.searchTimer =
new Timer(this.Reinitialize,
null, 60000, Timeout.Infinite);
543 public event EventHandlerAsync<PeerToPeerNetworkState>
OnStateChange =
null;
566 return this.
Wait(10000);
574 public bool Wait(
int TimeoutMilliseconds)
576 switch (WaitHandle.WaitAny(
new WaitHandle[] { this.ready, this.error }, TimeoutMilliseconds))
590 [Obsolete(
"Use DisposeAsync() instead.")]
608 this.disposed =
true;
611 NetworkChange.NetworkAddressChanged -= this.NetworkChange_NetworkAddressChanged;
613 this.searchTimer?.Dispose();
614 this.searchTimer =
null;
616 await this.UnregisterUPnPClient();
620 if (Registration.TcpRegistered)
622 Registration.TcpRegistered =
false;
625 Log.
Notice(
"Deleting Internet Gateway port mapping.",
626 new KeyValuePair<string, object>(
"Host",
string.Empty),
627 new KeyValuePair<string, object>(
"External Port", Registration.
ExternalPort),
628 new KeyValuePair<string, object>(
"Protocol",
"TCP"),
629 new KeyValuePair<string, object>(
"Local Port", Registration.
LocalPort),
630 new KeyValuePair<string, object>(
"Application", Registration.
ApplicationName));
640 if (Registration.UdpRegistered)
642 Registration.UdpRegistered =
false;
645 Log.
Notice(
"Deleting Internet Gateway port mapping.",
646 new KeyValuePair<string, object>(
"Host",
string.Empty),
647 new KeyValuePair<string, object>(
"External Port", Registration.
ExternalPort),
648 new KeyValuePair<string, object>(
"Protocol",
"UDP"),
649 new KeyValuePair<string, object>(
"Local Port", Registration.
LocalPort),
650 new KeyValuePair<string, object>(
"Application", Registration.
ApplicationName));
661 this.internetGateway =
null;
663 this.deviceUrlsProcessed?.Clear();
664 this.deviceUrlsProcessed =
null;
666 this.ready?.Dispose();
669 this.error?.Dispose();
681 if (IPAddress.Equals(RemoteEndPoint.Address,
this.externalAddress))
684 out ushort InternalPort, out
string InternalClient, out
bool _, out
string _, out uint
_);
686 return new IPEndPoint(IPAddress.Parse(InternalClient), InternalPort);
689 return RemoteEndPoint;
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
static void Notice(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a notice event.
Represents a registraing in an UPnP-compatible Internet Gateway.
ushort LocalPort
Port on local machine.
ushort ExternalPort
Port on external side of gateway.
string ApplicationName
Name of application to be registered.
Manages registration of TCP and UDP ports in an Internet Gateway
IPAddress LocalAddress
Local IP Address.
async Task SearchGateways()
Searches for Internet Gateways in the network.
virtual async Task Start()
Starts the registration.
Exception Exception
In case State=PeerToPeerNetworkState.Error, this exception object contains details about the error.
virtual async Task DisposeAsync()
IDisposable.Dispose
static bool IsPublicAddress(IPAddress Address)
Checks if an IPv4 address is public.
EventHandlerAsync< PeerToPeerNetworkState > OnStateChange
Event raised when the state of the peer-to-peer network changes.
IPAddress ExternalAddress
External IP Address.
void Dispose()
IDisposable.Dispose
IPEndPoint CheckLocalRemoteEndpoint(IPEndPoint RemoteEndPoint)
Checks if a remote endpoint resides in the internal network, and if so, replaces it with the correspo...
bool Wait(int TimeoutMilliseconds)
Waits for the peer-to-peer network object to be ready to receive connections.
bool Wait()
Waits for the peer-to-peer network object to be ready to receive connections.
bool OnPublicNetwork()
If the machine is on a public network.
InternetGatewayRegistrator(InternetGatewayRegistration[] Ports, params ISniffer[] Sniffers)
Manages registration of TCP and UDP ports in an Internet Gateway
PeerToPeerNetworkState State
Current state of the peer-to-peer network object.
virtual Task BeforeRegistration(InternetGatewayRegistration Registration, Dictionary< ushort, bool > TcpPortMapped, Dictionary< ushort, bool > UdpPortMapped)
is called before performing a registration.
Contains the information provided in a Device Description Document, downloaded from a device in the n...
UPnPService GetService(string ServiceType)
Gets a service, given its service type.
Event arguments for completion events when downloading device description documents.
IPEndPoint LocalEndPoint
Local End Point
DeviceLocation Location
Device Location information.
Task< DeviceDescriptionDocument > GetDeviceAsync()
Gets a Device Description Document from a device.
string Location
Location of device information
Contains the information provided in a Service Description Document, downloaded from a service in the...
Implements support for the UPnP protocol, as described in: http://upnp.org/specs/arch/UPnP-arch-Devic...
Task StartSearch()
Starts a search for devices on the network.
async Task DisposeAsync()
IDisposableAsync.DisposeAsync
Contains information about a service.
Task< ServiceDescriptionDocument > GetServiceAsync()
Starts the retrieval of a Service Description Document.
Interface for asynchronously disposable objects.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Interface for Internet Gateway Services.
void GetExternalIPAddress(out string NewExternalIPAddress)
Gets the external public IP address.
void DeletePortMapping(string NewRemoteHost, ushort NewExternalPort, string NewProtocol)
Deletes a port mapping entry.
void GetGenericPortMappingEntry(ushort PortMappingIndex, out string NewRemoteHost, out ushort NewExternalPort, out string NewProtocol, out ushort NewInternalPort, out string NewInternalClient, out bool NewEnabled, out string NewPortMappingDescription, out uint NewLeaseDuration)
Gets a port mapping entry.
void AddPortMapping(string NewRemoteHost, ushort NewExternalPort, string NewProtocol, ushort NewInternalPort, string NewInternalClient, bool NewEnabled, string NewPortMappingDescription, uint NewLeaseDuration)
Adds a port mapping entry.
void GetSpecificPortMappingEntry(string NewRemoteHost, ushort NewExternalPort, string NewProtocol, out ushort NewInternalPort, out string NewInternalClient, out bool NewEnabled, out string NewPortMappingDescription, out uint NewLeaseDuration)
Gets a specific port mapping entry.
PeerToPeerNetworkState
State of Peer-to-peer network.