Adding first code for new go-based dedicated server.

This commit is contained in:
lotodore
2014-05-30 17:07:43 +02:00
parent 027ba4c2f7
commit 6058345c92
9 changed files with 23953 additions and 315 deletions
+65
View File
@@ -0,0 +1,65 @@
/*****************************************************************************
* PokerTH dedicated server *
* Copyright (C) 2014 Lothar May *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* *
* Additional permission under GNU AGPL version 3 section 7 *
* *
* If you modify this program, or any covered work, by linking or *
* combining it with the OpenSSL project's OpenSSL library (or a *
* modified version of that library), containing parts covered by the *
* terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
* (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
* permission to convey the resulting work. *
* Corresponding Source for a non-source form of such a combination *
* shall include the source code for the parts of OpenSSL used as well *
* as that of the covered work. *
*****************************************************************************/
package gameserver
import (
"log"
"sync/atomic"
)
type Dispatcher struct {
handler PacketHandler
receiver chan SessionPacket
lastSessionId uint32
}
func NewDispatcher(handler PacketHandler) *Dispatcher {
return &Dispatcher{handler, make(chan SessionPacket, RECV_DISPATCHER_NUM_PACKET_BUF), 0}
}
func (d *Dispatcher) GetReceiver() *chan SessionPacket {
return &d.receiver
}
func (d *Dispatcher) GetNextSessionId() uint32 {
return atomic.AddUint32(&d.lastSessionId, 1)
}
func (d *Dispatcher) Run() {
var sessionPacket SessionPacket
for {
select {
case sessionPacket = <-d.receiver:
log.Printf("Packet in dispatcher session %d type %d", sessionPacket.session.id, sessionPacket.packet.GetMessageType())
d.handler.HandlePacket(sessionPacket.session, sessionPacket.packet)
}
}
}
+76
View File
@@ -0,0 +1,76 @@
/*****************************************************************************
* PokerTH dedicated server *
* Copyright (C) 2014 Lothar May *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* *
* Additional permission under GNU AGPL version 3 section 7 *
* *
* If you modify this program, or any covered work, by linking or *
* combining it with the OpenSSL project's OpenSSL library (or a *
* modified version of that library), containing parts covered by the *
* terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
* (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
* permission to convey the resulting work. *
* Corresponding Source for a non-source form of such a combination *
* shall include the source code for the parts of OpenSSL used as well *
* as that of the covered work. *
*****************************************************************************/
package gameserver
import (
"code.google.com/p/goprotobuf/proto"
"container/list"
"log"
"pokerth"
)
type PacketHandler interface {
HandlePacket(session *Session, packet *pokerth.PokerTHMessage)
}
type Lobby struct {
sessions *list.List
}
func NewLobby() *Lobby {
return &Lobby{list.New()}
}
func (l *Lobby) AddSession(session *Session) {
log.Print("New session")
l.sessions.PushBack(session)
announce := &pokerth.PokerTHMessage{
MessageType: pokerth.PokerTHMessage_PokerTHMessageType.Enum(pokerth.PokerTHMessage_Type_AnnounceMessage),
AnnounceMessage: &pokerth.AnnounceMessage{
ProtocolVersion: &pokerth.AnnounceMessage_Version{
MajorVersion: proto.Uint32(NET_VERSION_MAJOR),
MinorVersion: proto.Uint32(NET_VERSION_MINOR),
},
LatestGameVersion: &pokerth.AnnounceMessage_Version{
MajorVersion: proto.Uint32(POKERTH_VERSION_MAJOR),
MinorVersion: proto.Uint32(POKERTH_VERSION_MINOR),
},
LatestBetaRevision: proto.Uint32(0),
ServerType: pokerth.AnnounceMessage_ServerType.Enum(pokerth.AnnounceMessage_serverTypeInternetAuth),
NumPlayersOnServer: proto.Uint32(0),
},
}
session.sender <- announce
}
func (l *Lobby) HandlePacket(session *Session, packet *pokerth.PokerTHMessage) {
log.Print("packet")
}
+103
View File
@@ -0,0 +1,103 @@
/*****************************************************************************
* PokerTH dedicated server *
* Copyright (C) 2014 Lothar May *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* *
* Additional permission under GNU AGPL version 3 section 7 *
* *
* If you modify this program, or any covered work, by linking or *
* combining it with the OpenSSL project's OpenSSL library (or a *
* modified version of that library), containing parts covered by the *
* terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
* (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
* permission to convey the resulting work. *
* Corresponding Source for a non-source form of such a combination *
* shall include the source code for the parts of OpenSSL used as well *
* as that of the covered work. *
*****************************************************************************/
package gameserver
import (
"encoding/binary"
"pokerth"
)
const NET_HEADER_SIZE uint32 = 4
type PacketSerializer interface {
ReadPacket(buf []byte, num uint32) (uint32, *pokerth.PokerTHMessage)
WritePacket(buf []byte, packet *pokerth.PokerTHMessage) uint32
}
func readPacketRaw(buf []byte, num uint32) (uint32, *pokerth.PokerTHMessage) {
packet := &pokerth.PokerTHMessage{}
err := packet.Unmarshal(buf[0:num])
if err != nil {
packet = nil
}
return num, packet
}
func readPacketWithHeader(buf []byte, num uint32) (uint32, *pokerth.PokerTHMessage) {
var bytesScanned uint32 = 0
var packetSize uint32 = 0
packet := &pokerth.PokerTHMessage{}
if num >= NET_HEADER_SIZE {
packetSize = binary.BigEndian.Uint32(buf[0:NET_HEADER_SIZE])
if packetSize <= 0 {
bytesScanned = NET_HEADER_SIZE
} else if num >= NET_HEADER_SIZE+packetSize {
bytesScanned, packet = readPacketRaw(buf[NET_HEADER_SIZE:], NET_HEADER_SIZE+packetSize)
}
}
return bytesScanned, packet
}
func writePacketGeneric(buf []byte, packet *pokerth.PokerTHMessage, headerSize uint32) uint32 {
var bytesWritten uint32 = 0
num, err := packet.MarshalTo(buf[headerSize:])
if err == nil {
if headerSize > 0 {
binary.BigEndian.PutUint32(buf[0:headerSize], uint32(num))
bytesWritten = uint32(num) + headerSize
} else {
bytesWritten = uint32(num)
}
}
return bytesWritten
}
type RawPacketSerializer struct {
}
func (RawPacketSerializer) ReadPacket(buf []byte, num uint32) (uint32, *pokerth.PokerTHMessage) {
return readPacketRaw(buf, num)
}
func (RawPacketSerializer) WritePacket(buf []byte, packet *pokerth.PokerTHMessage) uint32 {
return writePacketGeneric(buf, packet, 0)
}
type HeaderPacketSerializer struct {
}
func (HeaderPacketSerializer) ReadPacket(buf []byte, num uint32) (uint32, *pokerth.PokerTHMessage) {
return readPacketWithHeader(buf, num)
}
func (HeaderPacketSerializer) WritePacket(buf []byte, packet *pokerth.PokerTHMessage) uint32 {
return writePacketGeneric(buf, packet, NET_HEADER_SIZE)
}
+130
View File
@@ -0,0 +1,130 @@
/*****************************************************************************
* PokerTH dedicated server *
* Copyright (C) 2014 Lothar May *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* *
* Additional permission under GNU AGPL version 3 section 7 *
* *
* If you modify this program, or any covered work, by linking or *
* combining it with the OpenSSL project's OpenSSL library (or a *
* modified version of that library), containing parts covered by the *
* terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
* (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
* permission to convey the resulting work. *
* Corresponding Source for a non-source form of such a combination *
* shall include the source code for the parts of OpenSSL used as well *
* as that of the covered work. *
*****************************************************************************/
package gameserver
import (
"log"
"net"
"pokerth"
)
const POKERTH_VERSION_MAJOR = 1
const POKERTH_VERSION_MINOR = 11
const NET_VERSION_MAJOR = 5
const NET_VERSION_MINOR = 1
const MAX_PACKET_SIZE uint32 = 384
const RECV_BUF_SIZE uint32 = 4 * MAX_PACKET_SIZE
const SEND_BUF_SIZE uint32 = 2 * MAX_PACKET_SIZE
const SEND_NUM_PACKET_BUF = 2048
const RECV_DISPATCHER_NUM_PACKET_BUF = 2048
type Session struct {
id uint32
PacketSerializer
Connection net.Conn
sender chan *pokerth.PokerTHMessage
receiver *chan SessionPacket
}
type SessionPacket struct {
session *Session
packet *pokerth.PokerTHMessage
}
func NewSession(id uint32, serializer PacketSerializer, conn net.Conn, receiver *chan SessionPacket) *Session {
return &Session{id, serializer, conn, make(chan *pokerth.PokerTHMessage, SEND_NUM_PACKET_BUF), receiver}
}
func (s *Session) Run() {
// run sender as separate goroutine
go s.handleSend()
s.handleReceive()
}
func (s *Session) handleReceive() {
// close connection on exit
defer s.Connection.Close()
var buf [RECV_BUF_SIZE]byte
var bufPos uint32 = 0
for {
// read upto RECV_BUF_SIZE bytes
num, err := s.Connection.Read(buf[bufPos:])
bufPos += uint32(num)
if err != nil {
log.Printf("Read error: %s\n", err.Error())
return
}
bytesScanned, packet := s.ReadPacket(buf[0:bufPos], bufPos)
if bytesScanned > 0 {
if packet == nil {
log.Print("Invalid packet")
} else {
log.Printf("Packet in: %d\n", packet.GetMessageType())
*s.receiver <- SessionPacket{s, packet}
remainingBytes := bufPos - bytesScanned
if remainingBytes > 0 {
copy(buf[0:], buf[bytesScanned:remainingBytes])
bufPos = remainingBytes
} else {
bufPos = 0
}
}
}
}
}
func (s *Session) handleSend() {
var buf [RECV_BUF_SIZE]byte
var packet *pokerth.PokerTHMessage
for {
select {
case packet = <-s.sender:
packetSize := s.WritePacket(buf[0:RECV_BUF_SIZE], packet)
if packetSize > 0 {
var bufStart uint32 = 0
for bufStart < packetSize {
num, err := s.Connection.Write(buf[bufStart:packetSize])
if err != nil {
log.Printf("Write error: %s\n", err.Error())
return
}
bufStart += uint32(num)
}
log.Printf("Packet out: %d, size: %d\n", packet.GetMessageType(), packetSize)
}
}
}
}
+77
View File
@@ -0,0 +1,77 @@
/*****************************************************************************
* PokerTH dedicated server *
* Copyright (C) 2014 Lothar May *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* *
* Additional permission under GNU AGPL version 3 section 7 *
* *
* If you modify this program, or any covered work, by linking or *
* combining it with the OpenSSL project's OpenSSL library (or a *
* modified version of that library), containing parts covered by the *
* terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
* (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
* permission to convey the resulting work. *
* Corresponding Source for a non-source form of such a combination *
* shall include the source code for the parts of OpenSSL used as well *
* as that of the covered work. *
*****************************************************************************/
package main
import (
"code.google.com/p/go.net/websocket"
"gameserver"
"log"
"net"
"net/http"
)
var lobby *gameserver.Lobby
var dispatcher *gameserver.Dispatcher
func main() {
lobby = gameserver.NewLobby()
dispatcher = gameserver.NewDispatcher(lobby)
go dispatcher.Run()
listener, err := net.Listen("tcp", ":7234")
if err != nil {
log.Fatalf("Listen error: %s", err.Error())
}
go acceptSockets(listener)
server := websocket.Server{Handler: handleWebsocketConn}
http.Handle("/pokerthwebsocket", server)
http.ListenAndServe(":7233", nil)
}
func acceptSockets(listener net.Listener) {
for {
conn, err := listener.Accept()
if err != nil {
log.Fatalf("Accept error: %s\n", err.Error())
}
s := gameserver.NewSession(dispatcher.GetNextSessionId(), gameserver.HeaderPacketSerializer{}, conn, dispatcher.GetReceiver())
lobby.AddSession(s)
go s.Run()
}
}
func handleWebsocketConn(ws *websocket.Conn) {
ws.PayloadType = websocket.BinaryFrame
s := gameserver.NewSession(dispatcher.GetNextSessionId(), gameserver.RawPacketSerializer{}, ws, dispatcher.GetReceiver())
lobby.AddSession(s)
s.Run()
}
File diff suppressed because it is too large Load Diff