/// <summary> /// TXT records contain additional attributes of services /// </summary> /// <param name="service"></param> /// <param name="player"></param> private void processTXTrecord(NetService service, JSONSrcSink player) { byte[] txt = service.TXTRecordData; IDictionary dict = NetService.DictionaryFromTXTRecordData(txt); if (dict == null) return; // Remove all sessions from this Player so that we can add all the new entries from this TXT record ArrayList itemsToRemove = new ArrayList(); lock (sessions.SyncRoot) { foreach (JSONSession nxtSess in sessions) { if (service.Name.Equals(nxtSess.sinkId)) itemsToRemove.Add(nxtSess); }; if (itemsToRemove.Count > 0) { foreach (JSONSession sess in itemsToRemove) sessions.Remove(sess); itemsToRemove.Clear(); } } foreach (DictionaryEntry kvp in dict) { String key = ((String)kvp.Key).ToUpper(); String value = null; try { value = Encoding.UTF8.GetString((byte[])kvp.Value); } catch { // All displaycast values are strings!! continue; } switch (key) { case "NAME": player.description = value; break; case "OSVERSION": player.os = value; break; case "MACHINENAME": player.machineName = value; break; case "LOCATIONID": player.locationID = value; break; case "VERSION": Trace.WriteLine("DEBUG: No use for version info in the API"); // player.version = Convert.ToDouble(value); break; case "IMAGEPORT": Trace.WriteLine("DEBUG: No use for image port in the session object"); // player.imagePort = Convert.ToInt32(value); break; case "USERID": player.userName = value; break; case "NEARBY": player.nearBy = value; break; case "MASKPORT": Trace.WriteLine("DEBUG: No use for Mask port info in the API"); break; case "BLUETOOTH": Trace.WriteLine("DEBUG: No use for Bluetooth ID's in the API"); break; case "MASKSCREEN": try { char[] separator = { ' ', 'x' }; String[] words = value.Split(separator); player.maskX = Convert.ToInt32(words[0]); player.maskY = Convert.ToInt32(words[1]); player.maskWidth = Convert.ToInt32(words[2]); player.maskHeight = Convert.ToInt32(words[3]); } catch (FormatException) { player.maskX = player.maskY = player.maskWidth = player.maskHeight = 0; } break; default: if (key.StartsWith("SCREEN")) { // Could be screen0, screen1 etc. Rectangle oldRect = new Rectangle(player.x, player.y, player.width, player.height); char[] separator = { ' ', 'x' }; String[] words = value.Split(separator); Rectangle newRect = new Rectangle(); try { newRect.X = Convert.ToInt32(words[0]); newRect.Y = Convert.ToInt32(words[1]); newRect.Width = Convert.ToInt32(words[2]); newRect.Height = Convert.ToInt32(words[3]); } catch (FormatException) { continue; } oldRect = Rectangle.Union(oldRect, newRect); player.x = oldRect.X; player.y = oldRect.Y; player.width = oldRect.Width; player.height = oldRect.Height; } else { // Sessions char[] separator = { ' ' }; String[] words = value.Split(separator); JSONSession sess = null; if (words.Length == 8) { // This shouldn't match anymore because we remove all sessions involving this player foreach (JSONSession nxtSess in sessions) { if (key.Equals(nxtSess.id)) { sess = nxtSess; break; } }; if (sess == null) { sess = new JSONSession(); sess.id = key; sessions.Add(sess); }; sess.srcId = words[0]; sess.sinkId = words[1]; try { sess.x = Convert.ToInt32(words[2]); sess.y = Convert.ToInt32(words[3]); sess.width = Convert.ToInt32(words[4]); sess.height = Convert.ToInt32(words[5]); sess.iconified = Convert.ToInt32(words[6]); sess.fullScreen = Convert.ToInt32(words[7]); } catch (FormatException) { // Would rather have all correct sessions than partially correct sessions sessions.Remove(sess); } Trace.WriteLine("DEBUG: " + sess.id + " at " + sess.width + " x " + sess.height); } else Trace.WriteLine("FATAL: Unknown attribute " + key + ":" + value); } break; } } }
/// <summary> /// TXT records contain additional attributes of services /// </summary> /// <param name="service"></param> /// <param name="player"></param> private void processTXTrecord(NetService service, JSONSrcSink player) { byte[] txt = service.TXTRecordData; IDictionary dict = NetService.DictionaryFromTXTRecordData(txt); if (dict == null) { return; } // Remove all sessions from this Player so that we can add all the new entries from this TXT record ArrayList itemsToRemove = new ArrayList(); lock (sessions.SyncRoot) { foreach (JSONSession nxtSess in sessions) { if (service.Name.Equals(nxtSess.sinkId)) { itemsToRemove.Add(nxtSess); } } ; if (itemsToRemove.Count > 0) { foreach (JSONSession sess in itemsToRemove) { sessions.Remove(sess); } itemsToRemove.Clear(); } } foreach (DictionaryEntry kvp in dict) { String key = ((String)kvp.Key).ToUpper(); String value = null; try { value = Encoding.UTF8.GetString((byte[])kvp.Value); } catch { // All displaycast values are strings!! continue; } switch (key) { case "NAME": player.description = value; break; case "OSVERSION": player.os = value; break; case "MACHINENAME": player.machineName = value; break; case "LOCATIONID": player.locationID = value; break; case "VERSION": Trace.WriteLine("DEBUG: No use for version info in the API"); // player.version = Convert.ToDouble(value); break; case "IMAGEPORT": Trace.WriteLine("DEBUG: No use for image port in the session object"); // player.imagePort = Convert.ToInt32(value); break; case "USERID": player.userName = value; break; case "NEARBY": player.nearBy = value; break; case "MASKPORT": Trace.WriteLine("DEBUG: No use for Mask port info in the API"); break; case "BLUETOOTH": Trace.WriteLine("DEBUG: No use for Bluetooth ID's in the API"); break; case "MASKSCREEN": try { char[] separator = { ' ', 'x' }; String[] words = value.Split(separator); player.maskX = Convert.ToInt32(words[0]); player.maskY = Convert.ToInt32(words[1]); player.maskWidth = Convert.ToInt32(words[2]); player.maskHeight = Convert.ToInt32(words[3]); } catch (FormatException) { player.maskX = player.maskY = player.maskWidth = player.maskHeight = 0; } break; default: if (key.StartsWith("SCREEN")) // Could be screen0, screen1 etc. { Rectangle oldRect = new Rectangle(player.x, player.y, player.width, player.height); char[] separator = { ' ', 'x' }; String[] words = value.Split(separator); Rectangle newRect = new Rectangle(); try { newRect.X = Convert.ToInt32(words[0]); newRect.Y = Convert.ToInt32(words[1]); newRect.Width = Convert.ToInt32(words[2]); newRect.Height = Convert.ToInt32(words[3]); } catch (FormatException) { continue; } oldRect = Rectangle.Union(oldRect, newRect); player.x = oldRect.X; player.y = oldRect.Y; player.width = oldRect.Width; player.height = oldRect.Height; } else // Sessions { char[] separator = { ' ' }; String[] words = value.Split(separator); JSONSession sess = null; if (words.Length == 8) { // This shouldn't match anymore because we remove all sessions involving this player foreach (JSONSession nxtSess in sessions) { if (key.Equals(nxtSess.id)) { sess = nxtSess; break; } } ; if (sess == null) { sess = new JSONSession(); sess.id = key; sessions.Add(sess); } ; sess.srcId = words[0]; sess.sinkId = words[1]; try { sess.x = Convert.ToInt32(words[2]); sess.y = Convert.ToInt32(words[3]); sess.width = Convert.ToInt32(words[4]); sess.height = Convert.ToInt32(words[5]); sess.iconified = Convert.ToInt32(words[6]); sess.fullScreen = Convert.ToInt32(words[7]); } catch (FormatException) { // Would rather have all correct sessions than partially correct sessions sessions.Remove(sess); } Trace.WriteLine("DEBUG: " + sess.id + " at " + sess.width + " x " + sess.height); } else { Trace.WriteLine("FATAL: Unknown attribute " + key + ":" + value); } } break; } } }
/// <summary> /// Process the current HTTP/REST request /// </summary> /// <param name="Context">returned from the asynchronous httplistener</param> protected virtual void ProcessRequest(HttpListenerContext Context) { HttpListenerRequest request = Context.Request; HttpListenerResponse response = Context.Response; String cmd = request.Url.LocalPath.Substring(1).ToUpper(); String responseString = null; response.StatusCode = (int)HttpStatusCode.OK; // Giant command processing switch switch (cmd) { case "WHOAMI": IPAddress who = request.RemoteEndPoint.Address; JSONwhoami ami = new JSONwhoami(); Trace.WriteLine("DEBUG: I am " + who.ToString() + " " + request.Headers); foreach (NetService service in sinkServices) { IList addresses = service.Addresses; foreach (IPEndPoint addr in addresses) { Trace.WriteLine("DEBUG: am I sink " + addr.Address.ToString()); if (who.Equals(addr.Address)) { if (service.Type.StartsWith(Shared.DisplayCastGlobals.PLAYER)) { ami.player = service.Name; } if (service.Type.StartsWith(Shared.DisplayCastGlobals.ARCHIVER)) { ami.archiver = service.Name; } } } } foreach (NetService service in sourceServices) { IList addresses = service.Addresses; foreach (IPEndPoint addr in addresses) { Trace.WriteLine("DEBUG: am I source " + addr.Address.ToString()); if (who.Equals(addr.Address)) { if (service.Type.StartsWith(Shared.DisplayCastGlobals.STREAMER)) { ami.streamer = service.Name; } } } } responseString = serializer.Serialize(ami); break; case "LISTPLAYERS": responseString = serializer.Serialize(players); break; case "LISTARCHIVERS": responseString = serializer.Serialize(archivers); break; case "LISTSTREAMERS": responseString = serializer.Serialize(streamers); break; case "LISTSESSIONS": responseString = serializer.Serialize(sessions); break; case "STATUS": if ((request.Url.Query == null) || (request.Url.Query.Length < 2)) { response.StatusCode = (int)HttpStatusCode.BadRequest; response.StatusDescription = DisplayCastGlobals.CONTROL_USAGE_STATUS; responseString = JSONError(DisplayCastGlobals.CONTROL_JSON_SYNTAX_ERROR); } else { String id = request.Url.Query.Substring(1); JSONSrcSink res = null; // Could be status of players/archivers/streamers foreach (JSONSrcSink clnt in players) { if (clnt.id.Equals(id)) { res = clnt; break; } } if (res == null) { foreach (JSONSrcSink clnt in archivers) { if (clnt.id.Equals(id)) { res = clnt; break; } } } if (res == null) { foreach (JSONSrcSink clnt in streamers) { if (clnt.id.Equals(id)) { res = clnt; break; } } } if (res == null) { response.StatusCode = (int)HttpStatusCode.NotFound; response.StatusDescription = "ID: " + id + " unknown"; responseString = JSONError(DisplayCastGlobals.CONTROL_JSON_UNKNOWN_ERROR); } else { responseString = serializer.Serialize(res); } } break; case "SESSIONSTATUS": if ((request.Url.Query == null) || (request.Url.Query.Length < 2)) { response.StatusCode = (int)HttpStatusCode.BadRequest; response.StatusDescription = DisplayCastGlobals.CONTROL_USAGE_SESSIONSTATUS; responseString = JSONError(DisplayCastGlobals.CONTROL_JSON_SYNTAX_ERROR); } else { String id = request.Url.Query.Substring(1); JSONSession res = null; foreach (JSONSession sess in sessions) { if (sess.id.Equals(id)) { res = sess; break; } } if (res == null) { response.StatusCode = (int)HttpStatusCode.NotFound; response.StatusDescription = "ID: " + id + " unknown"; responseString = JSONError(DisplayCastGlobals.CONTROL_JSON_UNKNOWN_ERROR); } else { responseString = serializer.Serialize(res); } } break; case "SNAPSHOT": if ((request.Url.Query == null) || (request.Url.Query.Length < 2)) { response.StatusCode = (int)HttpStatusCode.BadRequest; response.StatusDescription = DisplayCastGlobals.CONTROL_USAGE_SNAPSHOT; responseString = JSONError(DisplayCastGlobals.CONTROL_JSON_SYNTAX_ERROR); } else { String id = request.Url.Query.Substring(1); char[] delimiters = { '=', '&' }; String[] words = id.Split(delimiters); if ((words.Length < 2) || (!words[0].ToUpper().Equals("ID"))) { response.StatusCode = (int)HttpStatusCode.BadRequest; response.StatusDescription = DisplayCastGlobals.CONTROL_USAGE_SNAPSHOT; responseString = JSONError(DisplayCastGlobals.CONTROL_JSON_SYNTAX_ERROR); } else { NetService service = null; foreach (NetService s in sourceServices) { if (s.Name.Equals(words[1])) { service = s; break; } }