Newsgroup: it.comp.lang.visual-basic
Titolo: Ping in Vb

Come posso fare il ping in una applicazione client/server con controllo
winsock???
Saluti Marco

 winsock???
c'è un esempio sull'API Guide (scaricabile gratuitamente da
http://www.allapi.net
)
Ciao
Faber


'Newsgroups: it.comp.lang.Visual -basic
'Subject: Re: Ping in VB5 (lungo)
'Date: Fri, 1 Dec 2000 16:47:04 +0100
'
'Visto che sono arrivate ad oggi N° 63 richieste per questa "cosa",
'vorrei chiedere di evitare di inviarne altre. Grazie.
'Vedrò di passare la simulazione al SC al più presto.
'Nel frattempo posto qui il mini-tutorial, nel caso servisse ad altri.
'
'----------------------------------------------------------------------
'
'Il termine "Ping" deriva dal termine gergale usato in marina
'per riferirsi agli echo di risposta di un segnale sonar.
'I "Pings" sono appunto i segnali auditivi prodotti dal dispositivo
'sonar quando identifica un rimbalzo del segnale su un oggetto
'solido.
'
'Similmente, in informatica un Ping è un "segnale" che viene
'inviato ad un host per verificare il suo stato attivo.
'se l 'host è attivo, fa "rimbalzare" la richiesta, ritornando
'al mittente il suo stato e altre informazioni.
'
'Nella definizione dei Sockets Berkeley standard, Ping è un echo
'di request/reply che si ottiene tramite un socket di tipo
'SOCK_RAW e un protocollo IPPROTO_ICMP o IPPROTO_RAW.
'I raw socket vengono in genere creati per bypassare i layer nello
'stack TCP/IP e generare pacchetti che il sistema (il Kernel in Unix,
'Winsock in Windows) non supporta in maniera esplicita.
'
'La funzione socket() di Winsock2 permette la creazione di tali
'socket:
'
'es.
'hSock = socket(AF_INET, SOCK_RAW, <protocol>)
'
'Specificando IPPROTO_RAW, l 'applicazione dovrà farsi carico
'di creare l'header di definizione del protocollo. Può essere
'utile in sistemi "chiusi" o che utilizzano pacchetti proprietari.
'Il numero di protocollo viene inserito nella struttura
'dell 'header IP. IPPROTO_RAW inserisce 0.
'
'La maggior parte dei sistemi operativi ha una socket option
'IP_HDRINCL (raw IP) che permette di definire l'header del protocollo.
'Per quanto riguarda i sistemi Windows, il supporto è abbastanza
'limitato:
'
'Win95 Win9x WinNT Windows
'Winsock 1.1 Winsock 2 4.0 2000
'
'Raw ICMP No Si Si Si
'IP_HDRINCL No No No Si
'Raw TCP/UDP No No No No
'
'Da tenere presente che con WinNT 4.0 e Win2000, solo gli utenti che
'sono membri del gruppo Administrators possono aprire dei raw socket.
'
'Un Ping si attua inviando un echo packet ICMP (internet control
'message protocol - altro protocollo IP distinto da TCP o UDP).
'Il sistema dispone degli strumenti per inviare pacchetti echo - per
'adeguarsi alle specifiche TCP/IP - ma non ha mezzi per generare
'questi pacchetti, per il fatto che non è richiesto.
'La generazione di "ping packet" è invece delegata a software che
'agisce a livello application. La generazione del pacchetto avviene
'quindi nello "user space". Per questo un'applicazione, per generare
'dei "ping packet", deve interagire con il sistema a basso livello
'e avere quindi un livello di accesso che permetta questa interazione.
'In Windows NT, il privilegio di accesso "Act as part of the
'Operating System" è in genere concesso solo agli utenti del
'gruppo Administrators.
'
'Come evidenziato nella tabella precedente, i raw socket ICMP
'sono supportati dalla versione 2 di Winsock. Quindi le versioni
'di Win95 senza upgrade (la versione fornita con il SO è la 1.1)
'non dispongono di questa funzionalità.
'Occorre anche dire che la versione 2 del socket dispone di una
'implementazione dei raw socket che può essere definita
'approssimativa. In particolare, nessuno degli stack Microsoft
'riporta errori Winsock se viene ricevuto un messaggio di errore
'ICMP. Ad esempio, se un sistema riceve un datagram e la porta
'di destinazione del datagram non è collegata, il sistema risponde
'con un "ICMP Destination Unreachable" (porta non raggiungibile).
'l 'applicazione chiamante dovrebbe ricevere un errore
'10061 (WSAECONNREFUSED), ma così non è. L'errore viene perso.
'Un "workaround" potrebbe essere quello di utilizzare la funzione
'bind(), specificando come indirizzo INADDR_ANY. Purtroppo molti
'datagrammi vengono ugualmente persi, senza contare che
'l 'applicazione non è in grado di ricevere gli echo request
'inviati dalla macchina su cui gira.
'Inoltre, utilizzando IPPROTO_RAW, viene inviato un header mal
'formato (il valore del protocollo è 255 invece di 0) e l'header
'stesso è inviato come "dati". Il ricevente risponde con un errore
'ICMP "protocol unreachable".
'
'Questi problemi non si riscontrano con Windows 2000.
'
'Per motivi legati a queste carenze implementative, particolarmente
'in relazione alla versione 1.1 del socket, Microsoft mette a
'disposizione una libreria (icmp.dll) che consente l'invio e la
'ricezione di echo ICMP nonché la manipolazione delle impostazioni
'degli header IP. La libreria si appoggia solamente a Kernel32, non
'a Winsock32.
'
'In particolare, la libreria esporta le funzioni:
'
'IcmpCreateFile()
'IcmpCloseHandle()
'IcmpSendEcho()
'
'La funzione IcmpSendEcho() viene utilizzata per inviare un
'echo (ping) ad un host, dato il suo indirizzo IP.
'In Visual Basic, le funzioni vengono dichiarate in questo modo:
Declare Function IcmpCreateFile Lib "icmp.dll" () As Long
Declare Function IcmpCloseHandle Lib "icmp.dll" _
(ByVal IcmpHandle As Long) As Long
Declare Function IcmpSendEcho Lib "icmp.dll" _
(ByVal IcmpHandle As Long, _
ByVal DestinationAddress As Long, _
ByVal RequestData As String, _
ByVal RequestSize As Integer, _
ByVal RequestOptions As Long, _
ReplyBuffer As ICMP_ECHO_REPLY, _
ByVal ReplySize As Long, _
ByVal TimeOut As Long) As Long
La funzione IcmpCreateFile() viene utilizzata, similmente
'alla funzione del Kernel CreateFile(), per inizializzare
'un handle che istanzia un Raw Socket ICMP.
'
'La funzione IcmpSendEcho() si occupa di inviare la richiesta
'di echo all'host specificato.
'
'I parametri della funzione:
'
'IcmpHandle: l 'handle restituito da IcmpCreateFile()
'
'DestinationAddress: indirizzo, in Network Byte Order, dell'host
'di destinazione dell'echo. L'indirizzo è in formato Long.
'Con "Network Byte Order" si intende la rappresentazione
'esadecimale degli ottetti che compongono l'indirizzo IP.
'La funzione, come evidente, tratta solamente indirizzi IpV4,
'composto da 4 ottetti, quindi 32 bit. Un indirizzo IpV6, ai
'fini di routing, è composto da 128 bit.
'Winsock mette a disposizione la funzione inet_addr() per la
'conversione di un indirizzo IP nel formato stringa nella
'sua rappresentazione numerica in network byte order.
'
'RequestData: stringa di caratteri, per un massimo di 32,
'che rappresenta il messaggio inviato all'host. Il set di
'caratteri utilizzato è l'Ascii standard a 7 bit (tutti i
'caratteri con codice inferiore a 128). L'eventuale conversione
'della stringa dal formato ANSI multi-bye in Ascii è viene
'effettuata dalla funzione.
'
'RequestSize: dimensione, in byte, della stringa definita da
'RequestData.
'
'RequestOptions: puntatore alla struttura ip_option_information.
'In genere si imposta a 0 (null), dato che la struttura viene
'inizializzata tramite il parametro ReplyBuffer.
Type IP_OPTIONS_INFORMATION
TTL As Byte
Tos As Byte
Flags As Byte
OptionsSize As Byte
OptionsData As Long
End Type
'TTL: Time to Live -> tempo di vita del pacchetto
'Flags: Generalmente = 0
'
'Per ulteriori informazioni fare riferimento all'RFC 791.
'
'ReplyBuffer: puntatore alla struttura icmp_echo_reply.
'Nella struttura vengono restituite alcune informazioni
'e i dati del datagramma.
Public Type ICMP_ECHO_REPLY
address As Long
Status As Long
RoundTripTime As Long
Datasize As Integer
Reserved As Integer
Datapointer As Long
Options As IP_OPTIONS_INFORMATION
data As String * 250
End Type
'address: indirizzo in network byte order dell'host che
'ha effettivamente risposto alla richiesta di echo.
'l 'indirizzo può essere diverso da quello dell'host
'chiamato.
'
'Status: 0 se la richiesta ha avuto successo, altrimenti
'è il codice dell'errore. I codici di errore sono riportati
'nella simulazione Ping.
'
'RoundTripTime: tempo approssimato (in ms) impiegato dal
'pacchetto per giungere a destinazione.
'
'Datasize: dimensione del pacchetto dati ricevuto. Deve
'essere uguale alle dimensioni del pacchetto inviato (32 byte).
'
'Reserved: riservato.Sempre 0#
'
'Datapointer: puntatore alla sezione data in coda alla
'struttura.
'
'Options: puntatore alla struttura IP_OPTIONS_INFORMATION
'TimeOut: tempo di attesa (in ms) prima di considerare perso il
'pacchetto inviato. Il tempo di timeout è stabilito dall'applicazione.
'Occorre valutare con attenzione l'impostazione di questo periodo
'di attesa. Un timeout troppo basso porta a considerare "unreachable"
'(quindi potenzialmente off-line o inesistente) un host che impiega
'molto tempo a rispondere.
'
'Il workflow di una richiesta echo ICMP è il seguente:
'
'Inizializzazione del socket
'--> Funzione WSAStartUp()
'
'Creazione di una porta ICMP
'--> Funzione IcmpCreateFile()
'
'Invio di un echo all'indirizzo IP
'--> Funzione IcmpSendEcho()
'
'Chiusura della handle
'--> Funzione IcmpCloseHandle()
'
'Reset del socket
'--> Funzione WSACleanUp()
'
'-----------------------------------------------------------------
'Come evidenziato, la funzione IcmpSendEcho() accetta solo
'indirizzi in Network Byte Order (Long). Ossia non è possibile
'specificare un FQDN (Fully Qualified Domain Name) come indirizzo.
'Per richiedere un echo ad un host di cui si conosce solo l'FQDN
'(es. 
www.microsoft.com
), occorre ottenere il suo indirizzo IP dal
'DNS di riferimento (il DNS dell'Internet Service Provider).
'A questo scopo si usa la funzione Winsock gethostbyname() a cui
'si passa il nome dell'host in formato stringa.
'La simulazione dispone un wrapper a questa funzione per mezzo
'della funzione GetHostIPAddress().
Public Function GetHostIPAddress( _
lpszHostName As String, _
strHostAlias As String) As String
'lpszHostName [In]: nome dell 'host di cui si chiede l'indirizzo IP
'strHostAlias [OUT]: in uscita rende l'FQDN dell'host cercato
'
'La funzione restituisce l'indirizzo IP dell'host in formato stringa.
'
'Per contro, quando si richiede un echo ad un host di cui si conosce
'l 'indirizzo IP, normalmente non viene restituito il suo FQDN.
'La simulazione, a scopo di esempio, implementa anche questa
'funzionalità.
'La funzione Winsock utilizzata è gethostbyaddr(), il cui wrapper
'è costituito dalla funzione GetHostNameByIPAddress()
Public Function GetHostNameByIPAddress( _
lpszAddress As String) As String
'lpszAddress: indirizzo IP dell'host
'
'La funzione restituisce l'FQDN dell'host
'-----------------------------------------------------------------