Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Rilevare le variazioni alle interfacce di rete ed eseguire una notifica via email


Chi dispone di una linea ADSL a casa propria nella maggiorparte dei casi non dispone di un indirizzo IP fisso ma l' indirizzo IP della connessione internet viene generato dinamicamente tutte le volte che la connessione viene instaurata. Se ho un computer su cui lavora ad esempio mia sorella che usa internet e quando sono in giro col mio portatile voglio collegarmi a questo computer, devo sapere ogni volta l' indirizzo IP che è stato assegnato.
Spulciano nell' MSDN ho trovato l' API Win32 NotifyAddrChange che consente la rilevazione di variazioni sugli indirizzi delle varie interfacce di rete: è su questa api che ho costruito tutto l'applicativo

1. NotifyAddrChange

L'api win32 NotifyAddrChange consente di rilevare variazioni agli indirizzi IP delle interfacce di rete presenti. Trattandosi di una procedura bloccante che rimane in attesa dell'evento (ossia la variazione di un indirizzo IP) è opportuno chiamare l'api in questione all'interno di un thread.

1.1 Procedura per rilevare le variazioni sugli indirizzi IP

Si perviene al seguente codice che può essere considerato il kernel del nostro applicativo

type TNotifyIpChangeThread = class(TThread) public procedure Execute; override; end; ... procedure TNotifyIpChangeThread.Execute; var overlap: OVERLAPPED; hand: THandle; ret: DWORD; Closed: Boolean; begin while not Terminated do begin hand := WSACreateEvent(); overlap.hEvent := WSACreateEvent(); ret := NotifyAddrChange(hand, @overlap); if (ret <> NO_ERROR) then begin if (WSAGetLastError() <> 997) then //997 --> WSA_IO_PENDING begin //qui si può segnalare che c'è stato un errore, //ad esempio salvare in un file di log exit; end; end; Closed := False; repeat case WaitForSingleObject(overlap.hEvent, 1000) of WAIT_OBJECT_0 : begin //qui si può chiamare una procedura //creata da noi che va a calcolare gli indirizzi IP //e poi eseguire altre operazione come ad esempio //inviare gli IP via email, etc... Closed := True; end; WAIT_FAILED : RaiseLastWin32Error; end; until (Closed or Terminated); end; end;

di seguito la le dichiarazioni e le definizioni delle funzioni e tipi usati nel codice appena esposto

const WSA_IO_PENDING = 997; type POVERLAPPED = ^OVERLAPPED; OVERLAPPED = record Internal: Cardinal; InternalHigh: Cardinal; Union: record case Integer of 0: ( Offset: Cardinal; OffsetHigh: Cardinal); 1: ( Ptr: Pointer); end; hEvent: Cardinal; end; function NotifyAddrChange( var Handle: Cardinal; overlapped: POVERLAPPED): Cardinal; stdcall; external 'iphlpapi.dll' name 'NotifyAddrChange'; function WSACreateEvent: Cardinal; stdcall; external 'ws2_32.dll' name 'WSACreateEvent'; function WSAGetLastError: Integer; stdcall; external 'ws2_32.dll' name 'WSAGetLastError';

2. Funzione per ottenere l'elenco degli indirizzi IP relativamente a tutte le interfacce di rete

Dopo aver rilevato una variazione negli indirizzi IP è d'obbligo chiamare una funzione che mi restituisca i nuovi indirizzi IP.

//Convert IP address to dotted decimal function IpAddrToString(Addr: Cardinal): string; var inad: in_addr; begin inad.s_addr := Addr; Result := inet_ntoa(inad); //dichiarata nella Unit Winsock end; function ElencoIndirizzi: string; var IpAddrTable: PMIB_IPADDRTABLE; i: integer; Indirizzi: string; NroAdapters: integer; begin IpAddrTable := GetIpAddrTableWithAlloc; Indirizzi := ''; NroAdapters := IpAddrTable^.dwNumEntries; //scrivo l' indirizzo IP di tutte le interfacce di rete for i := 0 to IpAddrTable^.dwNumEntries - 1 do begin Indirizzi := Indirizzi + IpAddrToString(IpAddrTable^.table[i].dwAddr) + #13#10; end; end;

di seguito la le dichiarazioni e le definizioni delle funzioni e tipi usati nel codice appena esposto

type PMIB_IPADDRROW = ^MIB_IPADDRROW; MIB_IPADDRROW = record dwAddr: Cardinal; dwIndex: Cardinal; dwMask: Cardinal; dwBCastAddr: Cardinal; dwReasmSize: Cardinal; unused1: Word; wType: Word; end; PMIB_IPADDRTABLE = ^MIB_IPADDRTABLE; MIB_IPADDRTABLE = record dwNumEntries: Cardinal; table: array [0..0] of MIB_IPADDRROW; end; function GetIpAddrTable( pIpAddrTable: PMIB_IPADDRTABLE; var pdwSize: Cardinal; bOrder: Boolean): Cardinal; stdcall; external 'iphlpapi.dll' name 'GetIpAddrTable';

3. Invio di email

Una volta rilevata una variazione negli indirizzi IP e raccolti i nuovi indirizzi IP, un'ottima idea può essere quella di inviare gli IP ad un indirizzo email. L'implementazione di tale procedura di invio email può essere effettuata molto semplicemente grazie agli Indy Components. Useremo i seguenti 2 componenti appartenenti al pacchetto Indy:

1) TIdMessage: raccoglie tutte le caratteristiche del messaggio (indirizzo destinazione, body, etc...)
2) TIdSMTP: si occupa dell'invio

3.1 Procedura per inviare email

Creiamo un semplice applicativo: sulla nostra Form mettiamo i 2 suddetti componenti e via

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, IdMessage, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdMessageClient, IdSMTP; type TForm1 = class(TForm) SMTP: TIdSMTP; MailMessage: TIdMessage; private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure Invioemail; begin Form1.MailMessage.From.Address := 'indirizzo email from'; Form1.MailMessage.Recipients.EMailAddresses := 'indirizzo email destinazione'; Form1.MailMessage.Subject := 'test invio posta'; Form1.MailMessage.Body.Text := 'testo del messaggio'; //send mail try try Form1.SMTP.Connect(1000); Form1.SMTP.Send(svcIpNotify.MailMessage); except on E:Exception do //StatusMemo.Lines.Insert(0, 'ERROR: ' + E.Message); end; finally if Form1.SMTP.Connected then Form1.SMTP.Disconnect; end; end; end.

4. Creare un servizio che ingloba il tutto

A questo punto, la cosa migliore è creare un servizio in maniera tale che la procedura di rilevazione delle variazioni (che fa capo all'api NotifyAddrChange) sia sempre attiva. Tralascerei l'esposizione del sorgente del servizio e mi soffermerei sulle caratteristiche salienti del servizio stesso.

4.1 Caratteristiche del servizio

L' eseguibile che implementa il servizio si chiama Carlo_ip.exe mentre il nome visualizzato del servizio (la stringa che viene visualizzata nell' elenco dei servizi restituito dall' applet services.msc) è IpNotify. Il nome del servizio (nome della sottochiave della chiave di registro HKLM\System\CurrentControlSet\Services) è svcIpNotify. Bisogna inserire nel codice il "from" ed il "to" relativamente alla email; una volta creato l' eseguibile si procede alla sua installazione tramite

Carlo_ip.exe /INSTALL

A questo punto eseguendo services.msc ci sarà nell' elenco la voce IpNotify. Aprendo il registro ci sarà la chiave HKLM\System\CurrentControlSet\Services\svcIpNotify.
 

5. Conclusione

Tutte le volte che ci si connetterà ad internet (o verrà eseguita una qualsiasi altra modifica ad una qualsiasi interfaccia di rete) verrà inviata una email con l' indirizzo IP di tutte le interfacce di rete e con un soggetto del tipo: "notifica <data ora>"

IPNotify

 

 

 

 

 

 

 

 

 

 

 

 

 

 
 
Your Ad Here