This repository has been archived on 2022-06-29. You can view files and clone it, but cannot push or open issues or pull requests.
urtrator/requester/requester_object.go

186 lines
6.0 KiB
Go

// URTrator - Urban Terror server browser and game launcher, written in
// Go.
//
// Copyright (c) 2016-2020, Stanslav N. a.k.a pztrn (or p0z1tr0n) and
// URTrator contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package requester
import (
// stdlib
"bytes"
"errors"
"fmt"
"net"
"strconv"
"strings"
"time"
)
type Requester struct {
// Pooler.
Pooler *Pooler
// Packet prefix.
pp string
// Showstopper for delimiting IP addresses.
// As we are receiving bytes, we will put bytes representation of "\"
// character.
ip_delimiter int
}
// Requester's initialization.
func (r *Requester) Initialize() {
fmt.Println("Initializing Requester...")
r.pp = "\377\377\377\377"
r.ip_delimiter = 92
r.Pooler = &Pooler{}
r.Pooler.Initialize()
}
// Gets all available servers from master server.
// This isn't in pooler, because it have no need to be pooled.
func (r *Requester) getServers() error {
// Get master server address and port from configuration.
var master_server string = ""
var master_server_port string = ""
master_server_raw, ok := Cfg.Cfg["/servers_updating/master_server"]
if ok {
master_server = strings.Split(master_server_raw, ":")[0]
master_server_port = strings.Split(master_server_raw, ":")[1]
} else {
master_server = "master.urbanterror.info"
master_server_port = "27900"
}
fmt.Println("Using master server address: " + master_server + ":" + master_server_port)
// IP addresses we will compose to return.
conn, err1 := net.Dial("udp", master_server+":"+master_server_port)
if err1 != nil {
fmt.Println("Error dialing to master server!")
Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "Failed to connect to master server!"})
return errors.New("Failed to connect to master server!")
}
defer conn.Close()
// Set deadline, so we won't wait forever.
ddl := time.Now()
// This should be enough. Maybe, you should'n run URTrator on modem
// connections? :)
ddl = ddl.Add(time.Second * 2)
conn.SetDeadline(ddl)
fmt.Println("Master server connection deadline set: " + ddl.String())
// Request.
// 68 - protocol version for 4.3
// 70 - protocol version for 4.2.x
msg := []byte(r.pp + "getservers 68 full empty")
conn.Write(msg)
// UDP Buffer.
var received_buf []byte = make([]byte, 4096)
// Received buffer.
var raw_received []byte
// Received IP addresses.
//var received []string
fmt.Println("Receiving servers list...")
for {
_, err := conn.Read(received_buf)
raw_received = append(raw_received, received_buf...)
fmt.Println("Received " + strconv.Itoa(len(raw_received)) + " bytes")
if err != nil {
// A bit hacky - if we have received data length lower or
// equal to 4k - we have an error. Looks like conn.Read()
// reads by 4k.
if len(raw_received) < 4097 {
fmt.Println("Error dialing to master server!")
Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "Failed to connect to master server!"})
return errors.New("Failed to connect to master server!")
}
break
}
}
// Obtaining list of slices.
var raw_received_slices [][]byte = bytes.Split(raw_received, []byte("\\"))
// Every ip-port pair contains:
// 1. IP as first 4 bytes
// 2. Port as last 2 bytes.
// Every package is a 7-bytes sequence, which starts with "\"
// (code 92), which we used before to obtain list of slices.
for _, slice := range raw_received_slices {
// We need only 6-bytes slices. All other aren't represent
// server's address.
if len(slice) != 6 {
continue
}
// Generate IP.
ip := strconv.Itoa(int(slice[0])) + "." + strconv.Itoa(int(slice[1])) + "." + strconv.Itoa(int(slice[2])) + "." + strconv.Itoa(int(slice[3]))
// Generate port from last two bytes.
// This is a very shitty thing. Don't do this in real world.
// Maybe bitshifting will help here, but I can't get it to work :(
// Get first byte as integer and multiply it on 256 and summing with
// second byte.
p1 := int(slice[4]) * 256
port := strconv.Itoa(p1 + int(slice[5]))
addr := ip + ":" + port
// Check if we already have this server added previously. If so - do nothing.
_, ok := Cache.Servers[addr]
if !ok {
// Create cached server.
Cache.CreateServer(addr)
Cache.ServersMutex.Lock()
Cache.Servers[addr].Server.Ip = ip
Cache.Servers[addr].Server.Port = port
Cache.ServersMutex.Unlock()
}
}
return nil
}
// Updates information about all available servers from master server and
// parses it to usable format.
func (r *Requester) UpdateAllServers(task bool) {
fmt.Println("Starting all servers updating procedure...")
err := r.getServers()
if err != nil {
return
}
r.Pooler.UpdateServers("all")
if task {
Eventer.LaunchEvent("taskDone", map[string]string{"task_name": "Server's autoupdating"})
}
}
func (r *Requester) UpdateFavoriteServers() {
fmt.Println("Updating favorites servers...")
r.Pooler.UpdateServers("favorites")
}
func (r *Requester) UpdateOneServer(server_address string) {
fmt.Println("Updating server " + server_address)
r.Pooler.UpdateOneServer(server_address)
}