func Open(options ...EndpointOption) (*Endpoint, error) { e := &Endpoint{ TID: tracer.NewID(), modules: make(map[interface{}]Module), tokens: make(map[cipherset.Token]*Exchange), hashnames: make(map[hashname.H]*Exchange), } e.listenerSet = newListenerSet() e.listenerSet.addrFunc = func() net.Addr { return e.LocalHashname() } e.listenerSet.dropChannelFunc = func(c *Channel, reason error) { c.Kill() } e.endpointHooks.endpoint = e e.exchangeHooks.endpoint = e e.channelHooks.endpoint = e e.exchangeHooks.Register(ExchangeHook{OnClosed: e.onExchangeClosed}) err := e.setOptions( RegisterModule(modTransportsKey, &modTransports{e}), RegisterModule(modNetwatchKey, &modNetwatch{endpoint: e})) if err != nil { return nil, e.traceError(err) } err = e.setOptions(options...) if err != nil { return nil, e.traceError(err) } err = e.setOptions( defaultRandomKeys, defaultTransport) if err != nil { return nil, e.traceError(err) } e.traceNew() err = e.start() if err != nil { e.close() return nil, e.traceError(err) } e.traceStarted() return e, nil }
func newChannel( hn hashname.H, typ string, reliable bool, serverside bool, x exchangeI, options ...ChannelOption, ) *Channel { c := &Channel{ TID: tracer.NewID(), x: x, hashname: hn, typ: typ, reliable: reliable, serverside: serverside, readBuffer: make([]*readBufferEntry, 0, cReadBufferSize), writeBuffer: make(map[uint32]*writeBufferEntry, cWriteBufferSize), oSeq: cBlankSeq, iBufferedSeq: cBlankSeq, iSeenSeq: cBlankSeq, iSeq: cBlankSeq, oAckedSeq: cBlankSeq, iAckedSeq: cBlankSeq, } c.cndRead = sync.NewCond(&c.mtx) c.cndWrite = sync.NewCond(&c.mtx) c.cndClose = sync.NewCond(&c.mtx) c.setOpenDeadline() c.tReadDeadline = time.AfterFunc(10*time.Second, c.onReadDeadlineReached) c.tWriteDeadline = time.AfterFunc(10*time.Second, c.onWriteDeadlineReached) c.tReadDeadline.Stop() c.tWriteDeadline.Stop() if reliable { c.tResend = time.AfterFunc(1*time.Second, c.resendLastPacket) c.tAcker = time.AfterFunc(10*time.Second, c.autoDeliverAck) } c.setOptions(options...) c.traceNew() return c }
func (e *Endpoint) traceDroppedPacket(msg []byte, conn net.Conn, reason string) { if tracer.Enabled { pkt := tracer.Info{ "msg": base64.StdEncoding.EncodeToString(msg), } if conn != nil { pkt["src"] = conn.RemoteAddr() pkt["dst"] = conn.LocalAddr() } tracer.Emit("endpoint.drop.packet", tracer.Info{ "endpoint_id": e.TID, "packet_id": tracer.NewID(), "reason": reason, "packet": pkt, }) } }
func (c *Channel) write(pkt *lob.Packet, p *Pipe) error { if pkt.TID == 0 { pkt.TID = tracer.NewID() } if c.broken { // When a channel is marked as broken the all writes // must return a BrokenChannelError. return c.traceWriteError(pkt, p, &BrokenChannelError{c.hashname, c.typ, c.id}) } if c.writeDeadlineReached { // When a channel reached a write deadline then all writes // must return a ErrTimeout. return c.traceWriteError(pkt, p, ErrTimeout) } if c.deliveredEnd { // When a channel sent a packet with the "end" header set // then all subsequent writes must return io.EOF return c.traceWriteError(pkt, p, io.EOF) } c.oSeq++ hdr := pkt.Header() hdr.C, hdr.HasC = c.id, true if c.reliable { hdr.Seq, hdr.HasSeq = c.oSeq, true } if !c.serverside && c.oSeq == cInitialSeq { hdr.Type, hdr.HasType = c.typ, true } end := hdr.HasEnd && hdr.End if end { c.deliveredEnd = true c.setCloseDeadline() } if c.reliable { if c.oSeq%30 == 0 || hdr.End { c.applyAckHeaders(pkt) } c.writeBuffer[c.oSeq] = &writeBufferEntry{pkt, end, time.Time{}, p} c.needsResend = false } err := c.x.deliverPacket(pkt, p) if err != nil { return c.traceWriteError(pkt, p, err) } statChannelSndPkt.Add(1) if pkt.Header().HasAck { statChannelSndAckInline.Add(1) } if c.oSeq == cInitialSeq && c.serverside { c.unsetOpenDeadline() } c.traceWrite(pkt, p) if !c.reliable { pkt.Free() } return nil }