2 // Copyright © 2011-2017 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.
29 Logical network writer. Read wiredata structures from the communication
30 channel, and put the frame on the wire.
32 func (c
*Connection
) writer() {
37 c
.log("WTR_WIREWRITE start")
39 c
.log("WTR_WIREWRITE COMPLETE", d
.frame
.Command
, d
.frame
.Headers
,
40 HexData(d
.frame
.Body
))
41 if d
.frame
.Command
== DISCONNECT
{
42 break writerLoop
// we are done with this connection
45 c
.log("WTR_WIREWRITE shutdown S received")
48 c
.log("WTR_WIREWRITE shutdown W received")
53 c
.log("WTR_SHUTDOWN", time
.Now())
57 Connection logical write.
59 func (c
*Connection
) wireWrite(d wiredata
) {
61 // fmt.Printf("WWD01 f:[%v]\n", f)
63 case "\n": // HeartBeat frame
64 if c
.dld
.wde
&& c
.dld
.dns
{
65 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
67 _
, e
:= c
.wtr
.WriteString(f
.Command
)
69 if e
.(net
.Error
).Timeout() {
71 c
.dld
.dlnotify(e
, true)
77 default: // Other frames
78 if e
:= f
.writeFrame(c
.wtr
, c
); e
!= nil {
82 if e
:= c
.wtr
.Flush(); e
!= nil {
87 if e
:= c
.wtr
.Flush(); e
!= nil {
94 c
.hbd
.ls
= time
.Now().UnixNano() // Latest good send
97 c
.mets
.tfw
++ // Frame written count
98 c
.mets
.tbw
+= f
.Size(false) // Bytes written count
105 Physical frame write to the wire.
107 func (f
*Frame
) writeFrame(w
*bufio
.Writer
, c
*Connection
) error
{
110 // Content type. Always add it if the client does not suppress and does not
112 _
, sctok
= f
.Headers
.Contains(HK_SUPPRESS_CT
)
114 if _
, ctok
:= f
.Headers
.Contains(HK_CONTENT_TYPE
); !ctok
{
115 f
.Headers
= append(f
.Headers
, HK_CONTENT_TYPE
,
121 // Content length - Always add it if client does not suppress it and
122 // does not supply it.
123 _
, sclok
= f
.Headers
.Contains(HK_SUPPRESS_CL
)
125 if _
, clok
:= f
.Headers
.Contains(HK_CONTENT_LENGTH
); !clok
{
126 f
.Headers
= append(f
.Headers
, HK_CONTENT_LENGTH
, strconv
.Itoa(len(f
.Body
)))
129 // Encode the headers if needed
130 if c
.Protocol() > SPL_10
&& f
.Command
!= CONNECT
{
131 for i
:= 0; i
< len(f
.Headers
); i
+= 2 {
132 f
.Headers
[i
] = encode(f
.Headers
[i
])
133 f
.Headers
[i
+1] = encode(f
.Headers
[i
+1])
138 nz
:= bytes
.IndexByte(f
.Body
, 0)
139 // fmt.Printf("WDBG41 ok:%v\n", nz)
142 // fmt.Printf("WDBG42 body:%v bodystring: %v\n", f.Body, string(f.Body))
144 f
.Body
= f
.Body
[0:nz
]
145 // fmt.Printf("WDBG43 body:%v bodystring: %v\n", f.Body, string(f.Body))
149 if c
.dld
.wde
&& c
.dld
.dns
{
150 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
155 // Write the frame Command
156 _
, e
:= w
.WriteString(f
.Command
+ "\n")
157 if c
.checkWriteError(e
) != nil {
160 // fmt.Println("WRCMD", f.Command)
161 // Write the frame Headers
162 for i
:= 0; i
< len(f
.Headers
); i
+= 2 {
163 if c
.dld
.wde
&& c
.dld
.dns
{
164 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
166 _
, e
:= w
.WriteString(f
.Headers
[i
] + ":" + f
.Headers
[i
+1] + "\n")
167 if c
.checkWriteError(e
) != nil {
170 // fmt.Println("WRHDR", f.Headers[i]+":"+f.Headers[i+1]+"\n")
173 // Write the last Header LF
174 if c
.dld
.wde
&& c
.dld
.dns
{
175 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
177 e
= w
.WriteByte('\n')
178 if c
.checkWriteError(e
) != nil {
181 // fmt.Printf("WDBG40 ok:%v\n", sclok)
184 if len(f
.Body
) != 0 { // Foolish to write 0 length data
185 // fmt.Println("WRBDY", f.Body)
187 if c
.checkWriteError(e
) != nil {
191 if c
.dld
.wde
&& c
.dld
.dns
{
192 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
195 if c
.checkWriteError(e
) != nil {
201 func (c
*Connection
) checkWriteError(e error
) error
{
205 ne
, ok
:= e
.(net
.Error
)
211 c
.log("invoking write deadline callback 1")
212 c
.dld
.dlnotify(e
, true)
218 func (c
*Connection
) writeBody(f
*Frame
) error
{
219 // fmt.Printf("WDBG99 body:%v bodystring: %v\n", f.Body, string(f.Body))
223 if c
.dld
.wde
&& c
.dld
.dns
{
224 _
= c
.netconn
.SetWriteDeadline(time
.Now().Add(c
.dld
.wdld
))
226 n
, e
= c
.wtr
.Write(f
.Body
)
227 if n
== len(f
.Body
) {
230 c
.log("SHORT WRITE", n
, len(f
.Body
))
231 if c
.dld
.wde
&& c
.dld
.dns
&& isErrorTimeout(e
) {
232 c
.log("invoking write deadline callback 2")
233 c
.dld
.dlnotify(e
, true)
239 func isErrorTimeout(e error
) bool {
243 _
, ok
:= e
.(net
.Error
)