Jump to content

Recommended Posts

Posted

Hi all,

I need your help because I do not come on.

The purpose of my program is to collect all sent replies within 15 second of all devices in my network, after my SSDP-Discover via UPnP. Every 3 seconds, I will send again.

My program works on Windows XP, independent how many network cards are installed. In Windows 7 only, if only one network card is installed or active. This means, if all network cards are active, I get no UPnP-Responds. When I disable all network cards (vmware network adapter too!), except 1, my program works in Windows 7 too. the windows firewall is deactivated.

Now I'm not sure if I make a principal mistake or maybe it's a bug in AutoIt? to test several things, I wrote 2 functions:

The SSDPdiscover_V1 works as just described above. I use for UDPRecv the same port, which was used for sending.

In SSDPdiscover_V2 I've tried various UDPBinds to catch the incoming UPnP-packets, but nothing works :-( If you want to test this, you must adjust the call in main.

here is my program. Or you can use the attachment:

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=.\SSDPdiscover.exe
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_Res_Description=
#AutoIt3Wrapper_Res_Fileversion=0.0.0.1
#AutoIt3Wrapper_Res_LegalCopyright=(c) by Rainer Ullrich
#AutoIt3Wrapper_Res_Language=1031
://////=__=
://////=__=.=
#AutoIt3Wrapper_Run_After=del ".\SSDPdiscover*.au3.tbl"
#AutoIt3Wrapper_Run_After=del ".\SSDPdiscover*_Obfuscated.au3"
#AutoIt3Wrapper_Run_Obfuscator=y
#AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#Obfuscator_Parameters=/cs=1 /cn=1 /cf=1 /cv=1 /sf=1 /sv=1
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <Date.au3>
#include <Array.au3>
Opt("MustDeclareVars", 1)
; --- MainVar-Deklaration ---
#region MainVar-Deklaration
; Für SSDPdiscover
Global $MyCollectedResponses ; Array with the collected Responses
Global $MyCollectedIPs ; Array with the collected IPs
Global $MyTimeToSearch = 15 * 1000 ; time to search in ticks
Global $MySendInterval = 3 * 1000; each x ticks the ssdp-discover will be sent
Global $MyResultDatei = ".\ssdp-discover-result.txt"
Global $MyTemp, $MyError, $MyReturn
; MsgBox
Global Const $Mnormal = 0 + 262144
Global Const $Merror = 16 + 262144
Global Const $Mquestion = 32 + 262144
Global Const $Mattention = 48 + 262144
Global Const $Mresult = 64 + 262144
#endregion MainVar-Deklaration

; --- Main ---
#region Main
; -- SSDP Discxover via UPnP --
$MyReturn = SSDPdiscover_V1($MyCollectedResponses, $MyCollectedIPs, $MyTimeToSearch, $MySendInterval) ; change here ..._V1 or ..._V2   <-------------
$MyError = @error
If $MyError <> 0 Then
$MyTemp = "SSDPdiscover failed!" & @CRLF & @CRLF
Switch $MyError
  Case 0
   ; nix
  Case 1
   $MyTemp &= "UDPOpen-error"
  Case 2
   $MyTemp &= "UDPSend-error"
  Case 3
   $MyTemp &= "UDPRecv-error"
  Case 4
   $MyTemp &= "UDPBind-error"
EndSwitch
MsgBox($Merror, "error:", $MyTemp)
Exit
EndIf

; -- Result --
; delete file
If FileExists($MyResultDatei) Then
If Not FileDelete($MyResultDatei) Then
  MsgBox($Merror, "error:", 'the file "' & $MyResultDatei & '" could not be deletet!')
  Exit
EndIf
EndIf
; Responses
If IsArray($MyCollectedResponses) Then
$MyTemp = ''
For $e = 1 To $MyCollectedResponses[0]
  $MyTemp &= $MyCollectedResponses[$e] & @CRLF
Next
If FileWrite($MyResultDatei, $MyTemp) Then
  ; Quickhack un die Datei zu öffnen
  Run(@ComSpec & ' /c start "" "' & $MyResultDatei & '"', @WorkingDir, @SW_HIDE)
  MsgBox($Mresult, "result:", 'the result was writen in the file "' & $MyResultDatei & '"!')
Else
  MsgBox($Mresult, "result:", 'the file could not be written in the file "' & $MyResultDatei & '"!')
EndIf
Else
MsgBox(0, "result:", "no responses via UPnP!")
EndIf
; IP
If IsArray($MyCollectedIPs) Then
_ArrayDisplay($MyCollectedIPs, "Collectes IPs")
Else
MsgBox($Mresult, "result:", "no IP-addresses found!")
EndIf
Exit
#endregion Main
; --- Funktionsdefinitionen ---
#region Funktionsdefinitionen
; Function that performs a UPnP ssdp-discover and writes the results into an array.
; In addition, the IP addresses of the devices are written in a second array.
; V1: Receive-Socket = Send-Socket. Works on XP (independed how many networkcards are installed) and Win 7 only, when all network cards, exclude 1, are disabled in the device manager
; Error:
;   0  =  kein Error
;   1  =  UDPOpen-error
;   2  =  UDPSend-error
;   3  =  UDPRecv-error
;   4  =  UDPBind-error
Func SSDPdiscover_V1(ByRef $ResponsesArray, ByRef $IPArray, $TicksToSearch = 10000, $SendIntervalInTicks = 1000)
; --- UPnP-Kommando ---
Local Const $UPnPcmd = _
   'M-SEARCH * HTTP/1.1' & @CRLF & _
   'ST:upnp:rootdevice' & @CRLF & _
   'MX: 10' & @CRLF & _
   'MAN: "ssdp:discover"' & @CRLF & _
   'HOST: 239.255.255.250:1900' & @CRLF & _
   @CRLF
Local $UPNPsendSocket, $UPNPreceiveSocket
Local $SendCounter = 0, $ReceiveCounter = 0
Local $ReceiveData, $NewIP
Local $StartTimeoutTimer, $UsedTimeoutTicks ; Timeout-Timer
Local $StartSendTimer, $UsedSendTicks ; Send-Timer
Local $OldRemainSeconds = -99, $RemainSeconds
Local $return = 1, $error = 0
; Arrays "löschen"
$ResponsesArray = ""
$IPArray = ""
; UPnP-Kommando ausgeben
ConsoleWrite(@CRLF)
ConsoleWrite("UPnP-Kommando:" & @CRLF)
ConsoleWrite($UPnPcmd & @CRLF)
; UDP starten
UDPStartup()
; - Sender -
;   $array[1] contains the real socket, $array[2] contains the specified IP address and $array[3] contains the port
$UPNPsendSocket = UDPOpen("239.255.255.250", 1900)
ConsoleWrite("SendSocket: real socket: " & $UPNPsendSocket[1] & ", IP-address: " & $UPNPsendSocket[2] & ", port: " & $UPNPsendSocket[3] & @CRLF & @CRLF)
; _ArrayDisplay($UPNPsendSocket)
If $UPNPsendSocket[0] == -1 Or $UPNPsendSocket[0] == 0 Then ; documentation is somewhat vague
  ; Error 1
  Return SetError(1, 0, 0)
EndIf
; - Empfänger -
; Socket muß der gleiche sein, sonst geht es nicht. Allerdings funktioniert es nicht auf Win 7-Rechnern mit mehreren Netzwerkkarten :-(
$UPNPreceiveSocket = $UPNPsendSocket
; Timer setzen
$StartTimeoutTimer = TimerInit() ; Timeout-Timer
$StartSendTimer = -99 ; Notlösung, kann man schöner programmieren
While 1
  ; SenderPause berechnen
  If $StartSendTimer = -99 Then
   ; Timer wurde bisher noch nicht gesetzt, daher UsedTicks setzen
   $UsedSendTicks = $SendIntervalInTicks + 10
  Else
   ; Berechnen
   $UsedSendTicks = TimerDiff($StartSendTimer)
  EndIf
  ; Senden
  If $UsedSendTicks > $SendIntervalInTicks Then
   $SendCounter += 1
   ConsoleWrite("UPnP Send Count Nr " & $SendCounter & @CRLF & @CRLF)
   UDPSend($UPNPsendSocket, $UPnPcmd)
   If @error <> 0 Then
    $error = 2
    $return = 0
    ExitLoop
   EndIf
   ; reset timer
   $StartSendTimer = TimerInit()
  EndIf
  ; kurze Pause (nach dem Senden)
  Sleep(100)
  ; Empfangen
  $ReceiveData = UDPRecv($UPNPreceiveSocket, 1024)
  If @error <> 0 Then
   $error = 3
   $return = 0
   ExitLoop
  EndIf
  If $ReceiveData <> "" Then
   $ReceiveCounter += 1
   ConsoleWrite("-------------------- Received Response " & $ReceiveCounter & ":" & " --------------------" & @CRLF)
   ConsoleWrite($ReceiveData & @CRLF)
   ; Wenn neue Responds, dann hinzugügen
   If AddItemToArray($ResponsesArray, $ReceiveData, 1) > 0 Then
    ConsoleWrite("-> hinzugefügt" & @CRLF & @CRLF)
   Else
    ConsoleWrite("-> bereits vorhanden" & @CRLF & @CRLF)
   EndIf
   ; IP extrahieren und sammeln
   $NewIP = FetchIPfromUPNPdata($ReceiveData)
   If $NewIP <> "" Then AddItemToArray($IPArray, $NewIP, 1)
  EndIf
  ; Verbrauchte Zeit ermitteln
  $UsedTimeoutTicks = TimerDiff($StartTimeoutTimer)
  ; Wenn die Zeit verstrichen ist, dann raus
  If $UsedTimeoutTicks >= $TicksToSearch Then
   ExitLoop
  Else
   ; Restsekunden berechnen und als TrayTip ausgeben
   $RemainSeconds = Ceiling(($TicksToSearch - $UsedTimeoutTicks) / 1000)
   If $RemainSeconds <> $OldRemainSeconds Then
    TrayTip("SSDP-Discover", "Search for devices via UPnP (" & $RemainSeconds & " seconds)... ", 5, 1)
    $OldRemainSeconds = $RemainSeconds
   EndIf
  EndIf
WEnd
; TrayTip schliessen
TrayTip("", "", 0)
; Socket schliessen
UDPCloseSocket($UPNPsendSocket)
UDPCloseSocket($UPNPreceiveSocket)
; UDP beenden
UDPShutdown()
; Sortieren
If IsArray($IPArray) Then _ArraySort($IPArray, 0, 1)
If IsArray($ResponsesArray) Then _ArraySort($ResponsesArray, 0, 1)
; Wenn error vorhanden, dann error zurückliefern
If $error > 0 Then
  ; error zurückliefern
  Return SetError($error, 0, $return)
Else
  ; Normaler Return
  Return $return
EndIf
EndFunc   ;==>SSDPdiscover_V1

; Function that performs a UPnP ssdp-discover and writes the results into an array.
; In addition, the IP addresses of the devices are written in a second array.
; V2: Receive-Socket and Send-Socket are differ. I try many different ways, but nothing works :-(
; Error:
;   0  =  kein Error
;   1  =  UDPOpen-error
;   2  =  UDPSend-error
;   3  =  UDPRecv-error
;   4  =  UDPBind-error
Func SSDPdiscover_V2(ByRef $ResponsesArray, ByRef $IPArray, $TicksToSearch = 10000, $SendIntervalInTicks = 1000)
; --- UPnP-Kommando ---
Local Const $UPnPcmd = _
   'M-SEARCH * HTTP/1.1' & @CRLF & _
   'ST:upnp:rootdevice' & @CRLF & _
   'MX: 10' & @CRLF & _
   'MAN: "ssdp:discover"' & @CRLF & _
   'HOST: 239.255.255.250:1900' & @CRLF & _
   @CRLF
Local $UPNPsendSocket, $UPNPreceiveSocket
Local $SendCounter = 0, $ReceiveCounter = 0
Local $ReceiveData, $NewIP
Local $StartTimeoutTimer, $UsedTimeoutTicks ; Timeout-Timer
Local $StartSendTimer, $UsedSendTicks ; Send-Timer
Local $OldRemainSeconds = -99, $RemainSeconds
Local $return = 1, $error = 0
; Arrays "löschen"
$ResponsesArray = ""
$IPArray = ""
; UPnP-Kommando ausgeben
ConsoleWrite(@CRLF)
ConsoleWrite("UPnP-Kommando:" & @CRLF)
ConsoleWrite($UPnPcmd & @CRLF)
; UDP starten
UDPStartup()
; - Sender -
;   $array[1] contains the real socket, $array[2] contains the specified IP address and $array[3] contains the port
$UPNPsendSocket = UDPOpen("239.255.255.250", 1900)
ConsoleWrite("SendSocket: real socket: " & $UPNPsendSocket[1] & ", IP-address: " & $UPNPsendSocket[2] & ", port: " & $UPNPsendSocket[3] & @CRLF & @CRLF)
; _ArrayDisplay($UPNPsendSocket)
If $UPNPsendSocket[0] == -1 Or $UPNPsendSocket[0] == 0 Then ; documentation is somewhat vague
  ; Error 1
  Return SetError(1, 0, 0)
EndIf
; - Empfänger -
If @IPAddress1 <> "0.0.0.0" Then ConsoleWrite(@IPAddress1 & @CRLF)
If @IPAddress2 <> "0.0.0.0" Then ConsoleWrite(@IPAddress2 & @CRLF)
If @IPAddress3 <> "0.0.0.0" Then ConsoleWrite(@IPAddress3 & @CRLF)
If @IPAddress4 <> "0.0.0.0" Then ConsoleWrite(@IPAddress4 & @CRLF)
; $UPNPreceiveSocket = UDPBind("127.0.0.1", 1900)
; $UPNPreceiveSocket = UDPBind(@IPAddress1, 1900)
; $UPNPreceiveSocket = UDPBind("127.0.0.1", $UPNPsendSocket[1])
; $UPNPreceiveSocket = UDPBind(@IPAddress1, $UPNPsendSocket[1])
; $UPNPreceiveSocket = UDPBind("239.255.255.250", 1900)
$UPNPreceiveSocket = UDPBind(@IPAddress1, 1900)
ConsoleWrite("ReceiveSocket: real socket: " & $UPNPreceiveSocket[1] & ", IP-address: " & $UPNPreceiveSocket[2] & ", port: " & $UPNPreceiveSocket[3] & @CRLF & @CRLF)
; _ArrayDisplay($UPNPsendSocket)
If $UPNPreceiveSocket[0] == -1 Or $UPNPreceiveSocket[0] == -0 Then ; documentation is somewhat vague
  ; Error 4
  Return SetError(4, 0, 0)
EndIf
; Timer setzen
$StartTimeoutTimer = TimerInit() ; Timeout-Timer
$StartSendTimer = -99 ; temporary solution, could be better :)
While 1
  ; SenderPause berechnen
  If $StartSendTimer = -99 Then
   ; Timer wurde bisher noch nicht gesetzt, daher UsedTicks setzen
   $UsedSendTicks = $SendIntervalInTicks + 10
  Else
   ; Berechnen
   $UsedSendTicks = TimerDiff($StartSendTimer)
  EndIf
  ; Senden
  If $UsedSendTicks > $SendIntervalInTicks Then
   $SendCounter += 1
   ConsoleWrite("UPnP Send Count Nr " & $SendCounter & @CRLF & @CRLF)
   UDPSend($UPNPsendSocket, $UPnPcmd)
   If @error <> 0 Then
    $error = 2
    $return = 0
    ExitLoop
   EndIf
   ; reset timer
   $StartSendTimer = TimerInit()
  EndIf
  ; kurze Pause (nach dem Senden)
  Sleep(100)
  ; Empfangen
  $ReceiveData = UDPRecv($UPNPreceiveSocket, 1024)
  If @error <> 0 Then
   $error = 3
   $return = 0
   ExitLoop
  EndIf
  If $ReceiveData <> "" Then
   $ReceiveCounter += 1
   ConsoleWrite("-------------------- Received Response " & $ReceiveCounter & ":" & " --------------------" & @CRLF)
   ConsoleWrite($ReceiveData & @CRLF)
   ; Wenn neue Responds, dann hinzugügen
   If AddItemToArray($ResponsesArray, $ReceiveData, 1) > 0 Then
    ConsoleWrite("-> hinzugefügt" & @CRLF & @CRLF)
   Else
    ConsoleWrite("-> bereits vorhanden" & @CRLF & @CRLF)
   EndIf
   ; IP extrahieren und sammeln
   $NewIP = FetchIPfromUPNPdata($ReceiveData)
   If $NewIP <> "" Then AddItemToArray($IPArray, $NewIP, 1)
  EndIf
  ; Verbrauchte Zeit ermitteln
  $UsedTimeoutTicks = TimerDiff($StartTimeoutTimer)
  ; Wenn die Zeit verstrichen ist, dann raus
  If $UsedTimeoutTicks >= $TicksToSearch Then
   ExitLoop
  Else
   ; Restsekunden berechnen und als TrayTip ausgeben
   $RemainSeconds = Ceiling(($TicksToSearch - $UsedTimeoutTicks) / 1000)
   If $RemainSeconds <> $OldRemainSeconds Then
    TrayTip("SSDP-Discover", "Search for devices via UPnP (" & $RemainSeconds & " seconds)... ", 5, 1)
    $OldRemainSeconds = $RemainSeconds
   EndIf
  EndIf
WEnd
; TrayTip schliessen
TrayTip("", "", 0)
; Socket schliessen
UDPCloseSocket($UPNPsendSocket)
UDPCloseSocket($UPNPreceiveSocket)
; UDP beenden
UDPShutdown()
; Sortieren
If IsArray($IPArray) Then _ArraySort($IPArray, 0, 1)
If IsArray($ResponsesArray) Then _ArraySort($ResponsesArray, 0, 1)
; Wenn error vorhanden, dann error zurückliefern
If $error > 0 Then
  ; error zurückliefern
  Return SetError($error, 0, $return)
Else
  ; Normaler Return
  Return $return
EndIf
EndFunc   ;==>SSDPdiscover_V2
; Funktion, die aus den ReceivedPacket die IP-Adresse extrahiert
Func FetchIPfromUPNPdata($Data)
#cs Beispiel:

  HTTP/1.1 200 OK
  LOCATION: http://192.168.5.1:49000/igddesc.xml
  SERVER: WLAN_VDSL_Ullrich UPnP/1.0 AVM FRITZ!Box Fon WLAN 7270 54.04.74
  CACHE-CONTROL: max-age=1800
  EXT:
  ST: upnp:rootdevice
  USN: uuid:75802409-bccb-40e7-8e6c-001F3F56E239::upnp:rootdevice
#ce
; --- Einfach mit RegExp die IP rausfiltern ---
; Local $IP = StringRegExp($Data, "LOCATION: http://\d+\.\d+\.\d+\.\d+:49", 1)
Local $IP = StringRegExp($Data, "\d+\.\d+\.\d+\.\d+", 1)
; _ArrayDisplay($IP)
; Scheun ob es ein Array ist, wenn nicht raus
If Not IsArray($IP) Then Return ""
; Ich bauche erstes Element aus dem RegExp-Ergebnis
$IP = $IP[0]
; überprüfen auf Gültigkeit
If Not _IsIPv4($IP) Then Return ""
Return $IP
EndFunc   ;==>FetchIPfromUPNPdata

; Funktion, die überprüft, ob es eine gültige IP4-IP ist
Func _IsIPv4($S_IP)
If StringRegExp($S_IP, "\A(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])\z") Then Return (1)
Return (0)
EndFunc   ;==>_IsIPv4

; Funktion, die ein Item an das Array (mit Zelle) hinzufügt und dabei den Counter in Zelle 0 um eins erhöht
; Ist das Array noch leer, wird es angelegt. Es wird der Counter zurückgeliefert
; Wenn $OnlyIfNew = 1, dann wird vorher geschaut, ob es schon im Array vorhanden ist
Func AddItemToArray(ByRef $ArrayWithCounterCell, $value, $OnlyIfNew = 0) ; Fügt zum Array ein Item hinzu und erhöht den Wert in Zelle 0. Ist das Array leer, wird eines erzeugt
; Schauen, ob es ein Array ist. Wenn nicht, dann wird es angelegt und der Wert hinzugefügt
If IsArray($ArrayWithCounterCell) Then
  ; es ist ein Array
  ; ggf. schauen, ob es bereits enthalten ist
  If $OnlyIfNew == 1 Then
   ; Raus, wenn es bereist enthalten ist, also größer als 0
   If _ArraySearch($ArrayWithCounterCell, $value, 1) > 0 Then
    Return 0
   EndIf
  EndIf
  ; Element hinzufügen
  Local $ret = _ArrayAdd($ArrayWithCounterCell, $value)
  ; wenn ungleich -1 dann den Counter erhöhen
  If $ret <> -1 Then
   ; um 1 erhöhren in Zelle 0
   Local $Count = $ArrayWithCounterCell[0] + 1
   $ArrayWithCounterCell[0] = $Count
   ; Index, also Count zurückliefern
   Return $Count
  Else
   Return -1
  EndIf
Else
  ; Es ist kein Array, daher erzeugen und Wert hinzufügen
  Dim $ArrayWithCounterCell[2]
  $ArrayWithCounterCell[0] = 1
  $ArrayWithCounterCell[1] = $value
  Return 1
EndIf
EndFunc   ;==>AddItemToArray
#endregion Funktionsdefinitionen

Yes, I know, there is also a but my final goal is, to collect the "Locations", and the Obj-methode doesn't provide this information.

Does anyone have any idea what I'm doing wrong?

Many thanks and best regards

skyteddy

SSDPdiscover_V3_english.au3

Posted

Hi all,

I've just noticed with dismay, on Windows XP I receive only answers from devices, they are connected on the first network card.

I don't receive anything from the devices, they are connected on the second network cards.

When I want to "read" this devices, I must disable the first network card in Device Manager.

What do I wrong in principle or what is the matter?

many thanks in advance

skyteddy

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...