Skip to content

Instantly share code, notes, and snippets.

@filinvadim
Created October 24, 2018 21:09
Show Gist options
  • Save filinvadim/cbdea1c46e6f30195a2cb03254b8c6ae to your computer and use it in GitHub Desktop.
Save filinvadim/cbdea1c46e6f30195a2cb03254b8c6ae to your computer and use it in GitHub Desktop.

Revisions

  1. Vadim Filin created this gist Oct 24, 2018.
    101 changes: 101 additions & 0 deletions epoll
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,101 @@

    func serve() {
    ep, err := netpoll.EpollCreate(epollConfig())
    if err != nil {
    log.Fatal(err)
    }

    // Create listener on port 4444.
    ln, err := listen(4444)
    if err != nil {
    log.Fatal(err)
    }
    defer unix.Close(ln)
    done := make(chan struct{})

    var received bytes.Buffer
    // Add listener fd to epoll instance to know when there are new incoming
    // connections.
    ep.Add(ln, netpoll.EPOLLIN, func(evt netpoll.EpollEvent) {
    if evt&_EPOLLCLOSED != 0 {
    return
    }

    // Accept new incoming connection.
    nfd, _, err := unix.Accept(ln)
    if err != nil {
    log.Fatalf("could not accept: %s", err)
    }

    // Socket must not block read() from it.
    unix.SetNonblock(nfd, true)

    // Add connection fd to epoll instance to get notifications about
    // available data.
    ep.Add(
    nfd,
    netpoll.EPOLLIN|netpoll.EPOLLET|netpoll.EPOLLHUP|netpoll.EPOLLRDHUP,
    func(evt netpoll.EpollEvent,
    ) {
    // If EPOLLRDHUP is supported, it will be triggered after conn
    // close() or shutdown(). In older versions EPOLLHUP is triggered.
    if evt&_EPOLLCLOSED != 0 {
    return
    }

    var buf [128]byte

    for {
    n, err := unix.Read(nfd, buf[:])
    if err != nil {
    break
    }
    if n <= 0 {
    break
    }
    received.Write(buf[:n])
    }
    bIo := bufio.NewReader(bytes.NewReader(received.Bytes()))
    req, err := http.ReadRequest(bIo)
    fmt.Println(req, err, "!!!!!!!!!")
    received.Reset()
    })
    })
    <- done
    if err = ep.Close(); err != nil {
    log.Fatal(err)
    }
    }


    func listen(port int) (ln int, err error) {
    fmt.Println("start server")
    ln, err = unix.Socket(unix.AF_INET, unix.O_NONBLOCK|unix.SOCK_STREAM, 0)
    if err != nil {
    return
    }

    // Need for avoid receiving EADDRINUSE error.
    // Closed listener could be in TIME_WAIT state some time.
    unix.SetsockoptInt(ln, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)

    addr := &unix.SockaddrInet4{
    Port: port,
    Addr: [4]byte{0x7f, 0, 0, 1}, // 127.0.0.1
    }

    if err = unix.Bind(ln, addr); err != nil {
    return
    }
    err = unix.Listen(ln, 4)

    return
    }

    func epollConfig() *netpoll.EpollConfig {
    return &netpoll.EpollConfig{
    OnWaitError: func(err error) {
    log.Fatal(err)
    },
    }
    }