first
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/binary"
|
||||
"encoding/csv"
|
||||
"encoding/pem"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
quic "github.com/AeonDave/mp-quic-go"
|
||||
)
|
||||
|
||||
func generateTLSConfig() *tls.Config {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
template := x509.Certificate{SerialNumber: big.NewInt(1)}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
|
||||
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
||||
|
||||
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{tlsCert},
|
||||
NextProtos: []string{"mpquic-exp"},
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
addr := flag.String("addr", "0.0.0.0:4242", "Address to listen on")
|
||||
maxPaths := flag.Int("maxpaths", 4, "Maximum number of paths")
|
||||
outCSV := flag.String("output", "app_metrics.csv", "Output CSV for application-level metrics")
|
||||
flag.Parse()
|
||||
|
||||
listener, err := quic.ListenAddr(*addr, generateTLSConfig(), &quic.Config{
|
||||
MaxPaths: *maxPaths,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Server listening on %s with max %d paths\n", *addr, *maxPaths)
|
||||
fmt.Printf("Logging app-level metrics to %s\n", *outCSV)
|
||||
|
||||
// Open CSV
|
||||
f, err := os.OpenFile(*outCSV, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to open CSV:", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
writer := csv.NewWriter(f)
|
||||
writer.Write([]string{"sequence_number", "drone_send_time", "ground_recv_time", "latency_ns", "bytes_received"})
|
||||
writer.Flush()
|
||||
|
||||
// Mutex to protect CSV writer if multiple streams are used
|
||||
var mu sync.Mutex
|
||||
|
||||
for {
|
||||
conn, err := listener.Accept(context.Background())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("Client connected:", conn.RemoteAddr())
|
||||
|
||||
go func(conn *quic.Conn) {
|
||||
for {
|
||||
stream, err := conn.AcceptStream(context.Background())
|
||||
if err != nil {
|
||||
fmt.Println("Session error:", err)
|
||||
return
|
||||
}
|
||||
go func(stream *quic.Stream) {
|
||||
header := make([]byte, 4)
|
||||
for {
|
||||
// Read 4-byte length prefix
|
||||
_, err := io.ReadFull(stream, header)
|
||||
if err != nil {
|
||||
fmt.Printf("Stream closed\n")
|
||||
return
|
||||
}
|
||||
|
||||
length := binary.BigEndian.Uint32(header)
|
||||
if length < 20 {
|
||||
fmt.Printf("Warning: Invalid frame length %d\n", length)
|
||||
continue
|
||||
}
|
||||
|
||||
// Read rest of the payload
|
||||
payload := make([]byte, length-4)
|
||||
_, err = io.ReadFull(stream, payload)
|
||||
if err != nil {
|
||||
fmt.Printf("Stream read error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
recvTime := time.Now().UnixNano()
|
||||
|
||||
seqNum := binary.BigEndian.Uint64(payload[0:8])
|
||||
sendTime := binary.BigEndian.Uint64(payload[8:16])
|
||||
latency := recvTime - int64(sendTime)
|
||||
|
||||
mu.Lock()
|
||||
writer.Write([]string{
|
||||
strconv.FormatUint(seqNum, 10),
|
||||
strconv.FormatUint(sendTime, 10),
|
||||
strconv.FormatInt(recvTime, 10),
|
||||
strconv.FormatInt(latency, 10),
|
||||
strconv.FormatUint(uint64(length), 10),
|
||||
})
|
||||
// Periodically flush?
|
||||
if seqNum % 1000 == 0 {
|
||||
writer.Flush()
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}(stream)
|
||||
}
|
||||
}(conn)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user