aim-oscar-server/main.go
2021-12-16 18:37:27 -05:00

158 lines
3.5 KiB
Go

package main
import (
"aim-oscar/models"
"context"
"database/sql"
"fmt"
"io"
"log"
"net"
"os"
"os/signal"
"syscall"
"github.com/pkg/errors"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dbfixture"
"github.com/uptrace/bun/dialect/sqlitedialect"
"github.com/uptrace/bun/driver/sqliteshim"
"github.com/uptrace/bun/extra/bundebug"
)
const (
SRV_HOST = ""
SRV_PORT = "5190"
SRV_ADDRESS = SRV_HOST + ":" + SRV_PORT
)
var services = make(map[uint16]Service)
func init() {
services[0x17] = &AuthorizationRegistrationService{}
}
func main() {
// Set up the DB
sqldb, err := sql.Open(sqliteshim.ShimName, "file::memory:?cache=shared")
if err != nil {
panic(err)
}
db := bun.NewDB(sqldb, sqlitedialect.New())
// Print all queries to stdout.
db.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))
db.RegisterModel((*models.User)(nil))
fixture := dbfixture.New(db, dbfixture.WithRecreateTables())
err = fixture.Load(context.Background(), os.DirFS("models"), "fixtures.yml")
if err != nil {
panic(err)
}
listener, err := net.Listen("tcp", SRV_ADDRESS)
if err != nil {
fmt.Println("Error listening: ", err.Error())
os.Exit(1)
}
defer listener.Close()
exitChan := make(chan os.Signal, 1)
signal.Notify(exitChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGABRT)
go func() {
<-exitChan
fmt.Println("Shutting down")
os.Exit(1)
}()
fmt.Println("OSCAR listening on " + SRV_ADDRESS)
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting connection: ", err.Error())
os.Exit(1)
}
session := NewSession(conn)
log.Printf("Connection from %v", conn.RemoteAddr())
go handleTCPConnection(db, session, conn)
}
}
func handleTCPConnection(db *bun.DB, session *Session, conn net.Conn) {
// defer (func() {
// if err := recover(); err != nil {
// log.Printf("Error handling message: %+v\n", err.(error))
// }
// conn.Close()
// log.Printf("Closed connection to %v", conn.RemoteAddr())
// })()
buf := make([]byte, 1024)
for {
if !session.GreetedClient {
// send a hello
hello := NewFLAP(1)
hello.Data.Write([]byte{0, 0, 0, 1})
err := session.Send(hello)
panicIfError(err)
session.GreetedClient = true
}
n, err := conn.Read(buf)
if err != nil && err != io.EOF {
log.Println("Read Error: ", err.Error())
return
}
if n == 0 {
return
}
// Try to parse all of the FLAPs in the buffer if we have enough bytes to
// fill a FLAP header
for len(buf) >= 6 && buf[0] == 0x2a {
dataLength := Word(buf[4:6])
flapLength := int(dataLength) + 6
if len(buf) < flapLength {
log.Printf("not enough data, only %d bytes\n", len(buf))
break
}
flap := &FLAP{}
if err := flap.UnmarshalBinary(buf[:flapLength]); err != nil {
panicIfError(errors.Wrap(err, "could not unmarshal FLAP"))
}
buf = buf[flapLength:]
fmt.Printf("%v ->\n%+v\n", conn.RemoteAddr(), flap)
handleMessage(db, session, flap)
}
}
}
func handleMessage(db *bun.DB, session *Session, flap *FLAP) {
if flap.Header.Channel == 1 {
} else if flap.Header.Channel == 2 {
snac := &SNAC{}
err := snac.UnmarshalBinary(flap.Data.Bytes())
panicIfError(err)
fmt.Printf("%+v\n", snac)
if tlvs, err := UnmarshalTLVs(snac.Data.Bytes()); err == nil {
for _, tlv := range tlvs {
fmt.Printf("%+v\n", tlv)
}
} else {
fmt.Printf("%s\n\n", prettyBytes(snac.Data.Bytes()))
}
if service, ok := services[snac.Header.Family]; ok {
err = service.HandleSNAC(db, session, snac)
panicIfError(err)
}
}
}