// SendRaw sends to an ServerIdentity without wrapping the msg into a SDAMessage func (h *Host) SendRaw(e *network.ServerIdentity, msg network.Body) error { if msg == nil { return errors.New("Can't send nil-packet") } h.networkLock.RLock() c, ok := h.connections[e.ID] h.networkLock.RUnlock() if !ok { var err error c, err = h.Connect(e) if err != nil { return err } } log.Lvlf4("%s sends to %s msg: %+v", h.ServerIdentity.Addresses, e, msg) var err error err = c.Send(context.TODO(), msg) if err != nil /*&& err != network.ErrClosed*/ { log.Lvl2("Couldn't send to", c.ServerIdentity().First(), ":", err, "trying again") c, err = h.Connect(e) if err != nil { return err } err = c.Send(context.TODO(), msg) if err != nil { return err } } log.Lvl5("Message sent") return nil }
// RegisterProtocolInstance takes a PI and stores it for dispatching the message // to it. func (o *Overlay) RegisterProtocolInstance(pi ProtocolInstance) error { o.instancesLock.Lock() defer o.instancesLock.Unlock() var tni *TreeNodeInstance var tok = pi.Token() var ok bool // if the TreeNodeInstance doesn't exist if tni, ok = o.instances[tok.ID()]; !ok { return ErrWrongTreeNodeInstance } if tni.isBound() { return ErrProtocolRegistered } tni.bind(pi) o.protocolInstances[tok.ID()] = pi log.Lvlf4("%s registered ProtocolInstance %x", o.host.workingAddress, tok.ID()) return nil }
// Handle a connection => giving messages to the MsgChans func (h *Host) handleConn(c network.SecureConn) { address := c.Remote() for { ctx := context.TODO() am, err := c.Receive(ctx) // This is for testing purposes only: if the connection is missing // in the map, we just return silently h.networkLock.Lock() _, cont := h.connections[c.ServerIdentity().ID] h.networkLock.Unlock() if !cont { log.Lvl3(h.workingAddress, "Quitting handleConn ", c.Remote(), " because entry is not there") return } // So the receiver can know about the error am.SetError(err) am.From = address log.Lvl5("Got message", am) if err != nil { h.closingMut.Lock() log.Lvlf4("%+v got error (%+s) while receiving message (isClosing=%+v)", h.ServerIdentity.First(), err, h.isClosing) h.closingMut.Unlock() if err == network.ErrClosed || err == network.ErrEOF || err == network.ErrTemp { log.Lvl4(h.ServerIdentity.First(), c.Remote(), "quitting handleConn for-loop", err) h.closeConnection(c) return } log.Error(h.ServerIdentity.Addresses, "Error with connection", address, "=>", err) } else { h.closingMut.Lock() if !h.isClosing { h.networkChan <- am } h.closingMut.Unlock() } } }
// TransmitMsg takes a message received from the host and treats it. It might // - ask for the identityList // - ask for the Tree // - create a new protocolInstance // - pass it to a given protocolInstance func (o *Overlay) TransmitMsg(sdaMsg *ProtocolMsg) error { o.transmitMux.Lock() defer o.transmitMux.Unlock() // do we have the entitylist ? if not, ask for it. if o.Roster(sdaMsg.To.RosterID) == nil { log.Lvl4("Will ask the Roster from token", sdaMsg.To.RosterID, len(o.entityLists), o.host.workingAddress) return o.host.requestTree(sdaMsg.ServerIdentity, sdaMsg) } tree := o.Tree(sdaMsg.To.TreeID) if tree == nil { log.Lvl4("Will ask for tree from token") return o.host.requestTree(sdaMsg.ServerIdentity, sdaMsg) } // TreeNodeInstance var pi ProtocolInstance o.instancesLock.Lock() pi, ok := o.protocolInstances[sdaMsg.To.ID()] done := o.instancesInfo[sdaMsg.To.ID()] o.instancesLock.Unlock() if done { log.Lvl4("Message for TreeNodeInstance that is already finished") return nil } // if the TreeNodeInstance is not there, creates it if !ok { log.Lvlf4("Creating TreeNodeInstance at %s %x", o.host.ServerIdentity, sdaMsg.To.ID()) tn, err := o.TreeNodeFromToken(sdaMsg.To) if err != nil { return errors.New("No TreeNode defined in this tree here") } tni := o.newTreeNodeInstanceFromToken(tn, sdaMsg.To) // see if we know the Service Recipient s, ok := o.host.serviceStore.serviceByID(sdaMsg.To.ServiceID) // no servies defined => check if there is a protocol that can be // created if !ok { pi, err = ProtocolInstantiate(sdaMsg.To.ProtoID, tni) if err != nil { return err } go pi.Dispatch() /// use the Services to instantiate it } else { // request the PI from the Service and binds the two pi, err = s.NewProtocol(tni, &sdaMsg.Config) if err != nil { return err } if pi == nil { return nil } go pi.Dispatch() } if err := o.RegisterProtocolInstance(pi); err != nil { return errors.New("Error Binding TreeNodeInstance and ProtocolInstance: " + err.Error()) } log.Lvl4(o.host.workingAddress, "Overlay created new ProtocolInstace msg => ", fmt.Sprintf("%+v", sdaMsg.To)) } log.Lvl4("Dispatching message", o.host.ServerIdentity) // TODO Check if TreeNodeInstance is already Done pi.ProcessProtocolMsg(sdaMsg) return nil }
// Send opens the connection to 'dst' and sends the message 'req'. The // reply is returned, or an error if the timeout of 10 seconds is reached. func (c *Client) Send(dst *network.ServerIdentity, msg network.Body) (*network.Packet, error) { c.Lock() defer c.Unlock() if c.host == nil { kp := config.NewKeyPair(network.Suite) c.host = network.NewSecureTCPHost(kp.Secret, network.NewServerIdentity(kp.Public, "")) } // Connect to the root log.Lvl4("Opening connection to", dst) con, err := c.host.Open(dst) defer c.host.Close() if err != nil { return nil, err } m, err := network.NewNetworkMessage(msg) if err != nil { return nil, err } b, err := m.MarshalBinary() if err != nil { return nil, err } serviceReq := &ClientRequest{ Service: c.ServiceID, Data: b, } pchan := make(chan network.Packet) go func() { // send the request log.Lvlf4("Sending request %x", serviceReq.Service) if err := con.Send(context.TODO(), serviceReq); err != nil { close(pchan) return } log.Lvl4("Waiting for the response from", reflect.ValueOf(con).Pointer()) // wait for the response packet, err := con.Receive(context.TODO()) if err != nil { packet.Msg = StatusRet{err.Error()} packet.MsgType = network.TypeFromData(&StatusRet{}) } pchan <- packet }() select { case response := <-pchan: log.Lvlf5("Response: %+v %+v", response, response.Msg) // Catch an eventual error err := ErrMsg(&response, nil) if err != nil { return nil, err } return &response, nil case <-time.After(time.Second * 10): return &network.Packet{}, errors.New("Timeout on sending message") } }