123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- /*
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
- */
- package main
- import (
- "context"
- "errors"
- "io"
- "net"
- "os"
- "os/signal"
- "syscall"
- "time"
- "idio.link/go/ipc/internal"
- )
- func main() {
- log := internal.NewLogger()
- ctx := context.WithValue(context.Background(), "log", log)
- ctx, cancel := context.WithCancel(ctx)
- log.Level(internal.LogLevelDebug)
- log.Print("establish signal traps")
- go func() {
- c := make(chan os.Signal, 1)
- defer close(c)
- signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
- s := <-c
- log.Print("received %v signal; shutting down", s)
- cancel()
- }()
- log.Print("listen on abstract unix socket idio.link/go/ipc")
- // see `man 7 unix` for the unix sock abstract namespace
- abstract := "\000idio.link/go/ipc"
- addr, err := net.ResolveUnixAddr("unixpacket", abstract)
- if err != nil {
- panic(err)
- }
- listener, err := net.ListenUnix("unixpacket", addr)
- if err != nil {
- panic(err)
- }
- // TODO move to goroutine and supervise with restart
- acceptIPCConnections(ctx, listener)
- log.Print("exiting")
- }
- func acceptIPCConnections(
- ctx context.Context,
- l *net.UnixListener,
- ) {
- log := ctx.Value("log").(*internal.Logger)
- log.Print("accepting connections...") // TODO should info bypass the base msg?
- log.Push("accept ipc connections")
- defer func() {
- if err := l.Close(); err != nil {
- log.Error("failed to close listener: %v", err)
- }
- }()
- for ctx.Err() == nil {
- // TODO move config into server struct
- err :=
- l.SetDeadline(time.Now().Add(100 * time.Millisecond))
- if err != nil {
- log.Error("set accept deadline failed: %v", err)
- continue
- }
- conn, err := l.Accept()
- if err != nil {
- if !errors.Is(err, os.ErrDeadlineExceeded) {
- log.Error("listener accept failed: %+v", err)
- }
- continue
- }
- go handleIPCConnection(ctx, conn)
- }
- return
- }
- func handleIPCConnection(
- ctx context.Context,
- conn net.Conn,
- ) {
- log := ctx.Value("log").(*internal.Logger)
- log.Print("accepted connection; awaiting requests...")
- log = log.Push("handle ipc connection")
- defer func() {
- if err := conn.Close(); err != nil {
- log.Error("handle ipc connection: failed to close connection: %v", err)
- }
- }()
- cpm := internal.NewClientPM()
- buf := make([]byte, 1024)
- for ctx.Err() == nil {
- // TODO move config into server struct
- err := conn.SetDeadline(time.Now().Add(100 * time.Millisecond))
- if err != nil {
- log.Error("set connection deadline failed: %v", err)
- continue
- }
- sdu, err := internal.Receive(conn, buf)
- if errors.Is(err, os.ErrDeadlineExceeded) {
- continue
- }
- if errors.Is(err, io.EOF) {
- continue
- }
- if err != nil {
- log.Error("%v", err)
- continue
- }
- sdu, err = cpm.Event(sdu)
- if err := internal.Send(conn, sdu); err != nil {
- if !errors.Is(err, os.ErrDeadlineExceeded) {
- log.Error("%v", err)
- }
- continue
- }
- }
- }
|