108 lines
2.6 KiB
Go
108 lines
2.6 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
kademlia "gitlab.lrz.de/netintum/teaching/p2psec_projects_2024/DHT-6/pkg"
|
||
|
"io"
|
||
|
"log"
|
||
|
"net"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
// Server configuration and message type identifiers
|
||
|
|
||
|
type APIServer struct {
|
||
|
dht *kademlia.DHT
|
||
|
}
|
||
|
|
||
|
func initializeAPIServer(config *kademlia.Config, dht *kademlia.DHT) {
|
||
|
server := APIServer{}
|
||
|
server.dht = dht
|
||
|
listener, err := net.Listen("tcp", config.APIAddress+":"+strconv.Itoa(int(config.APIPort)))
|
||
|
if err != nil {
|
||
|
log.Fatalln("[API Server] Error starting server: ", err)
|
||
|
}
|
||
|
defer listener.Close()
|
||
|
|
||
|
for {
|
||
|
connection, err := listener.Accept()
|
||
|
if err != nil {
|
||
|
log.Println("[API Server] Error accepting connection: ", err)
|
||
|
continue
|
||
|
}
|
||
|
// Handle in seperate thread
|
||
|
go server.handleAPIRequest(connection)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *APIServer) handleAPIRequest(connection net.Conn) {
|
||
|
|
||
|
buf := make([]byte, 4)
|
||
|
_, err := connection.Read(buf)
|
||
|
if err != nil {
|
||
|
log.Println("[API Server] Error reading message: ", err)
|
||
|
return
|
||
|
}
|
||
|
defer connection.Close()
|
||
|
|
||
|
size := binary.BigEndian.Uint16(buf[:2])
|
||
|
messageType := binary.BigEndian.Uint16(buf[2:])
|
||
|
|
||
|
// Subtract 4 bytes used for size and message type
|
||
|
messageBody := make([]byte, size-4)
|
||
|
io.ReadFull(connection, messageBody)
|
||
|
|
||
|
// Combine body and head to get the full message again
|
||
|
message := append(buf, messageBody...)
|
||
|
|
||
|
switch messageType {
|
||
|
case kademlia.PUT:
|
||
|
s.handlePut(message, connection)
|
||
|
case kademlia.GET:
|
||
|
s.handleGet(message, connection)
|
||
|
default:
|
||
|
log.Println("[API Server] Invalid message type")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *APIServer) handlePut(data []byte, connection net.Conn) {
|
||
|
packet, err := kademlia.ParsePutPacket(data)
|
||
|
if err != nil {
|
||
|
log.Printf("[API Server] Error receiving PUT request: %v", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Store the value in the network
|
||
|
s.dht.Store(packet.Key, packet.Value, packet.TTL, uint16(packet.Replication))
|
||
|
}
|
||
|
|
||
|
func (s *APIServer) handleGet(data []byte, connection net.Conn) {
|
||
|
packet, err := kademlia.ParseGetPacket(data)
|
||
|
if err != nil {
|
||
|
log.Printf("[API Server] Error receiving GET request: %v", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Query the network for the value
|
||
|
val, exists := s.dht.Get(packet.Key)
|
||
|
|
||
|
if exists {
|
||
|
response := kademlia.DHTSuccessPacket{
|
||
|
Key: packet.Key,
|
||
|
Value: val,
|
||
|
}
|
||
|
_, err := connection.Write(kademlia.SerialiseSuccessPacket(response))
|
||
|
if err != nil {
|
||
|
log.Println("[API Server] Error sending GET response: ", err)
|
||
|
return
|
||
|
}
|
||
|
} else {
|
||
|
response := kademlia.DHTFailurePacket{Key: packet.Key}
|
||
|
_, err := connection.Write(kademlia.SerialiseFailurePacket(response))
|
||
|
if err != nil {
|
||
|
log.Println("[API Server] Error sending GET response: ", err)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|