2 // Copyright © 2011-2019 Guy M. Allard
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
30 Write data to logical network writer. Writer will take care of the output wire data.
31 If the underlying connection goes bad and writer give up working, the closed ssdc chan
32 will make sure write action aware that happens.
34 func (c
*Connection
) writeWireData(wd wiredata
) error
{
44 Logical network writer. Read wiredata structures from the communication
45 channel, and put the frame on the wire.
47 func (c
*Connection
) writer() {
52 c
.log("WTR_WIREWRITE start")
56 c
.logx("WTR_WIREWRITE COMPLETE", d
.frame
.Command
, d
.frame
.Headers
,
57 HexData(d
.frame
.Body
))
60 if d
.frame
.Command
== DISCONNECT
{
61 break writerLoop
// we are done with this connection
64 c
.log("WTR_WIREWRITE shutdown S received")
67 c
.log("WTR_WIREWRITE shutdown W received")
76 c
.log("WTR_SHUTDOWN", time
.Now())
80 Connection logical write.
82 func (c
*Connection
) wireWrite(d wiredata
) {
84 // fmt.Printf("WWD01 f:[%v]\n", f)
86 case "\n": // HeartBeat frame
87 if c
.dld
.wde
&& c
.dld
.wds
{
88 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
90 _
, e
:= c
.wtr
.WriteString(f
.Command
)
92 if e
.(net
.Error
).Timeout() {
94 c
.dld
.dlnotify(e
, true)
100 default: // Other frames
101 if e
:= f
.writeFrame(c
.wtr
, c
); e
!= nil {
105 if e
:= c
.wtr
.Flush(); e
!= nil {
110 if e
:= c
.wtr
.Flush(); e
!= nil {
117 c
.hbd
.ls
= time
.Now().UnixNano() // Latest good send
120 c
.mets
.tfw
++ // Frame written count
121 c
.mets
.tbw
+= f
.Size(false) // Bytes written count
128 Physical frame write to the wire.
130 func (f
*Frame
) writeFrame(w
*bufio
.Writer
, c
*Connection
) error
{
133 // Content type. Always add it if the client does not suppress and does not
135 _
, sctok
= f
.Headers
.Contains(HK_SUPPRESS_CT
)
137 if _
, ctok
:= f
.Headers
.Contains(HK_CONTENT_TYPE
); !ctok
{
138 f
.Headers
= append(f
.Headers
, HK_CONTENT_TYPE
,
144 // Content length - Always add it if client does not suppress it and
145 // does not supply it.
146 _
, sclok
= f
.Headers
.Contains(HK_SUPPRESS_CL
)
148 if _
, clok
:= f
.Headers
.Contains(HK_CONTENT_LENGTH
); !clok
{
149 f
.Headers
= append(f
.Headers
, HK_CONTENT_LENGTH
, strconv
.Itoa(len(f
.Body
)))
152 // Encode the headers if needed
153 if c
.Protocol() > SPL_10
&& f
.Command
!= CONNECT
{
154 for i
:= 0; i
< len(f
.Headers
); i
+= 2 {
155 f
.Headers
[i
] = encode(f
.Headers
[i
])
156 f
.Headers
[i
+1] = encode(f
.Headers
[i
+1])
161 nz
:= bytes
.IndexByte(f
.Body
, 0)
162 // fmt.Printf("WDBG41 ok:%v\n", nz)
165 // fmt.Printf("WDBG42 body:%v bodystring: %v\n", f.Body, string(f.Body))
167 f
.Body
= f
.Body
[0:nz
]
168 // fmt.Printf("WDBG43 body:%v bodystring: %v\n", f.Body, string(f.Body))
172 if c
.dld
.wde
&& c
.dld
.wds
{
173 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
178 // Write the frame Command
179 _
, e
:= w
.WriteString(f
.Command
+ "\n")
180 if c
.checkWriteError(e
) != nil {
183 // fmt.Println("WRCMD", f.Command)
184 // Write the frame Headers
185 for i
:= 0; i
< len(f
.Headers
); i
+= 2 {
186 if c
.dld
.wde
&& c
.dld
.wds
{
187 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
189 _
, e
:= w
.WriteString(f
.Headers
[i
] + ":" + f
.Headers
[i
+1] + "\n")
190 if c
.checkWriteError(e
) != nil {
193 // fmt.Println("WRHDR", f.Headers[i]+":"+f.Headers[i+1]+"\n")
196 // Write the last Header LF
197 if c
.dld
.wde
&& c
.dld
.wds
{
198 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
200 e
= w
.WriteByte('\n')
201 if c
.checkWriteError(e
) != nil {
204 // fmt.Printf("WDBG40 ok:%v\n", sclok)
207 if len(f
.Body
) != 0 { // Foolish to write 0 length data
208 // fmt.Println("WRBDY", f.Body)
210 if c
.checkWriteError(e
) != nil {
214 if c
.dld
.wde
&& c
.dld
.wds
{
215 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
218 if c
.checkWriteError(e
) != nil {
221 // End of write loop - set no deadline
223 _
= c
.netconn
.SetWriteDeadline(c
.dld
.t0
)
228 func (c
*Connection
) checkWriteError(e error
) error
{
232 ne
, ok
:= e
.(net
.Error
)
238 c
.log("invoking write deadline callback 1")
239 c
.dld
.dlnotify(e
, true)
245 func (c
*Connection
) writeBody(f
*Frame
) error
{
246 // fmt.Printf("WDBG99 body:%v bodystring: %v\n", f.Body, string(f.Body))
250 if c
.dld
.wde
&& c
.dld
.wds
{
251 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
253 n
, e
= c
.wtr
.Write(f
.Body
)
254 if n
== len(f
.Body
) {
257 c
.log("SHORT WRITE", n
, len(f
.Body
))
258 if n
== 0 { // Zero bytes would mean something is seriously wrong.
264 if c
.dld
.wde
&& c
.dld
.wds
&& c
.dld
.dns
&& isErrorTimeout(e
) {
265 c
.log("invoking write deadline callback 2")
266 c
.dld
.dlnotify(e
, true)
268 // *Any* error from a bufio.Writer is *not* recoverable. See code in
269 // bufio.go to understand this. We get a new writer here, to clear any
271 c
.wtr
= bufio
.NewWriter(c
.netconn
) // Create new writer
276 func isErrorTimeout(e error
) bool {
280 _
, ok
:= e
.(net
.Error
)