main 
 |
 +- NatFork
 |  |
 |  +- RotatingStream
 |  |  |
 |  |  +- RotatingStreambuf
 |  |
 |  +- setupStdMsg
 |     |
 |     +- RotatingStream::open
 |        |
 |        +- RotatingStreambuf::open
 |           |
 |           +- rotateThread (thread, once)
 |              |
 |              +- rotate
 |
 +- natfork.run()
    |
    +--- parentProcess
    |
    +--- childProcess
         |
         +---+ (1 of 3)
         |   |
         |   +- ConntrackProducer
         |   |  |
         |   |  +- signalHandler
         |   |
         |   +- DevicesProducer
         |   |
         |   +- TcpdumpProducer
         |  
         +--- Producer::process (thread)
         |    |
         |    +---+ (1 of 3)
         |    |   |
         |    |   +- ConntrackProducer.run
         |    |   |  |
         |    |   |  +- childProcess: execs 'conntrack'
         |    |   |  |
         |    |   |  +- parentProcess
         |    |   |     |
         |    |   |     +- process pushes ConntrackRecord on the storage
         |    |   |
         |    |   +- DevicesProducer.run
         |    |   |  |  
         |    |   |  +- PcapFilter (thread)
         |    |   |  |  |
         |    |   |  |  +- operator()
         |    |   |  |  |  |
         |    |   |  |  |  +- Pcap d_pcap.loop
         |    |   |  |  |   
         |    |   |  |  +- callback pushes PcapRecord on the storage
         |    |   |  |
         |    |   |  +- PcapFilter out
         |    |   |     |
         |    |   |     +- operator() (same, see above)
         |    |   |
         |    |   +- TcpdumpProducer.run
         |    |      |
         |    |      +- get
         |    |      |
         |    |      +- process
         |    |         |
         |    |         +- store pushes TcpdumpRecord on the storage
         |    |      
         |    +- storage.setEmpty
         |
         +- ConnectionsConsumer
         |  |
         |  +- RotatingStream
         |  |  |
         |  |  +- RotatingStreambuf
         |  |
         |  +- RotatingStream::open
         |     |
         |     +- RotatingStreambuf::open
         |        |
         |        +- rotateThread (thread, once)
         |           |
         |           +- rotate
         |
         +- ConnectionsConsumer.run
            |
            +- cleanupWrap (thread)
            |  |
            |  +- cleanupICMP_UDP
            |     |
            |     +- cleanup("icmp")
            |     |  |
            |     |  +- logICMP 
            |     |     |
            |     |     +-logICMPdata
            |     |
            |     +- cleanup("udp")
            |        |
            |        +- logTCP_UDP
            |           |
            |           +-logTCP_UDPdata
            +---+
            |   |
            |   +- icmp
            |   |  |
            |   |  +- icmpInDev
            |   |  |  |
            |   |  |  +- icmpSent 
            |   |  |  |
            |   |  |  +- icmpReceived
            |   |  |
            |   |  +- icmpOutDev
            |   |  |
            |   |  +- icmpDestroy
            |   |     |
            |   |     +- logICMP 
            |   |        |
            |   |        logICMPdata
            |   |
            |   +- udp
            |   |  |
            |   |  +- udpInDev
            |   |  |  |
            |   |  |  +- udpSent 
            |   |  |  |
            |   |  |  +- udpReceived
            |   |  |
            |   |  +- udpOutDev
            |   |  |  |
            |   |  |  +- newKey
            |   |  |
            |   |  +- tcp_udpDestroy
            |   |     |
            |   |     +- logTCP_UDP
            |   |        |
            |   |        logTCP_UDPdata
            |   |
            |   +- tcp
            |      |
            |      +- tcpInDev
            |      |  |
            |      |  +- tcpInType
            |      |  |
            |      |  +- tcpSyn
            |      |  |
            |      |  +- tcpSent
            |      |  |
            |      |  +- tcpReceived
            |      |  |
            |      |  +- tcpFin
            |      |  |  |
            |      |  |  +- logTCP_UDP
            |      |  |     |
            |      |  |     logTCP_UDPdata
            |      |  |
            |      |  +- ignoreRecord
            |      |  |
            |      |  +- logTCP_UDP
            |      |     |
            |      |     logTCP_UDPdata
            |      |
            |      +- tcpOutDev
            |      |  |
            |      |  +- newKey
            |      |
            |      +- tcp_udpDestroy
            |         |
            |         +- logTCP_UDP
            |            |
            |            logTCP_UDPdata
            |
            +- cleanupICMP_UDP
            |   |
            |   +- cleanup("icmp")
            |   |  |
            |   |  +- logICMP 
            |   |     |
            |   |     +-logICMPdata
            |   |
            |   +- cleanup("udp")
            |      |
            |      +- logTCP_UDP
            |         |
            |         +-logTCP_UDPdata
            |
            +- cleanup("tcp")
               |
               +- logTCP_UDP
                  |
                  logTCP_UDPdata

===================================================================

main -> natfork.run()

NatFork:

    childProcess
        mode CONNTRACK: ConntrackProducer object
                                installs signal handler for signals 
                                2 (SIGINT) and 15 (SIGTERM)

                    signalHandler: 
                        kills conntrack process
                        d_signalled = true

            thread: Producer::process calls one of:

                ConntrackProducer.run -> forks (repeatedly, with a limit)
                ---------------------
                    childProcess: execs 'conntrack'
                            throws 0 on failure, ending main,
                            thus ending parentProcess:

                    parentProcess:
                        loop:
                            process(line) from childProcess
                                pushes ConntrackRecord
                                       ===============

                        storage.setEmpty()
                        not d_signaled: 'terminated' msg

                    data.cc - definitions of regular expressions
                        (FBB::Pattern objects) matching TCP/UDP or ICMP
                        packets. 

                DevicesProducer.run
                -------------------
                    detach anonymous PcapFilter thread reading the
                        1st (incoming, pre-NAT) device 
                    PcapFilter out reading the 2nd (outgoing,
                        post-NAT) device

                    out(), ends at signal 2 or 15

                    storage.setEmpty()

                    out not signaled: 'terminated' msg


                        PcapFilter: 
                            Pcap d_pcap
                                wraps C pcap_ function calls.

                            operator()() - explicitly called or thread
                                d_pcap.loop: receives
                                    this as void *
                                    callback as pcap_handler. 

                            callback: pushes PcapRecord
                                             ==========

                        
                TcpdumpProducer.run
                -------------------
                    opens 1st (incoming, pre-NAT) tcpdump saved file 
                      and 2nd (outgoing, post-NAT) tcpdump saved file

                    gets 1st packets from both

                    calls process():
                        calls store() for all packets sorted by time
                            store: pushes TcpdumpRecord
                                          =============
                        storage.setEmpty


        ConnectionsConsumer.run()
            thread: cleanupWrap

            loop:
                storage.wait(), break if empty
                fetch Record
                notify producer

                handle protocol data:
                    icmp():
                        IN, NEW: d_icmp += record (key is record's ID)
                                 update addresses, sent/received
                        DESTROY: icmpDestroy():
                                    logICMP(), 
                                    d_icmp -= record
                    udp():
                        IN: udpIn()
                                d_udp += record (key: setTCPUDPkey)
                                d_id[record.id()] = key
                                update sent/received
                        OUT: udpOut()
                                record.id test
                                or: set IP, d_id -= ID
                        NEW: d_udp += record
                        DESTROY: tcp_udpDestroy() - cf. icmpDestroy

                    tcp():
                        IN: tcpIn()
                                d_tcp += record (key: setTCPTCPkey)
                                d_sequence[record.id()] = key
                                update sent/received
                        OUT: tcpOut()
                                SYN flag test
                                or: set IP, d_sequence -= ID
                        NEW: d_tcp += record
                        DESTROY: tcp_udpDestroy()

            cleanupICMP_UDP, cleanup(tcp)
