• Kirill Smelkov's avatar
    xnet/lonet: New package to provide TCP network simulated on top of localhost TCP loopback. · fd4f9a4e
    Kirill Smelkov authored
    Lonet is the virtnet network that, contrary to pipenet, could be used
    when there are several OS-level processes involved.
    
    It uses SQLite for its registry and native OS-level TCP over loopback
    for data exchange. There is small text-based connection handshake
    protocol prelude that have to be carried out when a connection is tried
    to be established to host via its subnetwork, but after it data exchange
    goes directly through OS TCP stack.
    
    Lonet documentation follows:
    
    """
    Package lonet provides TCP network simulated on top of localhost TCP loopback.
    
    For testing distributed systems it is sometimes handy to imitate network of
    several TCP hosts. It is also handy that ports allocated on Dial/Listen/Accept on
    that hosts be predictable - that would help tests to verify network events
    against expected sequence. When whole system could be imitated in 1 OS-level
    process, package lab.nexedi.com/kirr/go123/xnet/pipenet serves the task via
    providing TCP-like synchronous in-memory network of net.Pipes. However
    pipenet cannot be used for cases where tested system consists of 2 or more
    OS-level processes. This is where lonet comes into play:
    
    Similarly to pipenet addresses on lonet are host:port pairs and several
    hosts could be created with different names. A host is xnet.Networker and
    so can be worked with similarly to regular TCP network access-point with
    Dial/Listen/Accept. Host's ports allocation is predictable: ports of a host
    are contiguous integer sequence starting from 1 that are all initially free,
    and whenever autobind is requested the first free port of the host will be
    used.
    
    Internally lonet network maintains registry of hosts so that lonet
    addresses could be resolved to OS-level addresses, for example α:1 and β:1
    to 127.0.0.1:4567 and 127.0.0.1:8765, and once lonet connection is
    established it becomes served by OS-level TCP connection over loopback.
    
    Example:
    
    net, err := lonet.Join(ctx, "mynet")
    hα, err := net.NewHost(ctx, "α")
    hβ, err := net.NewHost(ctx, "β")
    
    // starts listening on address "α:10"
    l, err := hα.Listen(":10")
    go func() {
     csrv, err := l.Accept()   // csrv will have LocalAddr "α:1"
    }()
    ccli, err := hβ.Dial(ctx, "α:10") // ccli will be connection between "β:1" - "α:1"
    
    Once again lonet is similar to pipenet, but since it works via OS TCP stack
    it could be handy for testing networked application when there are several
    OS-level processes involved.
    """
    
    """
    Lonet organization
    
    For every lonet network there is a registry with information about hosts
    available on the network, and for each host its OS-level listening address.
    The registry is kept as SQLite database under
    
    /<tmp>/lonet/<network>/registry.db
    
    Whenever host α needs to establish connection to address on host β, it
    queries the registry for β and further talks to β on that address.
    Correspondingly when a host joins the network, it announces itself to the
    registry so that other hosts could see it.
    
    Handshake protocol
    
    After α establishes OS-level connection to β via main β address, it sends
    request to further establish lonet connection on top of that:
    
    > lonet "<network>" dial "<α:portα>" "<β:portβ>"\n
    
    β checks whether portβ is listening, and if yes, accepts the connection on
    corresponding on-β listener with giving feedback to α that connection was
    accepted:
    
    < lonet "<network>" connected "<β:portβ'>"\n
    
    After that connection is considered to be lonet-established and all further
    exchange on it is directly controlled by corresponding lonet-level
    Read/Write on α and β.
    
    If, on the other hand, lonet-level connection cannot be established, β replies:
    
    < lonet "<networkβ>" E "<error>"\n
    
    where <error> could be:
    
    - connection refused if <β:portβ> is not listening
    - network mismatch if β thinks it works on different lonet network than α
    - protocol error if β thinks that α send incorrect dial request
    - ...
    """
    fd4f9a4e
virtnet.go 22.1 KB