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?

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 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. TODO: rimando al documento che approfondisce il coordinator node.
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 metodo remotable ip_change(oldip, newip)
Si riprende a rispondere al radar e si genera l'evento HOOKED.