Skip to content
This repository has been archived by the owner on Oct 20, 2024. It is now read-only.

Commit

Permalink
feat: Parses IE's centrally (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
gruyaume authored Dec 23, 2023
1 parent 749322b commit 290b9e1
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 50 deletions.
42 changes: 42 additions & 0 deletions ie/ie.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
package ie

import (
"encoding/binary"
"fmt"
)

type InformationElement interface {
Serialize() []byte
}

func ParseInformationElements(b []byte) ([]InformationElement, error) {
var ies []InformationElement

index := 0

for index < len(b) {
if len(b[index:]) < 4 {
return nil, fmt.Errorf("not enough bytes for IE header")
}

ieType := int(binary.BigEndian.Uint16(b[index : index+2]))
ieLength := int(binary.BigEndian.Uint16(b[index+2 : index+4]))
index += 4 // Move past the header

if len(b[index:]) < ieLength {
return nil, fmt.Errorf("not enough bytes for IE data, expected %d, got %d", ieLength, len(b[index:]))
}

ieValue := b[index : index+ieLength]
var ie InformationElement
switch ieType {
case 96:
ie = DeserializeRecoveryTimeStamp(ieType, ieLength, ieValue)
default:
return nil, fmt.Errorf("unknown IE type %d", ieType)
}

if ie != nil {
ies = append(ies, ie)
}

index += ieLength
}

return ies, nil
}
41 changes: 41 additions & 0 deletions ie/nodeId.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ie

import (
"bytes"
"encoding/binary"
)

type NodeID struct {
Type uint16
Length uint16
NodeIDType int
NodeIDValue []byte
}

func NewNodeID(nodeIDType int, nodeIDValue []byte) NodeID {
return NodeID{
Type: 60,
Length: uint16(len(nodeIDValue) + 1),
NodeIDType: nodeIDType,
NodeIDValue: nodeIDValue,
}
}

func (n NodeID) Serialize() []byte {
buf := new(bytes.Buffer)

// Octets 1 to 2: Type (60)
binary.Write(buf, binary.BigEndian, uint16(n.Type))

// Octets 3 to 4: Length
binary.Write(buf, binary.BigEndian, uint16(n.Length))

// Octet 5: Spare (4 bits) + Node ID Type (4 bits)
spareAndType := byte(n.NodeIDType & 0x0F) // Ensure NodeIDType is only 4 bits
buf.WriteByte(spareAndType)

// Octets 6 to n+5: Node ID Value
buf.Write(n.NodeIDValue)

return buf.Bytes()
}
10 changes: 5 additions & 5 deletions ie/recoveryTimeStamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type RecoveryTimeStamp struct {
func NewRecoveryTimeStamp(value time.Time) RecoveryTimeStamp {
return RecoveryTimeStamp{
Type: 96,
Length: 8,
Length: 4,
Value: value.Unix() + ntpEpochOffset,
}
}
Expand All @@ -29,10 +29,10 @@ func (rt RecoveryTimeStamp) Serialize() []byte {
return bytes
}

func Deserialize(b []byte) RecoveryTimeStamp {
func DeserializeRecoveryTimeStamp(ieType int, ieLength int, ieValue []byte) RecoveryTimeStamp {
return RecoveryTimeStamp{
Type: int(binary.BigEndian.Uint16(b[0:2])),
Length: int(binary.BigEndian.Uint16(b[2:4])),
Value: int64(binary.BigEndian.Uint32(b[4:8])),
Type: ieType,
Length: ieLength,
Value: int64(binary.BigEndian.Uint32(ieValue)),
}
}
5 changes: 2 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/dot-5g/pfcp/client"
"github.com/dot-5g/pfcp/ie"
"github.com/dot-5g/pfcp/messages"
"github.com/dot-5g/pfcp/server"
)

Expand All @@ -28,10 +27,10 @@ func RunServer() {
pfcpServer.Run()
}

func HandleHeartbeatRequest(h *messages.HeartbeatRequest) {
func HandleHeartbeatRequest(sequenceNumber uint32, recoveryTimeStamp ie.RecoveryTimeStamp) {

}

func HandleHeartbeatResponse(h *messages.HeartbeatResponse) {
func HandleHeartbeatResponse(sequenceNumber uint32, recoveryTimeStamp ie.RecoveryTimeStamp) {

}
14 changes: 6 additions & 8 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/dot-5g/pfcp/client"
"github.com/dot-5g/pfcp/ie"
"github.com/dot-5g/pfcp/messages"
"github.com/dot-5g/pfcp/server"
)

Expand All @@ -25,20 +24,19 @@ var (
heartbeatResponseReceivedSequenceNumber uint32
)

func HandleHeartbeatRequest(h *messages.HeartbeatRequest) {
func HandleHeartbeatRequest(sequenceNumber uint32, recoveryTimeStamp ie.RecoveryTimeStamp) {
heartbeatRequestMu.Lock()
defer heartbeatRequestMu.Unlock()
heartbeatRequesthandlerCalled = true
heartbeatRequestreceivedRecoveryTimestamp = h.RecoveryTimeStamp
heartbeatRequestReceivedSequenceNumber = h.SequenceNumber
heartbeatRequestreceivedRecoveryTimestamp = recoveryTimeStamp
heartbeatRequestReceivedSequenceNumber = sequenceNumber
}

func HandleHeartbeatResponse(h *messages.HeartbeatResponse) {
func HandleHeartbeatResponse(sequenceNumber uint32, recoveryTimeStamp ie.RecoveryTimeStamp) {
heartbeatResponseMu.Lock()
defer heartbeatResponseMu.Unlock()
heartbeatResponsehandlerCalled = true
heartbeatResponsereceivedRecoveryTimestamp = h.RecoveryTimeStamp
heartbeatResponseReceivedSequenceNumber = h.SequenceNumber
heartbeatResponsereceivedRecoveryTimestamp = recoveryTimeStamp
heartbeatResponseReceivedSequenceNumber = sequenceNumber
}

func TestServer(t *testing.T) {
Expand Down
67 changes: 33 additions & 34 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,10 @@ const (
HeartbeatResponseType byte = 2
)

type HandleHeartbeatRequest func(*messages.HeartbeatRequest)
type HandleHeartbeatResponse func(*messages.HeartbeatResponse)
type MessageHandler func(*PfcpMessage)

type PfcpMessage struct {
Header messages.PFCPHeader
Message []byte
}
// Define a new handler type that specifically accepts RecoveryTimeStampIE
type HandleHeartbeatRequest func(sequenceNumber uint32, recoveryTimeStampIE ie.RecoveryTimeStamp)
type HandleHeartbeatResponse func(sequenceNumber uint32, recoveryTimeStampIE ie.RecoveryTimeStamp)
type MessageHandler func(header messages.PFCPHeader, ies []ie.InformationElement)

type Server struct {
address string
Expand All @@ -50,47 +46,50 @@ func (server *Server) Close() {
}

func (server *Server) HeartbeatRequest(handler HandleHeartbeatRequest) {
server.registerHandler(HeartbeatRequestType, func(msg *PfcpMessage) {
server.handleHeartbeatRequest(msg, handler)
server.registerHandler(HeartbeatRequestType, func(header messages.PFCPHeader, ies []ie.InformationElement) {
var recoveryTimeStamp ie.RecoveryTimeStamp
for _, elem := range ies {
if tsIE, ok := elem.(ie.RecoveryTimeStamp); ok {
recoveryTimeStamp = tsIE
break
}
}

handler(header.SequenceNumber, recoveryTimeStamp)
})
}

func (server *Server) HeartbeatResponse(handler HandleHeartbeatResponse) {
server.registerHandler(HeartbeatResponseType, func(msg *PfcpMessage) {
server.handleHeartbeatResponse(msg, handler)
server.registerHandler(HeartbeatResponseType, func(header messages.PFCPHeader, ies []ie.InformationElement) {
var recoveryTimeStamp ie.RecoveryTimeStamp
for _, elem := range ies {
if tsIE, ok := elem.(ie.RecoveryTimeStamp); ok {
recoveryTimeStamp = tsIE
break
}
}

handler(header.SequenceNumber, recoveryTimeStamp)
})
}

func (server *Server) handleUDPMessage(data []byte, addr net.Addr) {
header, err := messages.ParsePFCPHeader(data[:HeaderSize])
if err != nil {
log.Printf("Error parsing PFCP header: %v", err)
return
}
pfcpMessage := PfcpMessage{Header: header, Message: data[HeaderSize:]}

if genericHandler, exists := server.messageHandlers[pfcpMessage.Header.MessageType]; exists {
genericHandler(&pfcpMessage)
} else {
log.Printf("No handler registered for message type %d", pfcpMessage.Header.MessageType)
}
}

func (server *Server) handleHeartbeatRequest(msg *PfcpMessage, handler HandleHeartbeatRequest) {
recoveryTimeStamp := ie.Deserialize(msg.Message)
heartbeatRequest := messages.HeartbeatRequest{
RecoveryTimeStamp: recoveryTimeStamp,
SequenceNumber: msg.Header.SequenceNumber,
ies, err := ie.ParseInformationElements(data[HeaderSize:])
if err != nil {
log.Printf("Error parsing Information Elements: %v", err)
return
}
handler(&heartbeatRequest)
}

func (server *Server) handleHeartbeatResponse(msg *PfcpMessage, handler HandleHeartbeatResponse) {
recoveryTimeStamp := ie.Deserialize(msg.Message)
heartbeatResponse := messages.HeartbeatResponse{
RecoveryTimeStamp: recoveryTimeStamp,
SequenceNumber: msg.Header.SequenceNumber,
if handler, exists := server.messageHandlers[header.MessageType]; exists {
handler(header, ies)
} else {
log.Printf("No handler registered for message type %d", header.MessageType)
}
handler(&heartbeatResponse)
}

func (server *Server) registerHandler(messageType byte, handler MessageHandler) {
Expand Down

0 comments on commit 290b9e1

Please sign in to comment.