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")
74 c
.log("WTR_SHUTDOWN", time
.Now())
78 Connection logical write.
80 func (c
*Connection
) wireWrite(d wiredata
) {
82 // fmt.Printf("WWD01 f:[%v]\n", f)
84 case "\n": // HeartBeat frame
85 if c
.dld
.wde
&& c
.dld
.wds
{
86 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
88 _
, e
:= c
.wtr
.WriteString(f
.Command
)
90 if e
.(net
.Error
).Timeout() {
92 c
.dld
.dlnotify(e
, true)
98 default: // Other frames
99 if e
:= f
.writeFrame(c
.wtr
, c
); e
!= nil {
103 if e
:= c
.wtr
.Flush(); e
!= nil {
108 if e
:= c
.wtr
.Flush(); e
!= nil {
115 c
.hbd
.ls
= time
.Now().UnixNano() // Latest good send
118 c
.mets
.tfw
++ // Frame written count
119 c
.mets
.tbw
+= f
.Size(false) // Bytes written count
126 Physical frame write to the wire.
128 func (f
*Frame
) writeFrame(w
*bufio
.Writer
, c
*Connection
) error
{
131 // Content type. Always add it if the client does not suppress and does not
133 _
, sctok
= f
.Headers
.Contains(HK_SUPPRESS_CT
)
135 if _
, ctok
:= f
.Headers
.Contains(HK_CONTENT_TYPE
); !ctok
{
136 f
.Headers
= append(f
.Headers
, HK_CONTENT_TYPE
,
142 // Content length - Always add it if client does not suppress it and
143 // does not supply it.
144 _
, sclok
= f
.Headers
.Contains(HK_SUPPRESS_CL
)
146 if _
, clok
:= f
.Headers
.Contains(HK_CONTENT_LENGTH
); !clok
{
147 f
.Headers
= append(f
.Headers
, HK_CONTENT_LENGTH
, strconv
.Itoa(len(f
.Body
)))
150 // Encode the headers if needed
151 if c
.Protocol() > SPL_10
&& f
.Command
!= CONNECT
{
152 for i
:= 0; i
< len(f
.Headers
); i
+= 2 {
153 f
.Headers
[i
] = encode(f
.Headers
[i
])
154 f
.Headers
[i
+1] = encode(f
.Headers
[i
+1])
159 nz
:= bytes
.IndexByte(f
.Body
, 0)
160 // fmt.Printf("WDBG41 ok:%v\n", nz)
163 // fmt.Printf("WDBG42 body:%v bodystring: %v\n", f.Body, string(f.Body))
165 f
.Body
= f
.Body
[0:nz
]
166 // fmt.Printf("WDBG43 body:%v bodystring: %v\n", f.Body, string(f.Body))
170 if c
.dld
.wde
&& c
.dld
.wds
{
171 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
176 // Write the frame Command
177 _
, e
:= w
.WriteString(f
.Command
+ "\n")
178 if c
.checkWriteError(e
) != nil {
181 // fmt.Println("WRCMD", f.Command)
182 // Write the frame Headers
183 for i
:= 0; i
< len(f
.Headers
); i
+= 2 {
184 if c
.dld
.wde
&& c
.dld
.wds
{
185 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
187 _
, e
:= w
.WriteString(f
.Headers
[i
] + ":" + f
.Headers
[i
+1] + "\n")
188 if c
.checkWriteError(e
) != nil {
191 // fmt.Println("WRHDR", f.Headers[i]+":"+f.Headers[i+1]+"\n")
194 // Write the last Header LF
195 if c
.dld
.wde
&& c
.dld
.wds
{
196 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
198 e
= w
.WriteByte('\n')
199 if c
.checkWriteError(e
) != nil {
202 // fmt.Printf("WDBG40 ok:%v\n", sclok)
205 if len(f
.Body
) != 0 { // Foolish to write 0 length data
206 // fmt.Println("WRBDY", f.Body)
208 if c
.checkWriteError(e
) != nil {
212 if c
.dld
.wde
&& c
.dld
.wds
{
213 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
216 if c
.checkWriteError(e
) != nil {
219 // End of write loop - set no deadline
221 _
= c
.netconn
.SetWriteDeadline(c
.dld
.t0
)
226 func (c
*Connection
) checkWriteError(e error
) error
{
230 ne
, ok
:= e
.(net
.Error
)
236 c
.log("invoking write deadline callback 1")
237 c
.dld
.dlnotify(e
, true)
243 func (c
*Connection
) writeBody(f
*Frame
) error
{
244 // fmt.Printf("WDBG99 body:%v bodystring: %v\n", f.Body, string(f.Body))
248 if c
.dld
.wde
&& c
.dld
.wds
{
249 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
251 n
, e
= c
.wtr
.Write(f
.Body
)
252 if n
== len(f
.Body
) {
255 c
.log("SHORT WRITE", n
, len(f
.Body
))
256 if n
== 0 { // Zero bytes would mean something is seriously wrong.
262 if c
.dld
.wde
&& c
.dld
.wds
&& c
.dld
.dns
&& isErrorTimeout(e
) {
263 c
.log("invoking write deadline callback 2")
264 c
.dld
.dlnotify(e
, true)
266 // *Any* error from a bufio.Writer is *not* recoverable. See code in
267 // bufio.go to understand this. We get a new writer here, to clear any
269 c
.wtr
= bufio
.NewWriter(c
.netconn
) // Create new writer
274 func isErrorTimeout(e error
) bool {
278 _
, ok
:= e
.(net
.Error
)