FreeBSD, PHP e NGINX

Mi è capitato un VPS basato su FreeBSD, con un server NGINX…..mamma mia che schifo !

FreeBSD sparge i files in maniera praticamente casuale nel filesystem, è quasi impossibile andare a ritrovarli: alcuni script sono in /etc altri in /usr/local/etc altri ancora in /usr/local/libexec .

Per impostare il locale it_IT.UTF-8:

It is recommended that LC_COLLATE be set to C because some programs still require ASCII ordering in order to function correctly.

$ diff -u /usr/src/etc/login.conf /etc/login.conf
--- /usr/src/etc/login.conf     2011-03-10 13:48:59.000000000 -0800
+++ /etc/login.conf     2011-05-08 16:44:01.000000000 -0700
@@ -26,7 +26,7 @@
        :passwd_format=md5:\
        :copyright=/etc/COPYRIGHT:\
        :welcome=/etc/motd:\
-       :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,FTP_PASSIVE_MODE=YES:\
+       :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,FTP_PASSIVE_MODE=YES,LC_COLLATE=C:\
        :path=/sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin ~/bin:\
        :nologin=/var/run/nologin:\
        :cputime=unlimited:\
@@ -44,7 +44,9 @@
        :pseudoterminals=unlimited:\
        :priority=0:\
        :ignoretime@:\
-       :umask=022:
+       :umask=022:\
+       :charset=UTF-8:\
+       :lang=en_US.UTF-8:

$ sudo cap_mkdb /etc/login.conf

NGINX è cervellotico: ho provato a configurare una location al di fuori del server root (cosa che ho sempre fatto con apache) ed è stato impossibile attivare PHP per quella location.

Mai più NGINX e mai più senza Debian

Аглая Ильинична Шиловская e Александра Волкова Николаевна

Шиловская, Аглая Ильинична e Волкова, Александра Николаевна sono le protagoniste del telefilm Кураж

VirtualBox errore cartelle condivise

Con l’ aggiornamento di VirtualBox alla 4.3.10r93012 è nato un problema:
il mount delle directory condivise fallisce con errore sf_read_super_aux err=-22.

Impostando l’ automount e facendo reboot, il mount va a buon fine, ma il mount manuale non funziona ancora, neanche reinstallando VBoxGuestAdditions.

E’ un vecchio bug che si è ripresentato: /sbin/mount.vboxsf è un link sbagliato, infatti

ls -l /sbin/mount.vboxsf
lrwxrwxrwx 1 root root 40 apr 15 11:10 /sbin/mount.vboxsf -> /usr/lib/VBoxGuestAdditions/mount.vboxsf
# ma la destinazione non esiste:
ls/usr/lib/VBoxGuestAdditions/mount.vboxsf
bash: ls/usr/lib/VBoxGuestAdditions/mount.vboxsf: File o directory non esistente
# ricerco la destinazione giusta:
locate mount.vboxsf
/opt/VBoxGuestAdditions-4.3.10/lib/VBoxGuestAdditions/mount.vboxsf
# correggo il link
ln -sf /opt/VBoxGuestAdditions-4.3.10/lib/VBoxGuestAdditions/mount.vboxsf /sbin/mount.vboxsf

In questo modo il mount manuale funziona di nuovo.
Rimane solo un problema: il mount in /etc/fstab fallisce perchè non viene caricato il modulo vboxsf al boot: basta aggiungerlo a /etc/modules

echo vboxsf >> /etc/modules

fonte:
http://lifecs.likai.org/2014/04/virtualbox-shared-folder-linux-notes.html

Xen VGA passthrough – hardware

http://www.altechnative.net/2013/11/25/virtualized-gaming-nvidia-cards-part-3-how-to-modify-a-fermi-based-geforce-into-a-quadro-geforce-gts450gtx470gtx480-to-quadro-200050006000/

The Tesla (2xx/3xx) and Fermi (4xx) series of GPUs can be modified by modifying the BIOS. Earlier cards can also be modified, but the modification is slightly different to what is described in this article. There is no hardware modification required on any of these cards. The modification is performed by modifying what is known as the “straps” that configure the GPU at initialization time. The nouveau project (free open source nvidia driver implementation for Xorg) has reverse engineered and documented some of the straps, including the device ID locations. We can use this to change the device ID the card reports. This causes the driver to enable a different set of features that it wouldn’t normally expose on a gaming grade card, even though the hardware is perfectly capable of it (you are only supposed to have those features if you paid 4-8x more for what is essentially the same (and sometimes even inferior) card by buying a Quadro).

http://www.eevblog.com/forum/chat/hacking-nvidia-cards-into-their-professional-counterparts/
il post originale della modifica NVidia

http://blog.ktz.me/?p=219
esempio di configurazione

Analisi di Twisted Proxy

Flusso dei dati

La classe Proxy non fa altro che ereditare da HTTPChannel ed impostare requestFactory=ProxyRequest:

class Proxy(HTTPChannel):
    requestFactory = ProxyRequest

La classe HTTPChannel è un ricevitore di richieste: in essa viene creata la coda delle richieste, e il callback lineReceived(self, line) viene chiamato ogni volta che viene ricevuta una linea, creando una request se la linea è la “prima ricevuta”, oppure completando una request se è una linea successiva.
Quando tutta la request è stata ricevuta dal client, viene eseguito il metodo allContentReceived(): questo a sua volta chiama il metodo request.requestReceived(command, path, version) della richiesta, il quale vedremo in seguito eseguirà la richiesta.
Quando la richiesta avrà finito, essa chiamerà il metodo requestDone di HTTPChannel: se la connessione del client non è persistente verrà chiusa.

class HTTPChannel(basic.LineReceiver, policies.TimeoutMixin):
    ....
    requestFactory = Request
    ....
    def __init__(self):
        # the request queue
        self.requests = []
        ....
    def lineReceived(self, line):
        if self.__first_line:
        .... # fa qualche pulizia di dati precedenti
            request = self.requestFactory(self, len(self.requests))
            self.requests.append(request)

            self.__first_line = 0
            ....
        elif line == b'':
            ....
            self.allHeadersReceived()
            if self.length == 0:
                self.allContentReceived()
            ....
        elif line[0] in b' \t':
            ....
        else:
            ....
            self.__header = line
    ....
    def allContentReceived(self):
        command = self._command
        path = self._path
        version = self._version
        ....
        req = self.requests[-1] # prende la richiesta e
        req.requestReceived(command, path, version) # chiama il suo metodo
    ....
    def requestDone(self, request):
        """
        Called by first request in queue when it is done.
        """
        if request != self.requests[0]: raise TypeError
        del self.requests[0]
        if self.persistent:
            ....
        else:
            self.transport.loseConnection()

A questo punto bisogna ricordare che Proxy (erede di HTTPChannel) ha la proprietà requestFactory impostata a ProxyRequest.
La classe ProxyRequest eredita da Request e ne implementa il metodo astratto process(), oltre a dichiarare il protocollo da adoperare per eseguire la richiesta:

class ProxyRequest(Request):
    protocols = {'http': ProxyClientFactory}
    ports = {'http': 80}
    ....
    def process(self):
        .... # varie inizializzazioni
        port = self.ports[protocol]
        class_ = self.protocols[protocol]
        s = self.content.read()
        clientFactory = class_(self.method, rest, self.clientproto, headers,
                               s, self)
        self.reactor.connectTCP(host, port, clientFactory)

Nella classe genitrice Request ci sono alcuni metodi adoperati da HTTPChannel:

class Request:
    ....
    def requestReceived(self, command, path, version):
        # inizializzazioni varie
        self.process()
    ....
    def process(self):
        pass
    ....
    def notifyFinish(self):
        self.notifications.append(Deferred())
        return self.notifications[-1]
    def finish(self):
        if self._disconnected:
            raise RuntimeError(
                "Request.finish called on a request after its connection was lost; "
                "use Request.notifyFinish to keep track of this.")
        ....
        self.finished = 1
    def write(self, data):
        if self.finished:
            raise RuntimeError('Request.write called on a request after '
                               'Request.finish was called.')
        if not self.startedWriting: # intanto invia la parte HEAD
            self.startedWriting = 1
            version = self.clientproto
            l = []
            l.append(
                version + b" " +
                intToBytes(self.code) + b" " +
                networkString(self.code_message) + b"\r\n")
            ....
            l.append(b"\r\n")
            self.transport.writeSequence(l)
            ....
           # if this is a "HEAD" request, we shouldn't return any data
            if self.method == b"HEAD":
                self.write = lambda data: None
                return

        self.sentLength = self.sentLength + len(data)
        if data:
            if self.chunked:
                self.transport.writeSequence(toChunk(data))
            else:
                self.transport.write(data)
    ....
    def connectionLost(self, reason):
        """
        There is no longer a connection for this request to respond over.
        Clean up anything which can't be useful anymore.
        """
        self._disconnected = True
        self.channel = None
        if self.content is not None:
            self.content.close()
        for d in self.notifications:
            d.errback(reason)
        self.notifications = []

A questo punto la situazione è la seguente:

  • Proxy(HTTPChannel) riceve la connessione con lineReceived e crea una ProxyRequest(Request), inserendola nella sua coda
  • Quando la request è completa, sempre in lineReceived viene chiamato allContentReceived
  • allContentReceived chiama ProxyRequest.requestReceived
  • requestReceived chiama ProxyRequest.process()
  • ProxyRequest.process() crea un clientFactory e lo connette alla destinazione con self.reactor.connectTCP(host, port, clientFactory)

Si è visto che ProxyRequest.process() istanzia una ProxyClientFactory e la connette al server di destinazione della richiesta, per ricevere la risposta.
La factory esegue la connessione e imposta il transport, poi crea il protocollo ProxyClient che esegue la comunicazione vera e propria con il server.
Quando ProxyClient viene collegato al server, viene chiamato il suo callback connectionMade che invia headers e dati attraverso il transport.
Quando il server risponde, ci sono diversi handlers che ricevono i dati.
In particolare, handleResponseEnd() esegue la “pulizia” finale chiamando ProxyRequest.finish() e chiudendo la connessione con il server.
Attenzione: handleResponseEnd viene chiamato da HTTPClient.connectionLost().

class ProxyClient(HTTPClient):
    _finished = False
    ....
    def connectionMade(self):
        self.sendCommand(self.command, self.rest)
        for header, value in self.headers.items():
            self.sendHeader(header, value)
        self.endHeaders()
        self.transport.write(self.data)
    def handleHeader(self, key, value):
    .... # si può riusare per processare ogni header ricevuto
    def handleResponsePart(self, buffer):
        self.father.write(buffer) # usa il metodo write di Request
    def handleResponseEnd(self):
        if not self._finished:
            self._finished = True
            self.father.finish() # chiama il metodo finish di Request
            self.transport.loseConnection() #chiude la connessione

Gestione delle connessioni

Dal lato browser troviamo Proxy e ProxyRequest.
Proxy eredita da Protocol: il metodo connectionLost() è chiamato quando il browser si disconnette dal proxy, e notifica l’ evento a tutte le ProxyRequests ancora in coda

def connectionLost(self, reason):
    self.setTimeout(None)
    for request in self.requests:
        request.connectionLost(reason)

La ProxyRequest.connectionLost fa le pulizie: imposta _disconnected=True, cancella il puntatore al canale di comunicazione con il client, lancia gli errbacks delle notifiche.

def connectionLost(self, reason):
    self._disconnected = True
    self.channel = None
    if self.content is not None:
        self.content.close()
    for d in self.notifications:
        d.errback(reason)
    self.notifications = []

Dal lato opposto, quello che comunica con il server di destinazione, troviamo ProxyClient, che eredita da HTTPClient.
Se il server chiude la comunicazione, viene eseguito il metodo HTTPClient.connectionLost, che a sua volta chiama handleResponseEnd, implementato da ProxyClient:

def handleResponseEnd(self):
    if not self._finished:
        self._finished = True
        self.father.finish()
        self.transport.loseConnection()

Per controllare questo comportamento, basta imitare ciò che avviene nel codice sorgente:
basta cioè fare un test su self._finished

Due volte handleResponseEnd

ProxyClient riceve i dati e in alcuni casi (non so bene quali) esegue una prima volta handleResponseEnd().
Poi però c’è la disconnessione dal server: HTTPClient.connectionLost() chiama self.handleResponseEnd una seconda volta.