private string ChunkedRead(HttpWebResponse response) { Stream reader; byte[] buf = new byte[4096]; int len; string chunk; string resp = ""; reader = response.GetResponseStream(); try { do { len = reader.Read(buf, 0, buf.Length); //Console.WriteLine(" -> Read " + len.ToString() + " bytes from stream."); if (len > 0) { chunk = new String(Encoding.ASCII.GetString(buf).ToCharArray(), 0, len); resp += chunk; } } while (len > 0); } catch { WFLogging.Debug("Ignoring reader exception?"); } reader.Close(); return(resp); }
private static void ProcessWSData(string json) { if (json.Contains("obs_air")) { WeatherFlowNS.NS.udp_client.WSObservations(json); } else if (json.Contains("obs_sky")) { WeatherFlowNS.NS.udp_client.WSObservations(json); } else if (json.Contains("rapid_wind")) { WeatherFlowNS.NS.udp_client.RapidWindEvt(json); } else if (json.Contains("evt_strike")) { WeatherFlowNS.NS.udp_client.LigtningStrikeEvt(json); } else if (json.Contains("evt_precip")) { } else if (json.Contains("ack")) { } else { WFLogging.Error("Unknown type of WebSocket packet"); WFLogging.Error(json); } }
private void ReceiveLoop() { StateObject state = new StateObject(); WFLogging.Info(" Starting receive loop"); state.workSocket = client; while (!finished) { // Start receive data from server while (client.Client.Available == 0) { Thread.Sleep(100); } state.offset = 0; client.Client.BeginReceive(state.buffer, 0, StateObject.bufsize, 0, new AsyncCallback(ReceiveCallback), state); receiveDone.WaitOne(); } // Wait for server to close connection WFLogging.Info(" Waiting for server close."); CloseDone.WaitOne(); client.Close(); Thread.Sleep(500); Started = false; }
internal static void LogPage(HttpListenerContext context) { byte[] page; // Process changes if (context.Request.ContentLength64 > 0) { int len = (int)context.Request.ContentLength64; byte[] post = new byte[1024]; context.Request.InputStream.Read(post, 0, len); string resp = Encoding.Default.GetString(post); resp = resp.Substring(0, len); foreach (string item in resp.Split('&')) { string[] pair = item.Split('='); switch (pair[0]) { case "sLogLevel": int l = 0; int.TryParse(pair[1], out l); if (l != WF_Config.LogLevel) { WF_Config.LogLevel = l; WFLogging.Level = (LOG_LEVELS)l; WeatherFlowNS.SaveConfiguration(); } break; case "Save": // Look up value of filename and save log to that file string fname = element(resp, "filename"); try { using (StreamWriter sw = new StreamWriter(fname)) { sw.Write(WFLogging.ToString()); } } catch (Exception ex) { WFLogging.Error(ex.Message); } break; case "Clear": WFLogging.Clear(); break; } } } page = ASCIIEncoding.ASCII.GetBytes(MakeLog()); context.Response.ContentType = "text/html"; context.Response.ContentLength64 = page.Length; context.Response.AddHeader("Date", DateTime.Now.ToString("r")); context.Response.StatusCode = (int)HttpStatusCode.OK; context.Response.OutputStream.Write(page, 0, page.Length); context.Response.OutputStream.Flush(); context.Response.OutputStream.Close(); context.Response.Close(); }
internal void REST_POST(string url, string content, int len) { HttpWebRequest request; HttpWebResponse response; string rest_url; int code; rest_url = Base + url; WFLogging.Debug(rest_url); request = (HttpWebRequest)HttpWebRequest.Create(rest_url); request.UserAgent = "WFNodeServer"; if (AuthRequired) { request.Headers.Add("Authorization", Authorize()); } request.Proxy = null; request.KeepAlive = false; request.Method = "POST"; request.ContentLength = len; request.ContentType = "application/xml"; Stream datastream = request.GetRequestStream(); datastream.Write(Encoding.ASCII.GetBytes(content), 0, len); datastream.Close(); try { response = (HttpWebResponse)request.GetResponse(); code = (int)response.StatusCode; response.Close(); } catch (Exception ex) { WFLogging.Error(ex.Message); } }
internal static void UploadFile(rest Rest, int profile, string resname, string type) { Assembly assembly; string resourceName; string contents = ""; // Load resource into string assembly = Assembly.GetExecutingAssembly(); resourceName = "WFNodeServer.nodesetup." + resname; using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { using (StreamReader reader = new StreamReader(stream)) { contents = reader.ReadToEnd(); } } if (contents.Length > 0) { // Send to ISY // This is just a http post to /rest/ns/profile/<profile>/upload/<type>/<filename> Rest.AuthRequired = true; try { Rest.REST_POST("ns/profile/" + profile.ToString() + "/upload/" + type + "/" + resname, contents, contents.Length); } catch (Exception ex) { WFLogging.Error(resname + " upload failed: " + ex.Message); } } }
internal bool GetStationMeta(string station_id) { string resp; RootObject root; JavaScriptSerializer serializer = new JavaScriptSerializer(); resp = WFRest.REST("/swd/rest/stations/" + station_id + "?api_key=6c8c96f9-e561-43dd-b173-5198d8797e0a"); if (resp == "") { return(false); } if (resp.Contains("ERROR")) { return(false); } if (resp != "") { try { root = serializer.Deserialize <RootObject>(resp); if (root.stations.Count == 0) { return(false); } Latitude = root.stations[0].latitude; Longitude = root.stations[0].longitude; //Console.WriteLine("latitude: " + root.stations[0].latitude.ToString()); //Console.WriteLine("longitude: " + root.stations[0].longitude.ToString()); //Console.WriteLine("elevation: " + root.stations[0].station_meta.elevation.ToString()); foreach (Device device in root.stations[0].devices) { // Types that we're interested in are: // SK - sky // AR - air //Console.WriteLine("Sensor: " + device.device_id.ToString() + " is " + device.device_type + " -agl = " + device.device_meta.agl.ToString()); if (device.device_type == "AR") { Elevation = root.stations[0].station_meta.elevation + device.device_meta.agl; Air = device.device_id; AirSN = device.serial_number; } else if (device.device_type == "SK") { Sky = device.device_id; SkySN = device.serial_number; } } } catch (Exception ex) { WFLogging.Error("Error: " + ex.Message); return(false); } } return(true); }
internal void StopListenRapid(string device_id) { string message = "{ \"type\":\"listen_rapid_stop\", \"device_id\":"; message += device_id; message += ", \"id\":\"random-id-23456\" }"; WFLogging.Info(" Stopping listen for device " + device_id); SendMessage(client, message, 0x01); }
internal void Start() { if (!Active) { WFLogging.Log("Starting WeatherFlow data collection thread."); udp_thread = new Thread(new ThreadStart(WeatherFlowThread)); udp_thread.IsBackground = true; udp_thread.Start(); } }
internal void Updated(string address, int timestamp, WeatherFlow_UDP.DataType t) { // Check for missing data here. UDPTime utime; TimeSpan epoch = DateTime.UtcNow - new DateTime(1970, 1, 1); utime.timestamp = timestamp; utime.now = (int)epoch.TotalSeconds; if (!SecondsSinceUpdate.ContainsKey(address)) { SecondsSinceUpdate[address] = utime; } // TODO: The diff should be 2x the interval. Is there some way to get that // information here? int diff = timestamp - SecondsSinceUpdate[address].timestamp; switch (t) { case WeatherFlow_UDP.DataType.AIR: case WeatherFlow_UDP.DataType.SKY: // Expect data every 60 seconds if (diff >= 120) { WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds"); } break; case WeatherFlow_UDP.DataType.DEVICE: // Expect data every 60 seconds if (diff >= 90) { WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds"); } break; case WeatherFlow_UDP.DataType.HUB: // Expect data every 10 seconds if (diff >= 20) { WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds"); } break; case WeatherFlow_UDP.DataType.WIND: // Expect data every 3 seconds if (diff >= 6) { WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds"); } break; } SecondsSinceUpdate[address] = utime; }
internal void StartListen(string device_id) { string message = "{ \"type\":\"listen_start\", \"device_id\":"; message += device_id; message += ", \"id\":\"random-id-23456\" }"; WFLogging.Info(" Starting listen for device " + device_id); SendMessage(client, message, 0x01); started.Add(device_id, true); }
internal void PrecipitationEvt(string json) { JavaScriptSerializer serializer = new JavaScriptSerializer(); try { // evt[0] = timestamp PreciptObj = serializer.Deserialize <PreciptData>(json); WeatherFlowNS.NS.RaiseRainEvent(this, new RainEventArgs(PreciptObj)); } catch (Exception ex) { WFLogging.Error("Failed to deserialize precipitation event: " + ex.Message); } }
private string MakeRequest(string rest_url) { HttpWebRequest request; HttpWebResponse response; int code; DateTime start = DateTime.Now; string xml = ""; request = (HttpWebRequest)HttpWebRequest.Create(rest_url); request.UserAgent = "WFNodeServer"; if (AuthRequired) { request.Headers.Add("Authorization", Authorize()); } request.Proxy = null; request.ServicePoint.ConnectionLimit = 10; request.Timeout = 4000; request.KeepAlive = true; //request.Pipelined = true; // Read data from the stream try { response = (HttpWebResponse)request.GetResponse(); code = (int)response.StatusCode; if (code != 200) { response.Close(); throw new RestException(code, response.StatusDescription); } if (response.ContentLength == 0) { return(""); } // sucess with content xml = ChunkedRead(response); response.Close(); } catch (WebException ex) { if (ex.Status == WebExceptionStatus.ProtocolError) { throw new RestException(400, ex.Message); } WFLogging.Error("GetResponse thew exception: " + ex.Status.ToString()); throw new RestException(0, ex.Message); } stats.RequestTime = DateTime.Now.Subtract(start).TotalMilliseconds; stats.Count++; return(xml); }
internal void LigtningStrikeEvt(string json) { JavaScriptSerializer serializer = new JavaScriptSerializer(); try { // evt[0] = timestamp // evt[1] = distance (km) // evt[2] = energy StrikeObj = serializer.Deserialize <StrikeData>(json); WeatherFlowNS.NS.RaiseLightningEvent(this, new LightningEventArgs(StrikeObj)); } catch (Exception ex) { WFLogging.Error("Failed to deserialize strike event: " + ex.Message); } }
// This is handling the SetParent service only at this point but could // be expanded to handle other ISY WSDL reuests if needed. internal void SendWSDLReqeust(string service, string parent, string node) { string url = "http://" + WF_Config.ISY + "/services"; HttpWebRequest request; HttpWebResponse response; string reqString = ""; reqString = "<? version=\'1.0\' encoding=\'utf-8\'?>"; reqString += "<s:Envelope>"; reqString += "<s:Body>"; reqString += "<u:" + service + " xmlns:u=\'urn:udi-com:service:X_Insteon_Lighting_Service:1\'>"; reqString += "<node>" + node + "</node>"; reqString += "<nodeType>1</nodeType>"; reqString += "<parent>" + parent + "</parent>"; reqString += "<parentType>1</parentType>"; reqString += "</u:" + service + ">"; reqString += "</s:Body>"; reqString += "</s:Envelope>"; reqString += "\r\n"; request = (HttpWebRequest)HttpWebRequest.Create(url); request.KeepAlive = true; request.Method = "POST"; request.ContentType = "text/xml; charset-utf-8"; request.Headers.Add("Authorization", Authorize()); request.Headers.Add("SOAPAction", "urn:udi-com:device:X_Insteon_Lighting_Service:1#" + service); Stream data = request.GetRequestStream(); data.Write(Encoding.ASCII.GetBytes(reqString), 0, reqString.Length); data.Flush(); data.Close(); response = (HttpWebResponse)request.GetResponse(); if (response.StatusCode == HttpStatusCode.OK) { WFLogging.Log("Grouped " + node + " as a child of " + parent); } else { WFLogging.Error("Group of " + node + " under " + parent + "failed: " + response.StatusDescription); } response.Close(); return; }
internal static void LogText(HttpListenerContext context) { byte[] page; page = ASCIIEncoding.ASCII.GetBytes(WFLogging.ToString()); context.Response.ContentType = "text/text"; context.Response.ContentLength64 = page.Length; context.Response.AddHeader("Date", DateTime.Now.ToString("r")); context.Response.StatusCode = (int)HttpStatusCode.OK; context.Response.OutputStream.Write(page, 0, page.Length); context.Response.OutputStream.Flush(); context.Response.OutputStream.Close(); context.Response.Close(); }
// // Given a REST partial URL, make the connection and return // the XML response // internal string REST(string url) { string rest_url; string resp = ""; rest_url = Base + url; if (rest_url == "") { WFLogging.Error("ISY REST called with missing URL."); WFLogging.Error(" Does this mean there's no connection to an ISY?"); return(""); } lock (RateLimit) { WFLogging.Debug(rest_url); int retrys = 0; while (retrys < 5) { try { resp = MakeRequest(rest_url); break; } catch (RestException re) { if (re.Code != 0) { WFLogging.Error("REST request " + url + " failed " + re.Message); break; } else { // Timeout or failed to get result retrys++; if (retrys == 5) { WFLogging.Error("REST request " + url + " failed after 5 retries with " + re.Message); } Thread.Sleep(50 * retrys); } } } } return(resp); }
internal static void callback(IAsyncResult result) { UdpClient u = (UdpClient)((UdpState)(result.AsyncState)).client; IPEndPoint e = (IPEndPoint)((UdpState)(result.AsyncState)).ep; Byte[] receiveBytes = u.EndReceive(result, ref e); string receiveString = Encoding.ASCII.GetString(receiveBytes); //Console.WriteLine("Received: {0}", receiveString); // Parse IP address / port from recieved text int i1 = receiveString.IndexOf("//"); int i2 = receiveString.IndexOf("/desc"); if (i1 > 0) { i1 += 2; ISYAddress = receiveString.Substring(i1, (i2 - i1)); } WFLogging.Log("Found ISY at " + ISYAddress); }
internal void Stop() { string message = "close"; WFLogging.Info(" Stop all listening."); foreach (string key in started.Keys) { StopListen(key); } started.Clear(); foreach (string key in started_rapid.Keys) { StopListenRapid(key); } started_rapid.Clear(); SendMessage(client, message, 0x08); finished = true; }
internal void Server() { Thread handleClient; TcpListener server = new TcpListener(IPAddress.Parse(Address), Port); server.Start(); WFLogging.Log("Logging server has started on port " + Port.ToString()); // Add a new log client to get new events and send over // the websocket. WFLogging.AddListener(WSLog); while (true) { WFLogging.Info("Waiting for log client to connect"); client = server.AcceptTcpClient(); handleClient = new Thread(() => ClientHandler(client)); handleClient.Start(); } }
private bool AddStation(station_form a_form) { wf_station station = new wf_station(api_key); if (station.GetStationMeta(a_form.station_id.ToString()) || (a_form.station_id == 0)) { a_form.air_id = (a_form.air_id == 0) ? station.Air : a_form.air_id; a_form.sky_id = (a_form.sky_id == 0) ? station.Sky : a_form.sky_id; a_form.air_sn = (a_form.air_sn == "") ? station.AirSN : a_form.air_sn; a_form.sky_sn = (a_form.sky_sn == "") ? station.SkySN : a_form.sky_sn; a_form.elevation = (a_form.elevation == 0) ? station.Elevation : a_form.elevation; WeatherFlowNS.NS.AddStation(a_form.station_id, a_form.elevation, a_form.air_id, a_form.sky_id, a_form.remote, station.AirSN, station.SkySN, a_form.rapid); return(true); } else { WFLogging.Error("Failed to find station " + a_form.station_id.ToString()); cfg_file_status = "Station " + a_form.station_id.ToString() + " lookup failed."; } return(false); }
internal void RapidWindEvt(string json) { JavaScriptSerializer serializer = new JavaScriptSerializer(); try { // evt[0] = timestamp // evt[1] = speed (m/s) // evt[2] = direction WindObj = serializer.Deserialize <WindData>(json); StationInfo si = wf_station.FindStationSky(WindObj.serial_number); if (si.rapid) { WeatherFlowNS.NS.RaiseRapidEvent(this, new RapidEventArgs(WindObj)); WeatherFlowNS.NS.RaiseUpdateEvent(this, new UpdateEventArgs((int)WindObj.ob[0], WindObj.serial_number + "_r", DataType.WIND)); } } catch (Exception ex) { WFLogging.Error("Failed to deserialize rapid wind event: " + ex.Message); WFLogging.Error(json); } }
private void Listen() { using (listener = new HttpListener()) { try { listener.Prefixes.Add("http://*:" + port.ToString() + "/"); listener.Start(); } catch (Exception ex) { WFLogging.Error("Failed to start web server on port " + port.ToString()); WFLogging.Error(" Error was: " + ex.Message); return; } while (true) { try { HttpListenerContext context = listener.GetContext(); Process(context); } catch (Exception ex) { WFLogging.Error("Failed to process connection: " + ex.Message); } //Thread.Sleep(5000); } } }
// TODO: // How do we want to handle the device status? There should // be at least 2 devices present (Air & Sky). Do we create // a HS record for each and use that as a place to store the // device specific data? Or do we just create an internal // list of devivces? // // Whatever we do here we should probably do for the hub // as well (treat it as a third device). private void DeviceStatus(string json) { JavaScriptSerializer serializer = new JavaScriptSerializer(); try { DeviceObj = serializer.Deserialize <DeviceData>(json); // Add event to update this info. try { WeatherFlowNS.NS.RaiseDeviceEvent(this, new WFNodeServer.DeviceEventArgs(DeviceObj)); } catch { WFLogging.Warning("Failed to process device event."); } WeatherFlowNS.NS.RaiseUpdateEvent(this, new UpdateEventArgs((int)DeviceObj.timestamp, DeviceObj.serial_number + "_d", DataType.DEVICE)); //Console.WriteLine("Serial Number: " + DeviceObj.serial_number); //Console.WriteLine("Device Type: " + DeviceObj.type); //Console.WriteLine("Hub Serial Number: " + DeviceObj.hub_sn); //Console.WriteLine("timestamp: " + DeviceObj.timestamp.ToString()); //Console.WriteLine("uptime: " + DeviceObj.uptime.ToString()); //Console.WriteLine("Voltage: " + DeviceObj.voltage.ToString()); //Console.WriteLine("Firmware: " + DeviceObj.firmware_revision.ToString()); //Console.WriteLine("RSSI: " + DeviceObj.rssi.ToString()); //Console.WriteLine("Sensor status: " + DeviceObj.sensor_status.ToString()); if (Sensors.ContainsKey(DeviceObj.serial_number)) { Sensors[DeviceObj.serial_number] = DeviceObj; } else { Sensors.Add(DeviceObj.serial_number, DeviceObj); } } catch (Exception ex) { WFLogging.Error("Deserialization of device status failed: " + ex.Message); } }
private void HubStatus(string json) { JavaScriptSerializer serializer = new JavaScriptSerializer(); try { HubObj = serializer.Deserialize <HubData>(json); WeatherFlowNS.NS.RaiseHubEvent(this, new WFNodeServer.HubEventArgs(HubObj)); WeatherFlowNS.NS.RaiseUpdateEvent(this, new UpdateEventArgs((int)HubObj.timestamp, HubObj.serial_number, DataType.HUB)); //Console.WriteLine("Serial Number: " + HubObj.serial_number); //Console.WriteLine("Device Type: " + HubObj.type); //Console.WriteLine("Firmware: " + HubObj.firmware_revision.ToString()); //Console.WriteLine("uptime: " + HubObj.uptime.ToString()); //Console.WriteLine("RSSI: " + HubObj.rssi.ToString()); //Console.WriteLine("timestamp: " + HubObj.timestamp.ToString()); //Console.WriteLine("Reset Flags: " + HubObj.reset_flags); //Console.WriteLine("Stack: " + HubObj.stack); //Console.WriteLine("Sequence: " + HubObj.seq.ToString()); //Console.WriteLine("External File: " + HubObj.fs.ToString()); ValidHub = true; } catch (Exception ex) { WFLogging.Error("Deserialization of device status failed: " + ex.Message); } }
private void SkyObservations(string json) { JavaScriptSerializer serializer = new JavaScriptSerializer(); try { SkyObj = serializer.Deserialize <SkyData>(json); SkyObj.valid = true; WFNodeServer.SkyEventArgs evnt = new SkyEventArgs(SkyObj); evnt.SetDaily = CalcDailyPrecipitation(); evnt.Raw = json; try { WeatherFlowNS.NS.RaiseSkyEvent(this, evnt); } catch (Exception ex) { WFLogging.Warning("Failed to process Sky event. " + ex.Message); } WeatherFlowNS.NS.RaiseUpdateEvent(this, new UpdateEventArgs((int)SkyObj.obs[0][0].GetValueOrDefault(), SkyObj.serial_number, DataType.SKY)); } catch (Exception ex) { WFLogging.Error("Deserialization failed for sky data: " + ex.Message); WFLogging.Verbose(json); return; } }
// Look for UPNP broadcast messages from an ISY. If it finds // one, then use it. // // FIXME: How do we know this is the right ISY? What if there // is more than one on the network? internal static string IsyAutoDetect() { UdpClient listen_udp; IPAddress group_ip; IPEndPoint group_ep; string ip = ""; byte[] recv_data; int i; string buf = ""; int tries = 100; using (listen_udp = new UdpClient()) { listen_udp.ExclusiveAddressUse = false; listen_udp.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); group_ip = IPAddress.Parse("239.255.255.250"); //group_ep = new IPEndPoint(IPAddress.Any, 1900); group_ep = new IPEndPoint(IPAddress.Any, 20034); try { listen_udp.Client.Bind(group_ep); } catch (Exception e) { WFLogging.Error("Failed to bind to broadcast address"); WFLogging.Error(e.Message); return(""); } listen_udp.EnableBroadcast = true; try { listen_udp.JoinMulticastGroup(group_ip); } catch (Exception e) { WFLogging.Error("Failed to join Multicast group: " + e.Message); //listen_udp.Close(); return(""); } // Set the timeout at 90 seconds. If we haven't received anything in // that time, we probably won't. listen_udp.Client.ReceiveTimeout = 90000; while ((ip == "")) { try { recv_data = listen_udp.Receive(ref group_ep); } catch { WFLogging.Error("Timed out trying to discover ISY."); return(""); } if (recv_data.Length != 0) { // Found somelthing buf = Encoding.ASCII.GetString(recv_data); // Now see if this is really an ISY if (buf.Contains("X_Insteon") == false) { if (--tries == 0) { WFLogging.Error("Failed to detect ISY on the network."); return(""); } } else { // This really is an ISY. Pull the location field // from the string. i = buf.IndexOf("LOCATION:"); if ((i > 0)) { ip = buf.Substring((i + 9)).Split('\r')[0]; } } } } listen_udp.DropMulticastGroup(group_ip); //listen_udp.Close(); } WFLogging.Log(("Found an ISY: " + ip)); return(ip); }
// handle a client connection private void ClientHandler(TcpClient client) { Byte[] bytes; NetworkStream stream = client.GetStream(); WFLogging.Info("Log client connected."); // Wait for data to be available while (!stream.DataAvailable) { ; } bytes = new Byte[client.Available]; stream.Read(bytes, 0, bytes.Length); //translate bytes of request to string String data = Encoding.UTF8.GetString(bytes); byte[] response = null; const string eol = "\r\n"; // HTTP/1.1 defines the sequence CR LF as the end-of-line marker WFLogging.Debug("GOT:" + bytes.Length.ToString() + ": " + data); if (new System.Text.RegularExpressions.Regex("^GET").IsMatch(data)) { } string protocol = new System.Text.RegularExpressions.Regex("Sec-WebSocket-Protocol: (.*)").Match(data).Groups[1].Value.Trim(); Console.WriteLine("Protocol: " + protocol); int l = bytes.Length; if (bytes[l - 1] == '\n' && bytes[l - 2] == '\r' && bytes[l - 3] == '\n') { response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + eol + "Upgrade: websocket" + eol + "Connection: Upgrade" + eol + "Sec-WebSocket-Protocol: " + protocol + eol + "Sec-WebSocket-Accept: " + Convert.ToBase64String( System.Security.Cryptography.SHA1.Create().ComputeHash( Encoding.UTF8.GetBytes( new System.Text.RegularExpressions.Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ) ) ) + eol + eol); stream.Write(response, 0, response.Length); stream.Flush(); WFLogging.Debug(Encoding.ASCII.GetString(response)); } else { // What do we do here if we don't get a proper header (or complete header)? WFLogging.Info("Didn't get a proper header, closing connection"); client.Close(); return; } // Start sending the log. // Only send the most recent 500 lines of data because sending more // here makes the interface unresponse for too long while it processes // it all. int start = (WFLogging.EventLogCount > 500) ? (WFLogging.EventLogCount - 500) : 0; for (int i = start; i < WFLogging.EventLogCount; i++) { string[] e = WFLogging.GetEvent(i); try { SendMessage(client, e[0] + "\t" + e[1], 0x01); } catch { // Sending to client failed for some reason. So abort. client.Close(); return; } } // Push the client to the client list clients.Add(client); // Handle data comming in over the connection. Mainly we want to // check for a close connection frame. If we get a close frame // then close the connection. while (stream.DataAvailable) { bytes = new Byte[client.Available]; stream.Read(bytes, 0, bytes.Length); // Data from client that needs to be decoded? WFLogging.Debug("Got " + bytes.Length.ToString() + " bytes from client to decode"); if ((bytes[0] & 0x80) == 0x80) { int payload_type = bytes[0] & 0x0f; int payload_size = bytes[1] & 0x7f; int payload_masking = bytes[1] & 0x80; WFLogging.Debug("type = " + payload_type.ToString() + " mask = " + payload_masking.ToString() + " len = " + payload_size.ToString()); if (payload_size < 126) { if (payload_masking == 0x80) { byte[] mask = new byte[4]; mask[0] = bytes[2]; mask[1] = bytes[3]; mask[2] = bytes[4]; mask[3] = bytes[5]; for (int i = 0; i < payload_size; i++) { bytes[6 + i] = (byte)(bytes[6 + i] ^ mask[i % 4]); } WFLogging.Debug("Payload: " + Encoding.ASCII.GetString(bytes, 6, payload_size)); } else { //for (int i = 0; i < payload_size; i++) // state.buffer[2+i] = (byte)(state.buffer[2+i] ^ 0x10); WFLogging.Debug("Payload: " + Encoding.ASCII.GetString(bytes, 2, payload_size)); } } else { WFLogging.Debug("Extended size: " + payload_size.ToString()); } switch (payload_type) { case 0x01: // text payload Console.WriteLine("Got a text payload"); break; case 0x02: // binary payload Console.WriteLine("Got a binary payload"); break; case 0x0A: // Pong break; case 0x09: // Ping // Send a pong message back Console.WriteLine("Received ping frame, should send a pong"); break; case 0x08: // close connection Console.WriteLine("Received close frame, closing connection"); clients.Remove(client); client.Close(); return; } } else { WFLogging.Debug("Non Frame: " + Encoding.ASCII.GetString(bytes, 0, bytes.Length)); } } }
internal void Start() { byte[] buf = new byte[512]; int len; bool header = false; while (Started) { int retries = 0; WFLogging.Warning("Attempt to start already active WebSocket connection " + retries.ToString()); Thread.Sleep(1000); if (retries++ > 10) { WFLogging.Error("Giving up after 10 attempts."); return; } } client = new TcpClient(Host, Port); if (!client.Connected) { WFLogging.Error("Client not connected to " + Port); } WFLogging.Log("Starting communication with websocket server."); finished = false; Started = true; // Send header var seckeybytes = Encoding.UTF8.GetBytes(seckey); client.Client.Send(Encoding.ASCII.GetBytes("GET " + Path + " HTTP/1.1\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Host: " + Host + ":" + Port.ToString() + "\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Upgrade: websocket\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Connection: Upgrade\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Pragma: no-cache\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Origin: http://" + Host + "\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Cache-Control: no-cache\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Sec-WebSocket-Key: " + System.Convert.ToBase64String(seckeybytes) + "\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("Sec-WebSocket-Version: 13\r\n")); client.Client.Send(Encoding.ASCII.GetBytes("\r\n")); WFLogging.Info(" Waiting for handshake"); Thread.Sleep(100); // Receive handshake while (!header) { if (client.Client.Available > 0) { len = client.Client.Receive(buf, (client.Client.Available - 1), SocketFlags.None); if (len > 0) { string strbuf = Encoding.ASCII.GetString(buf, 0, len); // Just look for the a websock type response, ignore the rest of the headers if (strbuf.Contains("HTTP/1.1 101")) { header = true; } } } Thread.Sleep(500); } receive_thread = new Thread(new ThreadStart(ReceiveLoop)); receive_thread.IsBackground = true; receive_thread.Start(); }
private static void ReceiveCallback(IAsyncResult ar) { StateObject state = (StateObject)ar.AsyncState; TcpClient client = state.workSocket; int bytes_read = client.Client.EndReceive(ar); if (bytes_read > 0) { int bi = 0; byte[] mask = new byte[4]; if ((state.buffer[0] & 0x80) == 0x80) { int payload_type = state.buffer[0] & 0x0f; int payload_size = state.buffer[1] & 0x7f; int payload_masking = state.buffer[1] & 0x80; bi += 2; //Console.WriteLine("type = " + payload_type.ToString() + " mask = " + payload_masking.ToString() + " len = " + payload_size.ToString()); if (payload_size == 126) { payload_size = (state.buffer[bi++] << 8) + state.buffer[bi++]; //Console.WriteLine("extended size = " + payload_size.ToString()); } if (payload_masking == 0x80) { mask[0] = state.buffer[bi++]; mask[1] = state.buffer[bi++]; mask[2] = state.buffer[bi++]; mask[3] = state.buffer[bi++]; } if (bytes_read > payload_size) { for (int i = 0; i < payload_size; i++) { if (payload_masking == 0x80) { state.buffer[bi + i] = (byte)(state.buffer[bi + i] ^ mask[i % 4]); } } if (payload_type == 0x01) { // TODO: Text type payload so send it somewhere //Console.WriteLine("Payload: " + Encoding.ASCII.GetString(state.buffer, bi, payload_size)); //Program.RaiseEvent(new WSEventArgs(Encoding.ASCII.GetString(state.buffer, bi, payload_size))); ProcessWSData(Encoding.ASCII.GetString(state.buffer, bi, payload_size)); } else if (payload_type == 0x02) { // Binary payload } else if (payload_type == 0x00) { WFLogging.Error("Got a continuation opcode, currently not supported."); } else if (payload_type == 0x08) { // Close frame finished = true; SendMessage(client, Encoding.ASCII.GetString(state.buffer, bi, payload_size), 0x08); } else if (payload_type == 0x09) { // Ping so we need to pong SendMessage(client, Encoding.ASCII.GetString(state.buffer, bi, payload_size), 0x0A); } receiveDone.Set(); return; } else { // We need to read more data WFLogging.Info("Need more data to complete frame"); client.Client.BeginReceive(state.buffer, 0, StateObject.bufsize, 0, new AsyncCallback(ReceiveCallback), state); return; } } } receiveDone.Set(); }