// pinger() sends a ping frame when the session has been inactive for too long func (s *Session) pinger() { for { <-s.inactive.C // send ping pingF := frame.NewWPing() pingF.Set(frame.ControlStream, nil, false) if err := s.writeFrame(pingF, time.Time{}); err != nil { s.die(frame.InternalError, err) break } } }
func (s *Session) handleFrame(rf frame.RFrame) { switch f := rf.(type) { case *frame.RStreamSyn: // if we're going away, refuse new streams if atomic.LoadInt32(&s.local.goneAway) == 1 { rstF := frame.NewWStreamRst() rstF.Set(f.StreamId(), frame.RefusedStream) go s.writeFrame(rstF, time.Time{}) return } if f.StreamId() <= frame.StreamId(atomic.LoadUint32(&s.remote.lastId)) { s.die(frame.ProtocolError, fmt.Errorf("Stream id %d is less than last remote id.", f.StreamId())) return } if s.isLocal(f.StreamId()) { s.die(frame.ProtocolError, fmt.Errorf("Stream id has wrong parity for remote endpoint: %d", f.StreamId())) return } // update last remote id atomic.StoreUint32(&s.remote.lastId, uint32(f.StreamId())) // make the new stream str := s.newStream(f.StreamId(), f.RelatedStreamId(), f.StreamPriority(), f.StreamInfo(), false, f.Fin(), s.defaultWindowSize, s) // add it to the stream map s.streams.Set(f.StreamId(), str) // put the new stream on the accept channel s.accept <- str case *frame.RStreamData: if str := s.getStream(f.StreamId()); str != nil { str.handleStreamData(f) } else { // DATA frames on closed connections are just stream-level errors fRst := frame.NewWStreamRst() if err := fRst.Set(f.StreamId(), frame.StreamClosed); err != nil { s.die(frame.InternalError, err) } s.wr.Lock() defer s.wr.Unlock() s.transport.WriteFrame(fRst) return } case *frame.RStreamRst: // delegate to the stream to handle these frames if str := s.getStream(f.StreamId()); str != nil { str.handleStreamRst(f) } case *frame.RStreamWndInc: // delegate to the stream to handle these frames if str := s.getStream(f.StreamId()); str != nil { str.handleStreamWndInc(f) } case *frame.RGoAway: atomic.StoreInt32(&s.remote.goneAway, 1) s.remoteDebug = f.Debug() lastId := f.LastStreamId() s.streams.Each(func(id frame.StreamId, str stream) { // close all streams that we opened above the last handled id if s.isLocal(str.Id()) && str.Id() > lastId { str.closeWith(fmt.Errorf("Remote is going away")) } }) case *frame.RPing: if !f.Ack() { pingF := frame.NewWPing() pingF.Set(f.StreamId(), f.Body(), true) go s.writeFrame(pingF, time.Time{}) } default: s.die(frame.ProtocolError, fmt.Errorf("Unrecognized frame type: %v", reflect.TypeOf(f))) return } }