-
Notifications
You must be signed in to change notification settings - Fork 0
/
conn_writing.go
117 lines (98 loc) · 3.55 KB
/
conn_writing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package bngsocket
import (
"encoding/binary"
"fmt"
)
// writeBytesIntoSocketConn sendet die gegebenen Daten in 1024-Byte-Chunks über die Socket-Verbindung des BngConn-Objekts.
// Die Funktion teilt die Daten in kleinere Teile auf, sendet jeden Chunk mit dem Typ 'M' (Message) und wartet auf eine ACK-Bestätigung.
// Nach dem Senden aller Chunks wird ein EndTransfer ('E') gesendet und erneut auf eine ACK-Bestätigung gewartet.
//
// Parameter:
// - o *BngConn: Ein Zeiger auf das BngConn-Objekt, das die Socket-Verbindung verwaltet.
// - data []byte: Die zu sendenden Daten.
//
// Rückgabe:
// - error: Ein Fehler, falls beim Senden der Daten ein Problem aufgetreten ist, ansonsten nil.
func writeBytesIntoSocketConn(o *BngConn, data []byte) error {
const chunkSize = 1024 // Maximale Größe eines Chunks in Bytes
// Gesamtlänge der Daten
totalLength := len(data)
_DebugPrint(fmt.Sprintf("BngConn(%s): Sending %d bytes in %d-byte chunks", o._innerhid, totalLength, chunkSize))
// Aufteilen und Senden der Daten
for start := 0; start < totalLength; start += chunkSize {
end := start + chunkSize
if end > totalLength {
end = totalLength // Der letzte Chunk hat möglicherweise weniger als 1024 Bytes
}
chunk := data[start:end]
// Kritischer Abschnitt: Sperre den Mutex
o.connMutex.Lock()
defer o.connMutex.Unlock()
// Schreibe den Typ 'M' (Message)
if err := o.writer.WriteByte('M'); err != nil {
errmsg := fmt.Errorf("%w: %v", ErrWriteMessageType, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
// Schreibe die Länge des Chunks (Big-Endian)
chunkLength := uint32(len(chunk))
if err := binary.Write(o.writer, binary.BigEndian, chunkLength); err != nil {
errmsg := fmt.Errorf("%w: %v", ErrWriteChunkLength, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
// Schreibe den Chunk selbst
bytesToWrite := len(chunk)
for bytesWritten := 0; bytesWritten < bytesToWrite; {
n, err := o.writer.Write(chunk[bytesWritten:])
if err != nil {
errmsg := fmt.Errorf("%w: %v", ErrWriteChunk, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
bytesWritten += n
if n == 0 {
errmsg := fmt.Errorf("%w: no further bytes written, connection may be broken", ErrWriteChunk)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
}
// Flush die Daten
if err := o.writer.Flush(); err != nil {
errmsg := fmt.Errorf("%w: %v", ErrFlushWriter, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
_DebugPrint(fmt.Sprintf("BngConn(%s): Chunk [%d:%d] sent", o._innerhid, start, end))
// Mutex freigeben, bevor auf ACK gewartet wird
o.connMutex.Unlock()
defer o.connMutex.Lock()
// Warte auf ACK
if err := o.ackHandle.WaitOfACK(); err != nil {
errmsg := fmt.Errorf("%w for chunk [%d:%d]: %v", ErrWaitForACK, start, end, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
}
// Senden von EndTransfer (ET)
o.connMutex.Lock()
defer o.connMutex.Unlock()
if err := o.writer.WriteByte('E'); err != nil {
errmsg := fmt.Errorf("%w: %v", ErrWriteEndTransfer, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
if err := o.writer.Flush(); err != nil {
errmsg := fmt.Errorf("%w after ET: %v", ErrFlushWriter, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
_DebugPrint(fmt.Sprintf("BngConn(%s): ET sent", o._innerhid))
// Warten auf ACK für ET
if err := o.ackHandle.WaitOfACK(); err != nil {
errmsg := fmt.Errorf("%w after ET: %v", ErrWaitForACK, err)
writeProcessErrorHandling(o, errmsg)
return errmsg
}
return nil
}