func (u *User) SendMessage(from string, msg string) { buf := make([]byte, len(from)+len(msg)+4) b := buf buf, err := proto.WriteString(buf, from) buf, err = proto.WriteString(buf, msg) pkt := proto.NewPacket(13, b) pkt.Sign(u.Privkey) _, err = u.Conn.Write(pkt.Bytes()) if err != nil { u.Kicked = true u.Conn.Close() return } }
func (u *User) refreshBoard() { if u.Game == nil { return } var placed, color uint64 for i := 0; i < 8; i++ { for j := 0; j < 8; j++ { this := uint((i << 3) | j) if u.Game.Board[i][j] != 0 { placed |= uint64(1) << this if u.Game.Board[i][j] == 2 { color |= uint64(1) << this } } } } black := "[Empty]" white := "[Empty]" if u.Game.Black != nil { black = u.Game.Black.Name } if u.Game.White != nil { white = u.Game.White.Name } buf := make([]byte, 16384) binary.BigEndian.PutUint64(buf, placed) binary.BigEndian.PutUint64(buf[8:], color) buf[16] = byte(u.Game.Turn) b := buf[17:] b, _ = proto.WriteString(b, white) b, _ = proto.WriteString(b, black) length := 16384 - len(b) pkt := proto.NewPacket(12, buf[:length]) pkt.Sign(u.Privkey) _, err := u.Conn.Write(pkt.Bytes()) if err != nil { u.Kicked = true u.Conn.Close() return } }
func (u *User) Kick(reason string) { u.Leave() u.Kicked = true buf := make([]byte, len(reason)+2) b := buf buf, _ = proto.WriteString(buf, reason) pkt := proto.NewPacket(5, b) pkt.Sign(u.Privkey) u.Conn.Write(pkt.Bytes()) u.Conn.Close() }
func upstream() { buff := make([]byte, 16384) for { line, err := rl.Readline() if err == readline.ErrInterrupt { line = "exit" } if err == io.EOF { continue } line = strings.TrimSpace(line) switch { case strings.HasPrefix(line, "login "): // arg1 => username args, err := sw.Parse(line) if err != nil { fmt.Fprintln(stderr, "Invalid line:", err.Error()) continue } args = args[1:] if len(args) == 0 { fmt.Fprintf(stderr, "Usage: login username\n") continue } if len(args) == 1 { proto.WriteString(buff, args[0]) pkt := proto.NewPacket(4, buff[:len(args[0])+2]) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } } case strings.HasPrefix(line, "exit"): // arg1 => reason reason := "Disconnected" args, err := sw.Parse(line) if err != nil { fmt.Fprintln(stderr, "Invalid line:", err.Error()) continue } if len(args) >= 2 { reason = args[1] } proto.WriteString(buff, reason) pkt := proto.NewPacket(5, buff[:len(reason)+2]) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } time.Sleep(500 * time.Millisecond) os.Exit(0) case line == "games": pkt := proto.NewPacket(6, []byte{}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } case line == "players": pkt := proto.NewPacket(7, []byte{}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } case strings.HasPrefix(line, "join "): // arg1 => roomid args, err := sw.Parse(line) if err != nil { fmt.Fprintln(stderr, "Invalid line:", err.Error()) continue } args = args[1:] if len(args) == 0 { fmt.Fprintf(stderr, "Usage: join roomid\n") continue } if len(args) == 1 { r, err := strconv.Atoi(args[0]) if err != nil { fmt.Fprintf(stderr, "Invalid roomid %s\n", args[0]) } roomid := uint16(r) binary.BigEndian.PutUint16(buff, roomid) pkt := proto.NewPacket(8, buff[:2]) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } } case line == "leave": pkt := proto.NewPacket(9, []byte{}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") return } case line == "restart": pkt := proto.NewPacket(10, []byte{}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } case strings.HasPrefix(line, "place "): args, err := sw.Parse(line) if err != nil { fmt.Fprintln(stderr, "Invalid line:", err.Error()) continue } args = args[1:] if len(args) < 2 { fmt.Fprintf(stderr, "Usage: place x y\n") continue } // arg1 => x, arg2 => y x, err := strconv.Atoi(args[0]) if err != nil { fmt.Fprintf(stderr, "Invalid number %s\n", args[0]) } y, err := strconv.Atoi(args[1]) if err != nil { fmt.Fprintf(stderr, "Invalid number %s\n", args[1]) } buff[0] = byte((x << 4) | y) pkt := proto.NewPacket(11, buff[:1]) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } case strings.HasPrefix(line, "msg "): args, err := sw.Parse(line) if err != nil { fmt.Fprintln(stderr, "Invalid line:", err.Error()) continue } args = args[1:] if len(args) < 2 { fmt.Fprintf(stderr, "Usage: msg player message\n") continue } b := buff b, _ = proto.WriteString(b, args[0]) b, _ = proto.WriteString(b, args[1]) pkt := proto.NewPacket(13, buff[:len(args[0])+len(args[1])+4]) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error()) panic("Socket error!") } default: fmt.Fprintln(stderr, "Commands: ") fmt.Fprint(stderr, completer.Tree(" ")) } } }
func client(conn net.Conn, id int) { user := new(common.User) user.Conn = conn user.Pubkey = pubkey user.Privkey = privkey pkt, err := proto.ReadPacket(user.Conn) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error()) user.Conn.Close() return } if pkt.Frametype != 0 || len(pkt.Payload) != 64 { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } user.RPubKey = new([ed25519.PublicKeySize]byte) copy(user.RPubKey[:], pkt.Payload[:32]) if !pkt.Validate(user.RPubKey) { fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id) user.Conn.Close() return } // Client key & challenge payload := make([]byte, 96) copy(payload, pubkey[:]) copy(payload[32:], pkt.Payload[32:]) challenge := make([]byte, 32) _, err = rand.Read(challenge) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] !!WARNING!!, random pool error: %s, using empty challenge string!\n", id, err.Error()) } copy(payload[64:], challenge) pkt = proto.NewPacket(1, payload) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } // Server validation pkt, err = proto.ReadPacket(user.Conn) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error()) user.Conn.Close() return } if !pkt.Validate(user.RPubKey) { fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id) user.Conn.Close() return } if pkt.Frametype != 2 || len(pkt.Payload) != 32 { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } if !bytes.Equal(pkt.Payload, challenge) { fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid challenge data!\n", id) user.Conn.Close() return } pkt = proto.NewPacket(3, []byte{}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } // Login for { pkt, err = proto.ReadPacket(user.Conn) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error()) user.Conn.Close() return } if !pkt.Validate(user.RPubKey) { fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id) user.Conn.Close() return } if pkt.Frametype != 4 { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } username, _, err := proto.ReadString(pkt.Payload) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } if _, ok := users[username]; !ok { // Username ok fmt.Fprintf(rl.Stderr(), "[Conn %d] User %s logged in, from %s\n", id, username, user.Conn.RemoteAddr().String()) pkt = proto.NewPacket(4, []byte{0}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } users[username] = user user.Name = username defer func(name string) { users[name].Kick(""); delete(users, name) }(username) // Delete on leave break } pkt = proto.NewPacket(4, []byte{1}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } } for !user.Kicked { pkt, err := proto.ReadPacket(user.Conn) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error()) user.Conn.Close() return } if !pkt.Validate(user.RPubKey) { fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id) user.Conn.Close() return } buf := make([]byte, 16384) switch pkt.Frametype { case 5: // Quit packet reason, _, err := proto.ReadString(pkt.Payload) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } fmt.Fprintf(rl.Stderr(), "[Conn %d] Client Quit: %s\n", id, reason) user.Conn.Close() return case 6: // Roomlist request b := buf for rid, room := range games { if room == nil { continue } usera := "" if room.Black != nil { usera = room.Black.Name } userb := "" if room.White != nil { userb = room.White.Name } binary.BigEndian.PutUint16(b, rid) b = b[2:] b, _ = proto.WriteString(b, usera) b, _ = proto.WriteString(b, userb) } length := 16384 - len(b) b = buf[:length] pkt = proto.NewPacket(6, b) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } case 7: // Player list request b := buf for username := range users { b, _ = proto.WriteString(b, username) } length := 16384 - len(b) b = buf[:length] pkt = proto.NewPacket(7, b) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } case 8: if len(pkt.Payload) != 2 { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } jrid := binary.BigEndian.Uint16(pkt.Payload) room := games[jrid] result := user.Join(room) pkt = proto.NewPacket(8, []byte{result}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } case 9: user.Leave() pkt = proto.NewPacket(9, []byte{}) pkt.Sign(privkey) _, err = user.Conn.Write(pkt.Bytes()) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error()) user.Conn.Close() return } case 10: user.Restart() if user.Game.Black != nil { user.Game.Black.SendMessage("", fmt.Sprintf("%s is now ready.", user.Name)) } if user.Game.White != nil { user.Game.White.SendMessage("", fmt.Sprintf("%s is now ready.", user.Name)) } case 11: if len(pkt.Payload) != 1 { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } xy := uint8(pkt.Payload[0]) x := xy >> 4 y := xy & 15 if user.Game.Black == user { if !user.Game.Place(x, y, 1) { user.SendMessage("", "Invalid operation") } } else { if !user.Game.Place(x, y, 2) { user.SendMessage("", "Invalid operation") } } case 13: p := pkt.Payload dest, p, err := proto.ReadString(p) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } msg, p, err := proto.ReadString(p) if err != nil { fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype) user.Conn.Close() return } if dest != "" { u, ok := users[dest] if !ok { user.SendMessage("", "No such user.") } else { go u.SendMessage(user.Name, msg) } } } } }