= La microfunc hook =
La microfunc '''hook''' implementa la prima parte del meccanismo "''communicating vessels''" descritto nel documento topology.pdf.
I parametri che riceve, sono:
<
>
{{{ (neigh_list=[], forbidden_neighs=[], condition=False, gnumb=0)}}}
=== Quando viene richiamata? ===
* Viene richiamata una prima volta all'avvio del demone (vedi [[../NtkNodeStartup|fase di startup]]) solo per attivare le interfacce di rete. Di seguito, sempre nella fase di startup dopo aver eseguito una prima scansione della LAN con il radar, viene richiamata una seconda volta per fare il primo hook. Infatti un nodo appena avviato è subito un "''hooking node''". In queste chiamate non viene passato nessun argomento.
* Viene richiamata come gestore dell'evento {{{NET_COLLISION}}}. Questo evento viene generato dalla classe {{{Etp}}} quando, durante l'esecuzione di un ETP ricevuto, si rileva una collisione di due reti disgiunte. In questo caso l'elenco neigh_list di vicini da esaminare è passato nell'evento ed è l'elenco dei nodi appartenenti all'altra rete. Infatti siamo nella rete più piccola e dobbiamo fare noi ''hook'' nella altra rete.
* Viene richiamata nel [[../ElencoRemotableFunctions|metodo remotable]] [[../CommunicatingVessels|communicating_vessels]]. Il metodo {{{communicating_vessels}}} può essere stato richiamato da remoto o da un evento {{{ETP_EXECUTED}}} locale. In ogni caso questo metodo eseguito localmente fa i suoi calcoli e poi richiama eventualmente hook, indicando i nodi con più spazi liberi del nostro e con gnumb=il numero di nodi liberi nel miglior candidato.
=== Cosa fa? ===
Si memorizza il proprio nip attuale in {{{oldnip}}}.
<
>
Deve scoprire se è solo. Per ora imposta {{{we_are_alone = False}}}.
Ricorda che la {{{maproute.free_nodes_list(lvl)}}} restituisce una lista dei posti liberi di livello {{{lvl}}}, tipo ad esempio [1, 2, 56, 57, 123, 124, 125, 200]
<
>
La funzione {{{highest_free_nodes()}}} restituisce una tupla {{{(lvl, free_nodes_list)}}} per il più alto livello in cui {{{self.maproute.free_nodes_list(lvl)}}} non è vuoto.
<
>
Quindi una cosa tipo (3, [1, 2, 56, 57, 123, 124, 125, 200])
Si inizia a preparare '''hfn''' che conterrà una lista di coppie (nip, highestfreenodes) partendo dal proprio attuale nip.
<
>
Quindi tipo [([44,33,22,11], (3, [1, 2, 56, 57, 123, 124, 125, 200])), ...]
<
>
Cioè
<
>
'''hfn''' = [ ( nip, ( lvl, [ id, id, id, ...] ) ), ( nip2, ( lvl2, [ id2, id2, id2, ...] ) ), ... ]
<
>
Per ora contiene il '''proprio''' nip e il livello più alto in cui la '''propria''' mappa ha qualche free_node
Se è stato specificato quali neighbour prendere in esame (caso collisione di due reti disgiunte) guarda solo quelli, sennò recupera tutti i neighbour conosciuti col metodo {{{neigh_list}}} della classe {{{Neighbour}}}.
<
>
Qui vediamo se siamo soli e valoriziamo {{{we_are_alone}}}.
Viene definita una funzione {{{is_neigh_forbidden}}}, per vedere se un neigh è incluso nell'elenco vietato {{{forbidden_neighs}}}.
Ogni neighbour passa al vaglio di {{{is_neigh_forbidden}}}. Inoltre ci si assicura di esaminare solo neighbour esterni. Per vedere se è del nostro stesso gnodo di livello 1 usiamo il metodo {{{nip_cmp}}} della classe {{{Map}}}, che restituirebbe 0.
<
>
Se passa queste verifiche si richiama su questo neighbour il [[../ElencoRemotableFunctions|metodo remotable]] {{{highest_free_nodes}}} e si aggiunge {{{nip}}} e lista nella '''hfn'''.
Dalla '''hfn''' cosi ottenuta si tolgono i livelli più bassi. Dall'elenco rimasto si prende la prima tupla con più nodi liberi, di questa il primo id di nodo libero.
<
>
Il caso estremo di "''{{{Netsukuku is full}}}''" viene rilevato qui.
<
>
Si genera il nuovo nip {{{newnip}}}, appartenente al (g)nodo libero trovato.
<
>
Se {{{we_are_alone}}} si genera anche un nuovo {{{netid}}}.
In questa fase abbiamo bisogno dell'aiuto del '''coordinator node'''. Vedi il [[../ModuloCoord|modulo coord]].
<
>
Se stiamo creando un nodo di livello 0 ed è stata richiesta la verifica della condizione perché stiamo uscendo da un altro gnodo (tipo {{{|G'| < |G| and gnumb < |G|}}}) questa viene eseguita con l'uso del coordinator node e i metodi {{{going_out}}}, {{{going_in}}} che restituisce il nuovo IP convalidato, {{{going_out_ok}}} che conferma l'uscita.
<
>
Se stiamo creando un gnodo di livello più alto questa condizione non serve. '''''TODO''': capire perché.'' - Va comunque richiesto il permesso al coordinator node di livello superiore (a meno che {{{we_are_alone}}}) con il metodo {{{going_in}}} che restituisce il nuovo IP convalidato.
<
>
Se stiamo creando un gnodo di ultimo livello non viene fatto nessun controllo.
<
>
'''''TODO''': A me pare che sia necessario anche in questo caso venire coadiuvati da un coordinator node globale. Ci sono controindicazioni a implementare un coordinator node a livello globale?''
Per completare la fase di ''hook'', si smette di rispondere ai {{{radar.reply}}}.
<
>
Si attiva il {{{newnip}}} nelle proprie interfacce di rete.
<
>
Si cambia il nip in {{{me}}} della mappa e si resettano i vari livelli della mappa.
<
>
Si esegue il metodo di {{{Neighbour}}} {{{readvertise()}}}.
<
>
Si avvertono i nostri vicini chiamando il loro [[../ElencoRemotableFunctions|metodo remotable]] {{{ip_change(oldip, newip)}}}
<
>
Si riprende a rispondere al radar e si genera l'evento {{{HOOKED}}}.