/// <summary> /// Add an observer for the given observable resource /// </summary> /// <param name="coapReq">A request message from client that is requesting resource observation</param> public void AddResourceObserver(CoAPRequest coapReq) { if (coapReq == null) { throw new ArgumentNullException("CoAP message requesting for observation is NULL"); } if (!coapReq.IsObservable()) { throw new ArgumentException("CoAP message requesting for observation is not marked as observable"); } string observableURL = coapReq.GetURL().Trim().ToLower(); //First, add this URL as an observable resource this.AddObservableResource(observableURL); //Now, add this observer for the given observable resource this._observableListSync.WaitOne(); bool observerAlreadyExists = false; ArrayList observers = (ArrayList)this._observers[observableURL]; for (int count = 0; count < observers.Count; count++) { CoAPRequest storedObserver = (CoAPRequest)observers[count]; if (storedObserver.ID.Value == coapReq.ID.Value) { observerAlreadyExists = true; break; } } if (!observerAlreadyExists) { observers.Add(coapReq); } this._observableListSync.Set(); }
/// <summary> /// Send the CoAP message to client /// </summary> /// <param name="coapMsg">The CoAP message to send</param> /// <returns>Number of bytes sent</returns> public override int Send(AbstractCoAPMessage coapMsg) { if (coapMsg == null) { throw new ArgumentNullException("Message is NULL"); } if (this._socket == null) { throw new InvalidOperationException("CoAP server not yet started"); } int bytesSent = 0; try { //We do not want server to die when a socket send error occurs... //just clean all settings specific to the remote client and //keep going byte[] coapBytes = coapMsg.ToByteStream(); bytesSent = this._socket.SendTo(coapBytes, coapMsg.RemoteSender); if (coapMsg.MessageType.Value == CoAPMessageType.CON) { //confirmable message...need to wait for a response coapMsg.DispatchDateTime = DateTime.Now; this._msgPendingAckQ.AddToWaitQ(coapMsg); } } catch (Exception e) { this._msgPendingAckQ.RemoveFromWaitQ(coapMsg.ID.Value); if (coapMsg.GetType() == typeof(CoAPRequest)) { CoAPRequest coapReq = (CoAPRequest)coapMsg; this._observers.RemoveResourceObserver(coapReq.GetURL(), coapReq.Token.Value); } else if (coapMsg.GetType() == typeof(CoAPResponse)) { CoAPResponse coapResp = (CoAPResponse)coapMsg; this._observers.RemoveResourceObserver(coapResp); } this.HandleError(e, coapMsg); } return(bytesSent); }
/// <summary> /// Called when a CoAP request is received...we will only support CON requests /// of type GET... the path is sensors/temp /// </summary> /// <param name="coapReq">CoAPRequest object</param> static void OnCoAPRequestReceived(CoAPRequest coapReq) { string reqPath = (coapReq.GetPath() != null) ? coapReq.GetPath().ToLower() : ""; /*We have skipped error handling in code below to just focus on observe option*/ if (coapReq.MessageType.Value == CoAPMessageType.CON && coapReq.Code.Value == CoAPMessageCode.GET) { if (!coapReq.IsObservable() /*Does the request have "Observe" option*/) { /*Request is not to observe...we do not support anything no-observable*/ CoAPResponse resp = new CoAPResponse(CoAPMessageType.ACK, CoAPMessageCode.NOT_IMPLEMENTED, coapReq /*Copy all necessary values from request in the response*/); coapServer.Send(resp); } else if (!coapServer.ObserversList.IsResourceBeingObserved(coapReq.GetURL()) /*do we support observation on this path*/) { //Observation is not supported on this path..just to tell you how to check CoAPResponse resp = new CoAPResponse(CoAPMessageType.ACK, CoAPMessageCode.NOT_FOUND, coapReq /*Copy all necessary values from request in the response*/); coapServer.Send(resp); } else { //This is a request to observe this resource...register this client coapServer.ObserversList.AddResourceObserver(coapReq); /*Request contains observe option and path is correct*/ CoAPResponse resp = new CoAPResponse(CoAPMessageType.ACK, CoAPMessageCode.EMPTY, coapReq /*Copy all necessary values from request in the response*/); //send it..tell client we registered it's request to observe coapServer.Send(resp); } } }
/// <summary> /// Based on the token value, find which resource was being observed /// </summary> /// <param name="token">The CoAP token that is used for req/resp matching</param> /// <returns>The URL of the resource being observed</returns> protected string FindResourceBeingObserved(CoAPToken token) { if (token == null || token.Value == null) { throw new ArgumentNullException("Invalid token"); } bool observerFound = false; string observedResourceURL = null; CoAPRequest observerEntry = null; this._observableListSync.WaitOne(); foreach (string observedResURL in this._observers.Keys) { ArrayList observers = (ArrayList)this._observers[observedResURL]; foreach (CoAPRequest req in observers) { if (AbstractByteUtils.AreByteArraysEqual(req.Token.Value, token.Value)) { observerFound = true; observerEntry = req; break; } } if (observerFound) { break; } } this._observableListSync.Set(); if (observerFound && observerEntry != null) { observedResourceURL = observerEntry.GetURL(); } return(observedResourceURL); }