func (conn *Conn) WriteLoop() (err error) { Debug("start conn.WriteLoop()") for frame := range conn.WriteChan { Notice("%v %v", Red("send"), util.Indent(frame.String())) // TODO: ここで connection レベルの WindowSize を見る err = frame.Write(conn.RW) if err != nil { Error("%v", err) return err } } return }
func (conn *Conn) ReadLoop() { Debug("start conn.ReadLoop()") for { // コネクションからフレームを読み込む frame, err := ReadFrame(conn.RW, conn.Settings) if err != nil { Error("%v", err) h2Error, ok := err.(*H2Error) if ok { conn.GoAway(0, h2Error) } break } if frame != nil { Notice("%v %v", Green("recv"), util.Indent(frame.String())) } streamID := frame.Header().StreamID types := frame.Header().Type // CONNECTION LEVEL if streamID == 0 { if types == DataFrameType || types == HeadersFrameType || types == PriorityFrameType || types == RstStreamFrameType || types == PushPromiseFrameType || types == ContinuationFrameType { msg := fmt.Sprintf("%s FRAME for Stream ID 0", types) Error("%v", msg) conn.GoAway(0, &H2Error{PROTOCOL_ERROR, msg}) break // TODO: check this flow is correct or not } // SETTINGS frame を受け取った場合 if types == SettingsFrameType { settingsFrame, ok := frame.(*SettingsFrame) if !ok { Error("invalid settings frame %v", frame) return } conn.HandleSettings(settingsFrame) } // Connection Level Window Update if types == WindowUpdateFrameType { windowUpdateFrame, ok := frame.(*WindowUpdateFrame) if !ok { Error("invalid window update frame %v", frame) return } Debug("connection window size increment(%v)", int32(windowUpdateFrame.WindowSizeIncrement)) conn.Window.UpdatePeer(int32(windowUpdateFrame.WindowSizeIncrement)) } // respond to PING if types == PingFrameType { // ignore ack if frame.Header().Flags != ACK { conn.PingACK([]byte("pong ")) // should be 8 byte } continue } // handle GOAWAY with close connection if types == GoAwayFrameType { Debug("stop conn.ReadLoop() by GOAWAY") break } } // STREAM LEVEL if streamID > 0 { if types == SettingsFrameType || types == PingFrameType || types == GoAwayFrameType { msg := fmt.Sprintf("%s FRAME for Stream ID not 0", types) Error("%v", msg) conn.GoAway(0, &H2Error{PROTOCOL_ERROR, msg}) break // TODO: check this flow is correct or not } // DATA frame なら winodw を消費 if types == DataFrameType { length := int32(frame.Header().Length) conn.WindowConsume(length) } // 新しいストリーム ID なら対応するストリームを生成 stream, ok := conn.Streams[streamID] if !ok { // create stream with streamID stream = conn.NewStream(streamID) conn.Streams[streamID] = stream // update last stream id if streamID > conn.LastStreamID { conn.LastStreamID = streamID } } // stream の state を変える err = stream.ChangeState(frame, RECV) if err != nil { Error("%v", err) h2Error, ok := err.(*H2Error) if ok { conn.GoAway(0, h2Error) } break } // stream が close ならリストから消す if stream.State == CLOSED { // ただし、1 秒は window update が来てもいいように待つ // TODO: atomic にする go func(streamID uint32) { <-time.After(1 * time.Second) Info("remove stream(%d) from conn.Streams[]", streamID) conn.Streams[streamID] = nil }(streamID) } // ストリームにフレームを渡す stream.ReadChan <- frame } } Debug("stop the readloop") }