func NewMaster() *Master { address, err := net.ResolveTCPAddr("tcp", config.CORE_HOST+":"+strconv.Itoa(config.CORE_PORT)) if err != nil { utils.Print("Master: Error resolving TCP address:", err) return nil } l, err := net.ListenTCP("tcp", address) if err != nil { utils.Print("Master: Error listening to the TCP address:", err) return nil } master := &Master{ address: address, listener: l, quit: make(chan int), newConnections: make(chan *net.TCPConn), deadConnections: make(chan *net.TCPConn), validConnections: make(map[*net.TCPConn]bool), messages: make(chan *Packet), Services: []*Service{}, ServiceById: make(map[uint8]*Service), SubscriptionMap: NewSubscriptionMap(), commandInterpreter: NewCommandInterpreter(), packetReader: nil, LastPacketId: make(map[uint8]uint), } master.packetReader = NewPacketReader(master) return master }
func (s *Service) Write(packet *Packet) { if !s.master.IsValidConnection(s.Connection) { return } if config.DEBUG { utils.Debug(s.Connection.LocalAddr(), "->", s.Connection.RemoteAddr(), "Len:", packet.ContentLength, "Packet:", packet) } else { utils.Print(s.Connection.LocalAddr(), "->", s.Connection.RemoteAddr(), "Len:", packet.ContentLength) } _, err := s.Connection.Write(packet.Prepare()) if err != nil { netOpError, ok := err.(*net.OpError) if err == io.EOF || err.Error()[0:11] == "WSARecv tcp" || (ok && (netOpError.Err.Error() == "use of closed network connection" || netOpError.Err.Error() == "read: connection reset by peer")) { s.master.RemoveValidConnection(s.Connection) } } }
func (r *PacketReader) Listen(conn *net.TCPConn) { for _, connection := range r.connections { if connection == conn { utils.Debug("PacketReader: Already listening on Connection", conn, ". Skipped enabling another listener.") return } } r.connections = append(r.connections, conn) utils.Debug("PacketReader: Now listening on Connection:", conn) r.recovering[conn] = []byte{} defer conn.Close() LoopListen: for r.master.IsValidConnection(conn) { select { case <-r.quit: utils.Debug("PacketReader: LoopListen stopped. (Quit)", conn) break LoopListen default: if len(r.recovering[conn]) > 0 { r.Recover(conn) if !r.master.IsValidConnection(conn) { utils.Debug("PacketReader: LoopListen stopped. (Recovering failed)", conn) r.master.deadConnections <- conn break LoopListen } } else { packet, err := r.Read(conn) if err != nil { netOpError, ok := err.(*net.OpError) if err == io.EOF || err.Error()[0:11] == "WSARecv tcp" || (ok && netOpError.Err.Error() == "read: connection reset by peer") { r.master.SetValidConnection(conn, false) r.master.deadConnections <- conn utils.Debug("PacketReader: LoopListen stopped. (Client disconnected)", conn) break LoopListen } if ok && netOpError.Err.Error() == "use of closed network connection" { r.master.SetValidConnection(conn, false) r.master.deadConnections <- conn utils.Debug("PacketReader: LoopListen stopped. (Lost Connection)", conn) break LoopListen } utils.Debug("PacketReader: Error reading a packet for Connection", conn, ":", err) continue } if config.DEBUG { utils.Debug(conn.RemoteAddr(), "->", conn.LocalAddr(), "Len:", packet.ContentLength, "Packet:", packet) } else { utils.Print(conn.RemoteAddr(), "->", conn.LocalAddr(), "Len:", packet.ContentLength) } r.master.NewMessage(packet) } } } for index, connection := range r.connections { if connection == conn { r.connections = append(r.connections[:index], r.connections[index+1:]...) break } } delete(r.recovering, conn) utils.Debug("PacketReader stopped listening on Connection:", conn) }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) if config.LOG { logDirectory := config.LOGDIR if len(config.LOGDIR) > 0 && config.LOGDIR[len(config.LOGDIR)-1] != '/' { logDirectory = logDirectory + "/" } f, err := os.OpenFile(logDirectory+"log_"+time.Now().Format("02-01-2006_15-04")+".txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatalf("error opening file: %v", err) } defer f.Close() log.SetOutput(f) } var serviceId uint8 = 1 serviceName := "ServiceTestName" tunnelHost := "core.craftolution.de" tunnelService := 1 tunnelPort := 8123 p := core.ConstructPacket(nil, serviceId, core.PACKETTYPE_CONNECT, 1, []byte{}) p.AppendContent(utils.UintToByte(uint(len(serviceName)), 1)) p.AppendContent([]byte(serviceName)) p.AppendContent(utils.UintToByte(uint(len(tunnelHost)), 1)) p.AppendContent([]byte(tunnelHost)) p.AppendContent(utils.UintToByte(uint(tunnelService), 1)) p.AppendContent(utils.UintToByte(uint(tunnelPort), 2)) p.Prepare() master := core.NewMaster() if master == nil { return } var cmds []commands.Command = []commands.Command{} cmds = append(cmds, commands.NewConnectCommand(master)) cmds = append(cmds, commands.NewDisconnectCommand(master)) cmds = append(cmds, commands.NewSubscribeCommand(master)) cmds = append(cmds, commands.NewUnsubscribeCommand(master)) cmds = append(cmds, commands.NewListServicesCommand(master)) cmds = append(cmds, commands.NewAskTunnelCommand(master)) cmds = append(cmds, commands.NewSyncTimeCommand(master)) cmds = append(cmds, commands.NewNothingCommand(master)) clients := []*net.TCPConn{} go func() { if !config.RUN_TEST { return } utils.Print("Running test, program will quit automatically when the test is finished. (ETA: 1 min)") address, err := net.ResolveTCPAddr("tcp", config.CORE_HOST+":"+strconv.Itoa(config.CORE_PORT)) if err != nil { utils.Print(err) } time.Sleep(time.Duration(3) * time.Second) for i := 0; i < 100; i++ { conn, err := net.DialTCP("tcp", nil, address) if err != nil { utils.Print(err) continue } serviceName := "Service " + strconv.Itoa(i) connectPacket := core.ConstructPacket(nil, uint8(i), core.PACKETTYPE_CONNECT, 1, []byte{}) connectPacket.AppendContent(utils.UintToByte(uint(len(serviceName)), 1)) connectPacket.AppendContent([]byte(serviceName)) connectPacket.AppendContent(utils.UintToByte(uint(len(tunnelHost)), 1)) connectPacket.AppendContent([]byte(tunnelHost)) connectPacket.AppendContent(utils.UintToByte(uint(tunnelService), 1)) connectPacket.AppendContent(utils.UintToByte(uint(tunnelPort), 2)) conn.Write(connectPacket.Prepare()) clients = append(clients, conn) time.Sleep(time.Duration(10) * time.Millisecond) listServicesPacket := core.ConstructPacket(nil, uint8(i), core.PACKETTYPE_LIST_SERVICES, 2, []byte{}) conn.Write(listServicesPacket.Prepare()) time.Sleep(time.Duration(10) * time.Millisecond) } time.Sleep(time.Duration(3) * time.Second) for i := 0; i < 100; i++ { conn := clients[i] disconnectPacket := core.ConstructPacket(nil, uint8(i), core.PACKETTYPE_DISCONNECT, 3, []byte{}) conn.Write(disconnectPacket.Prepare()) time.Sleep(time.Duration(10) * time.Millisecond) } time.Sleep(time.Duration(3) * time.Second) for i := 0; i < 100; i++ { clients[i].Close() time.Sleep(time.Duration(10) * time.Millisecond) } time.Sleep(time.Duration(3) * time.Second) clients := []*net.TCPConn{} for i := 1; i < 5; i++ { conn, err := net.DialTCP("tcp", nil, address) if err != nil { utils.Print(err) continue } serviceName := "Service " + strconv.Itoa(i) connectPacket := core.ConstructPacket(nil, uint8(i), core.PACKETTYPE_CONNECT, 1, []byte{}) connectPacket.AppendContent(utils.UintToByte(uint(len(serviceName)), 1)) connectPacket.AppendContent([]byte(serviceName)) connectPacket.AppendContent(utils.UintToByte(uint(len(tunnelHost)), 1)) connectPacket.AppendContent([]byte(tunnelHost)) connectPacket.AppendContent(utils.UintToByte(uint(4), 1)) connectPacket.AppendContent(utils.UintToByte(uint(1234), 2)) connectPacket.AppendContent(utils.UintToByte(uint(2), 1)) connectPacket.AppendContent(utils.UintToByte(uint(1235), 2)) conn.Write(connectPacket.Prepare()) clients = append(clients, conn) time.Sleep(time.Duration(10) * time.Millisecond) askTunnelPacket := core.ConstructPacket(nil, uint8(i), core.PACKETTYPE_ASK_TUNNEL, 2, []byte{}) askTunnelPacket.AppendContent(utils.UintToByte(1, 1)) askTunnelPacket.AppendContent(utils.UintToByte(2, 1)) askTunnelPacket.AppendContent(utils.UintToByte(3, 1)) askTunnelPacket.AppendContent(utils.UintToByte(4, 1)) conn.Write(askTunnelPacket.Prepare()) time.Sleep(time.Duration(10) * time.Millisecond) } time.Sleep(time.Duration(3) * time.Second) subscribePacket := core.ConstructPacket(nil, uint8(1), core.PACKETTYPE_SUBSCRIBE, 3, []byte{}) subscribePacket.AppendContent(utils.UintToByte(14, 1)) clients[0].Write(subscribePacket.Prepare()) subscribePacket.ServiceId = uint8(4) subscribePacket.AppendContent(utils.UintToByte(1, 1)) subscribePacket.AppendContent(utils.UintToByte(11, 1)) clients[3].Write(subscribePacket.Prepare()) time.Sleep(time.Duration(3) * time.Second) dataPacket := core.ConstructPacket(nil, uint8(2), uint8(13), 3, []byte{}) dataPacket.AppendContent([]byte{8, 3, 7}) for i := 10; i < 15; i++ { dataPacket.Next() dataPacket.PacketType = uint8(i) clients[1].Write(dataPacket.Prepare()) time.Sleep(time.Duration(10) * time.Millisecond) } time.Sleep(time.Duration(3) * time.Second) disconnectPacket := core.ConstructPacket(nil, uint8(3), core.PACKETTYPE_DISCONNECT, 4, []byte{}) clients[2].Write(disconnectPacket.Prepare()) // no disconnect packets for other clients, test master functionality... time.Sleep(time.Duration(3) * time.Second) for i := 0; i < 4; i++ { clients[i].Close() time.Sleep(time.Duration(10) * time.Millisecond) } time.Sleep(time.Duration(3) * time.Second) master.Quit() }() master.Listen() }
func (master *Master) Listen() { utils.Debug("Master: Now listening for TCP connections.") running := true // fetch new tcp connections parallel go func() { LoopConnector: for running { select { case <-master.quit: running = false break LoopConnector default: conn, err := master.listener.AcceptTCP() if err != nil { if err == io.EOF || err.Error()[0:11] != "WSARecv tcp" { running = false break LoopConnector } netOpError, ok := err.(*net.OpError) if ok && (netOpError.Err.Error() == "use of closed network connection" || netOpError.Err.Error() == "read: connection reset by peer") { running = false break LoopConnector } utils.Debug("Master: Error accepting new TCP connection:", err) continue } master.newConnections <- conn } } utils.Debug("Master: LoopConnector stopped.") }() LoopWorker: for running { select { case <-master.quit: utils.Debug("Master: LoopWorker stopped.") break LoopWorker case conn := <-master.newConnections: master.AddValidConnection(conn) go master.packetReader.Listen(conn) case conn := <-master.deadConnections: master.RemoveValidConnection(conn) services := master.Services for _, service := range services { if service.Connection == conn { master.DisconnectService(service) } } case message := <-master.messages: if !message.IsData() { service := master.ServiceById[message.ServiceId] err := master.GetCommandInterpreter().Handle(message, service) if err != nil { utils.Debug("Master WARN: CommandInterpreter couldn't handle packet:", err) } } subscribers := master.SubscriptionMap.GetServicesForPacketType(message.PacketType) for _, service := range subscribers { service.Write(message) } } } utils.Print("Master stopped.") }