Socket.io handshake with PHP websocket? - ios

I'm using a PHP web socket on my server side. I'm currently only testing the connection between the client and the server, so I haven't configured the socket yet to respond to specific events. This is what the basic template looks like:
#!/php -q
<?php /* >php -q server.php */
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
$master = WebSocket("example.com",8080);
$sockets = array($master);
$users = array();
$debug = false;
while(true){
$changed = $sockets;
socket_select($changed,$write=NULL,$except=NULL,NULL);
foreach($changed as $socket){
if($socket==$master){
$client=socket_accept($master);
if($client<0){ console("socket_accept() failed"); continue; }
else{ connect($client); }
}
else{
$bytes = #socket_recv($socket,$buffer,2048,0);
if($bytes==0){ disconnect($socket); }
else{
$user = getuserbysocket($socket);
if(!$user->handshake){ dohandshake($user,$buffer); }
else{ process($user,$buffer); }
}
}
}
}
//---------------------------------------------------------------
function process($user,$msg){
$action = unwrap($msg);
say("< ".$action);
switch($action){
case "hello" : send($user->socket,"hello human"); break;
case "hi" : send($user->socket,"zup human"); break;
case "name" : send($user->socket,"my name is Multivac, silly I know"); break;
case "age" : send($user->socket,"I am older than time itself"); break;
case "date" : send($user->socket,"today is ".date("Y.m.d")); break;
case "time" : send($user->socket,"server time is ".date("H:i:s")); break;
case "thanks": send($user->socket,"you're welcome"); break;
case "bye" : send($user->socket,"bye"); break;
default : send($user->socket,$action." not understood"); break;
}
}
function send($client,$msg){
say("> ".$msg);
$msg = wrap($msg);
socket_write($client,$msg,strlen($msg));
}
function WebSocket($address,$port){
$master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
socket_bind($master, $address, $port) or die("socket_bind() failed");
socket_listen($master,20) or die("socket_listen() failed");
echo "Server Started : ".date('Y-m-d H:i:s')."\n";
echo "Master socket : ".$master."\n";
echo "Listening on : ".$address." port ".$port."\n\n";
return $master;
}
function connect($socket){
global $sockets,$users;
$user = new User();
$user->id = uniqid();
$user->socket = $socket;
array_push($users,$user);
array_push($sockets,$socket);
console($socket." CONNECTED!");
}
function disconnect($socket){
global $sockets,$users;
$found=null;
$n=count($users);
for($i=0;$i<$n;$i++){
if($users[$i]->socket==$socket){ $found=$i; break; }
}
if(!is_null($found)){ array_splice($users,$found,1); }
$index = array_search($socket,$sockets);
socket_close($socket);
console($socket." DISCONNECTED!");
if($index>=0){ array_splice($sockets,$index,1); }
}
function dohandshake($user,$buffer){
console("\nRequesting handshake...");
console($buffer);
list($resource,$host,$origin,$strkey1,$strkey2,$data) = getheaders($buffer);
console("Handshaking...");
$pattern = '/[^\d]*/';
$replacement = '';
$numkey1 = preg_replace($pattern, $replacement, $strkey1);
$numkey2 = preg_replace($pattern, $replacement, $strkey2);
$pattern = '/[^ ]*/';
$replacement = '';
$spaces1 = strlen(preg_replace($pattern, $replacement, $strkey1));
$spaces2 = strlen(preg_replace($pattern, $replacement, $strkey2));
if ($spaces1 == 0 || $spaces2 == 0 || $numkey1 % $spaces1 != 0 || $numkey2 % $spaces2 != 0) {
socket_close($user->socket);
console('failed');
return false;
}
$ctx = hash_init('md5');
hash_update($ctx, pack("N", $numkey1/$spaces1));
hash_update($ctx, pack("N", $numkey2/$spaces2));
hash_update($ctx, $data);
$hash_data = hash_final($ctx,true);
$upgrade = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" .
"Upgrade: WebSocket\r\n" .
"Connection: Upgrade\r\n" .
"Sec-WebSocket-Origin: " . $origin . "\r\n" .
"Sec-WebSocket-Location: ws://" . $host . $resource . "\r\n" .
"\r\n" .
$hash_data;
socket_write($user->socket,$upgrade.chr(0),strlen($upgrade.chr(0)));
$user->handshake=true;
console($upgrade);
console("Done handshaking...");
return true;
}
function getheaders($req){
$r=$h=$o=null;
if(preg_match("/GET (.*) HTTP/" ,$req,$match)){ $r=$match[1]; }
if(preg_match("/Host: (.*)\r\n/" ,$req,$match)){ $h=$match[1]; }
if(preg_match("/Origin: (.*)\r\n/",$req,$match)){ $o=$match[1]; }
if(preg_match("/Sec-WebSocket-Key2: (.*)\r\n/",$req,$match)){ $key2=$match[1]; }
if(preg_match("/Sec-WebSocket-Key1: (.*)\r\n/",$req,$match)){ $key1=$match[1]; }
if(preg_match("/\r\n(.*?)\$/",$req,$match)){ $data=$match[1]; }
return array($r,$h,$o,$key1,$key2,$data);
}
function getuserbysocket($socket){
global $users;
$found=null;
foreach($users as $user){
if($user->socket==$socket){ $found=$user; break; }
}
return $found;
}
function say($msg=""){ echo $msg."\n"; }
function wrap($msg=""){ return chr(0).$msg.chr(255); }
function unwrap($msg=""){ return substr($msg,1,strlen($msg)-2); }
function console($msg=""){ global $debug; if($debug){ echo $msg."\n"; } }
class User{
var $id;
var $socket;
var $handshake;
}
?>
And I want to connect to this socket from my Swift client with Socket.io:
let io:SocketIOClient = SocketIOClient(socketURL: URL(string: "example.com:8080/server.php")!, config: [.log(true), .compress])
override func viewDidLoad() {
super.viewDidLoad()
self.io.on(clientEvent: .connect) { (data:[Any], ack:SocketAckEmitter) in
NSLog("Socket connected!")
}
self.io.on(clientEvent: .disconnect) { (data:[Any], ack:SocketAckEmitter) in
NSLog("Socket disconnected!")
}
self.io.connect()
}
I'm running the server on my Mac's Terminal with SSH. The PHP web socket says it's listening for connections, but it doesn't respond to the socket.io connecting. The server nor the client is giving me any errors, so I'm assuming I missed a crucial step in the connection process. I was wondering if it's possible to perform a handshake with the Socket.IO swift client when you're trying to connect to a PHP web socket. Is this a compatibility issue or am I just forgetting something? By the way, by now you may have noticed I'm very new to web socket programming (I found out about websockets less than a week ago), so please excuse me if this is a really noob question. I appreciate any help I can get. Thank you!

socket.io != webSocket. You can't connect a socket.io client to a webSocket server. Socket.io adds its own protocol on top of a webSocket. While socket.io uses a webSocket transport under the covers, the client will fail to connect if you only have a webSocket server.
You must connect a webSocket client to a webSocket server. Or, connect a socket.io client to a socket.io server.
So, in your case, if you have a socket.io client, then you need to get a socket.io server for your server environment and use that instead.

Related

WS Mqtt with mqttws31.js don't receive messages

i am need one help. i make a broker with node red and i am using mqtt ws. I tested in Hivemq website and all works good, but in my website i do publish only, and nothing received. i am using mqttws31.js. in my javascript console show conected, and i can publish but never read. Somebody help me? bellow my code. sorry for my english.\
var mqtt;
var reconnectTimeout = 2000;
var host="my_broker"; //change this
var port=9001;
function onFailure(msg) {
alert(msg);
console.log("Connection Attempt to Host "+host+"Failed");
setTimeout(MQTTconnect, reconnectTimeout);
}
function onMessageArrived(msg){
out_msg="Message received "+ msg.payloadString+"<br>";
out_msg=out_msg+"Message received Topic "+msg.destinationName;
console.log(out_msg);
document.write(msg.payloadString);
// funcoes executar
if (msg.destinationName == "voltas") {
// Temperatura
alert(msg.payloadString);
}
}
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("Connected ");
}
function MQTTconnect() {
//console.log("connecting to "+ host +" "+ port);
var x=Math.floor(Math.random() * 10000);
var cname="orderform-"+x;
mqtt = new Paho.MQTT.Client(host,port,cname);
//document.write("connecting to "+ host);
var options = {
timeout: 3,
onSuccess: onConnect,
onFailure: onFailure,
};
mqtt.onMessageArrived = onMessageArrived
mqtt.connect(options); //connect
}

Having trouble decrypting HTTPS traffic from IOS using FiddlerCore

I was able to run the FiddlerCore demo (that comes with the package) without issue. I see both http and https traffic being logged on my PC.
My goal now is to do the same for my iOS traffic but I can't figure out what I am missing. I can see my https traffic fine when I use the desktop Fiddler app, by following the instructions at ConfigureForiOS.
I run the console FiddlerCore demo, hit 't' to trust the root certificate and then try to follow the same steps on my iPhone as I did for the Fidder app, namely setting my proxy to the Fiddler instance (my machine's IP and port 7777 as that is what it looks like the demo is using) and trusting the Fiddler cert that I had already installed on my phone when setting it up to work with the desktop Fiddler app. Then when I try to start an app on my phone that goes over https (for example a game) it just hangs. I don't see any errors being logged in the console app. It works ok when just running the desktop Fiddler app.
My SSL/cert/Fiddler knowledge is weak so I am hoping I am just missing a simple step or two.
Questions:
How can I capture iOS HTTPS traffic using the FiddlerCore demo app?
Do I need to trust the root certificate each time I start the demo
app (hitting 't')?
Thanks.
P.S. I added the demo app here, which can be found in the FiddlerCore package, for reference.
using Fiddler;
using System;
using System.Collections.Generic;
using System.Threading;
namespace FiddlerCoreDemo
{
class Program
{
static Proxy oSecureEndpoint;
static string sSecureEndpointHostname = "localhost";
static int iSecureEndpointPort = 7777;
public static void WriteCommandResponse(string s)
{
ConsoleColor oldColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(s);
Console.ForegroundColor = oldColor;
}
public static void DoQuit()
{
WriteCommandResponse("Shutting down...");
if (null != oSecureEndpoint) oSecureEndpoint.Dispose();
Fiddler.FiddlerApplication.Shutdown();
Thread.Sleep(500);
}
private static string Ellipsize(string s, int iLen)
{
if (s.Length <= iLen) return s;
return s.Substring(0, iLen - 3) + "...";
}
#if SAZ_SUPPORT
private static void ReadSessions(List<Fiddler.Session> oAllSessions)
{
Session[] oLoaded = Utilities.ReadSessionArchive(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
+ Path.DirectorySeparatorChar + "ToLoad.saz", false);
if ((oLoaded != null) && (oLoaded.Length > 0))
{
oAllSessions.AddRange(oLoaded);
WriteCommandResponse("Loaded: " + oLoaded.Length + " sessions.");
}
}
private static void SaveSessionsToDesktop(List<Fiddler.Session> oAllSessions)
{
bool bSuccess = false;
string sFilename = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
+ Path.DirectorySeparatorChar + DateTime.Now.ToString("hh-mm-ss") + ".saz";
try
{
try
{
Monitor.Enter(oAllSessions);
string sPassword = null;
Console.WriteLine("Password Protect this Archive (Y/N)?");
ConsoleKeyInfo oCKI = Console.ReadKey();
if ((oCKI.KeyChar == 'y') || (oCKI.KeyChar == 'Y'))
{
Console.WriteLine("\nEnter the password:");
sPassword = Console.ReadLine();
Console.WriteLine(String.Format("\nEncrypting with Password: '{0}'", sPassword));
}
Console.WriteLine();
bSuccess = Utilities.WriteSessionArchive(sFilename, oAllSessions.ToArray(), sPassword, false);
}
finally
{
Monitor.Exit(oAllSessions);
}
WriteCommandResponse( bSuccess ? ("Wrote: " + sFilename) : ("Failed to save: " + sFilename) );
}
catch (Exception eX)
{
Console.WriteLine("Save failed: " + eX.Message);
}
}
#endif
private static void WriteSessionList(List<Fiddler.Session> oAllSessions)
{
ConsoleColor oldColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Session list contains...");
try
{
Monitor.Enter(oAllSessions);
foreach (Session oS in oAllSessions)
{
Console.Write(String.Format("{0} {1} {2}\n{3} {4}\n\n", oS.id, oS.oRequest.headers.HTTPMethod, Ellipsize(oS.fullUrl, 60), oS.responseCode, oS.oResponse.MIMEType));
}
}
finally
{
Monitor.Exit(oAllSessions);
}
Console.WriteLine();
Console.ForegroundColor = oldColor;
}
static void Main(string[] args)
{
List<Fiddler.Session> oAllSessions = new List<Fiddler.Session>();
// <-- Personalize for your Application, 64 chars or fewer
Fiddler.FiddlerApplication.SetAppDisplayName("FiddlerCoreDemoApp");
#region AttachEventListeners
//
// It is important to understand that FiddlerCore calls event handlers on session-handling
// background threads. If you need to properly synchronize to the UI-thread (say, because
// you're adding the sessions to a list view) you must call .Invoke on a delegate on the
// window handle.
//
// If you are writing to a non-threadsafe data structure (e.g. List<t>) you must
// use a Monitor or other mechanism to ensure safety.
//
// Simply echo notifications to the console. Because Fiddler.CONFIG.QuietMode=true
// by default, we must handle notifying the user ourselves.
Fiddler.FiddlerApplication.OnNotification += delegate (object sender, NotificationEventArgs oNEA) { Console.WriteLine("** NotifyUser: " + oNEA.NotifyString); };
Fiddler.FiddlerApplication.Log.OnLogString += delegate (object sender, LogEventArgs oLEA) { Console.WriteLine("** LogString: " + oLEA.LogString); };
Fiddler.FiddlerApplication.BeforeRequest += delegate (Fiddler.Session oS)
{
// Console.WriteLine("Before request for:\t" + oS.fullUrl);
// In order to enable response tampering, buffering mode MUST
// be enabled; this allows FiddlerCore to permit modification of
// the response in the BeforeResponse handler rather than streaming
// the response to the client as the response comes in.
oS.bBufferResponse = false;
Monitor.Enter(oAllSessions);
oAllSessions.Add(oS);
Monitor.Exit(oAllSessions);
// Set this property if you want FiddlerCore to automatically authenticate by
// answering Digest/Negotiate/NTLM/Kerberos challenges itself
// oS["X-AutoAuth"] = "(default)";
/* If the request is going to our secure endpoint, we'll echo back the response.
Note: This BeforeRequest is getting called for both our main proxy tunnel AND our secure endpoint,
so we have to look at which Fiddler port the client connected to (pipeClient.LocalPort) to determine whether this request
was sent to secure endpoint, or was merely sent to the main proxy tunnel (e.g. a CONNECT) in order to *reach* the secure endpoint.
As a result of this, if you run the demo and visit https://localhost:7777 in your browser, you'll see
Session list contains...
1 CONNECT http://localhost:7777
200 <-- CONNECT tunnel sent to the main proxy tunnel, port 8877
2 GET https://localhost:7777/
200 text/html <-- GET request decrypted on the main proxy tunnel, port 8877
3 GET https://localhost:7777/
200 text/html <-- GET request received by the secure endpoint, port 7777
*/
if ((oS.oRequest.pipeClient.LocalPort == iSecureEndpointPort) && (oS.hostname == sSecureEndpointHostname))
{
oS.utilCreateResponseAndBypassServer();
oS.oResponse.headers.SetStatus(200, "Ok");
oS.oResponse["Content-Type"] = "text/html; charset=UTF-8";
oS.oResponse["Cache-Control"] = "private, max-age=0";
oS.utilSetResponseBody("<html><body>Request for httpS://" + sSecureEndpointHostname + ":" + iSecureEndpointPort.ToString() + " received. Your request was:<br /><plaintext>" + oS.oRequest.headers.ToString());
}
};
/*
// The following event allows you to examine every response buffer read by Fiddler. Note that this isn't useful for the vast majority of
// applications because the raw buffer is nearly useless; it's not decompressed, it includes both headers and body bytes, etc.
//
// This event is only useful for a handful of applications which need access to a raw, unprocessed byte-stream
Fiddler.FiddlerApplication.OnReadResponseBuffer += new EventHandler<RawReadEventArgs>(FiddlerApplication_OnReadResponseBuffer);
*/
/*
Fiddler.FiddlerApplication.BeforeResponse += delegate(Fiddler.Session oS) {
// Console.WriteLine("{0}:HTTP {1} for {2}", oS.id, oS.responseCode, oS.fullUrl);
// Uncomment the following two statements to decompress/unchunk the
// HTTP response and subsequently modify any HTTP responses to replace
// instances of the word "Microsoft" with "Bayden". You MUST also
// set bBufferResponse = true inside the beforeREQUEST method above.
//
//oS.utilDecodeResponse(); oS.utilReplaceInResponse("Microsoft", "Bayden");
};*/
Fiddler.FiddlerApplication.AfterSessionComplete += delegate (Fiddler.Session oS)
{
//Console.WriteLine("Finished session:\t" + oS.fullUrl);
Console.Title = ("Session list contains: " + oAllSessions.Count.ToString() + " sessions");
};
// Tell the system console to handle CTRL+C by calling our method that
// gracefully shuts down the FiddlerCore.
//
// Note, this doesn't handle the case where the user closes the window with the close button.
// See http://geekswithblogs.net/mrnat/archive/2004/09/23/11594.aspx for info on that...
//
Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
#endregion AttachEventListeners
string sSAZInfo = "NoSAZ";
#if SAZ_SUPPORT
sSAZInfo = Assembly.GetAssembly(typeof(Ionic.Zip.ZipFile)).FullName;
// You can load Transcoders from any different assembly if you'd like, using the ImportTranscoders(string AssemblyPath)
// overload.
//
//if (!FiddlerApplication.oTranscoders.ImportTranscoders(Assembly.GetExecutingAssembly()))
//{
// Console.WriteLine("This assembly was not compiled with a SAZ-exporter");
//}
DNZSAZProvider.fnObtainPwd = () =>
{
Console.WriteLine("Enter the password (or just hit Enter to cancel):");
string sResult = Console.ReadLine();
Console.WriteLine();
return sResult;
};
FiddlerApplication.oSAZProvider = new DNZSAZProvider();
#endif
Console.WriteLine(String.Format("Starting {0} ({1})...", Fiddler.FiddlerApplication.GetVersionString(), sSAZInfo));
// For the purposes of this demo, we'll forbid connections to HTTPS
// sites that use invalid certificates. Change this from the default only
// if you know EXACTLY what that implies.
Fiddler.CONFIG.IgnoreServerCertErrors = false;
// ... but you can allow a specific (even invalid) certificate by implementing and assigning a callback...
// FiddlerApplication.OnValidateServerCertificate += new System.EventHandler<ValidateServerCertificateEventArgs>(CheckCert);
FiddlerApplication.Prefs.SetBoolPref("fiddler.network.streaming.abortifclientaborts", true);
// For forward-compatibility with updated FiddlerCore libraries, it is strongly recommended that you
// start with the DEFAULT options and manually disable specific unwanted options.
FiddlerCoreStartupFlags oFCSF = FiddlerCoreStartupFlags.Default;
// E.g. If you want to add a flag, start with the .Default and "OR" the new flag on:
// oFCSF = (oFCSF | FiddlerCoreStartupFlags.CaptureFTP);
// ... or if you don't want a flag in the defaults, "and not" it out:
// Uncomment the next line if you don't want FiddlerCore to act as the system proxy
// oFCSF = (oFCSF & ~FiddlerCoreStartupFlags.RegisterAsSystemProxy);
// *******************************
// Important HTTPS Decryption Info
// *******************************
// When FiddlerCoreStartupFlags.DecryptSSL is enabled, you must include either
//
// MakeCert.exe
//
// *or*
//
// CertMaker.dll
// BCMakeCert.dll
//
// ... in the folder where your executable and FiddlerCore.dll live. These files
// are needed to generate the self-signed certificates used to man-in-the-middle
// secure traffic. MakeCert.exe uses Windows APIs to generate certificates which
// are stored in the user's \Personal\ Certificates store. These certificates are
// NOT compatible with iOS devices which require specific fields in the certificate
// which are not set by MakeCert.exe.
//
// In contrast, CertMaker.dll uses the BouncyCastle C# library (BCMakeCert.dll) to
// generate new certificates from scratch. These certificates are stored in memory
// only, and are compatible with iOS devices.
// Uncomment the next line if you don't want to decrypt SSL traffic.
// oFCSF = (oFCSF & ~FiddlerCoreStartupFlags.DecryptSSL);
// NOTE: In the next line, you can pass 0 for the port (instead of 8877) to have FiddlerCore auto-select an available port
int iPort = 8877;
Fiddler.FiddlerApplication.Startup(iPort, oFCSF);
FiddlerApplication.Log.LogFormat("Created endpoint listening on port {0}", iPort);
FiddlerApplication.Log.LogFormat("Starting with settings: [{0}]", oFCSF);
FiddlerApplication.Log.LogFormat("Gateway: {0}", CONFIG.UpstreamGateway.ToString());
Console.WriteLine("Hit CTRL+C to end session.");
// We'll also create a HTTPS listener, useful for when FiddlerCore is masquerading as a HTTPS server
// instead of acting as a normal CERN-style proxy server.
oSecureEndpoint = FiddlerApplication.CreateProxyEndpoint(iSecureEndpointPort, true, sSecureEndpointHostname);
if (null != oSecureEndpoint)
{
FiddlerApplication.Log.LogFormat("Created secure endpoint listening on port {0}, using a HTTPS certificate for '{1}'", iSecureEndpointPort, sSecureEndpointHostname);
}
bool bDone = false;
do
{
Console.WriteLine("\nEnter a command [C=Clear; L=List; G=Collect Garbage; W=write SAZ; R=read SAZ;\n\tS=Toggle Forgetful Streaming; T=Trust Root Certificate; Q=Quit]:");
Console.Write(">");
ConsoleKeyInfo cki = Console.ReadKey();
Console.WriteLine();
switch (Char.ToLower(cki.KeyChar))
{
case 'c':
Monitor.Enter(oAllSessions);
oAllSessions.Clear();
Monitor.Exit(oAllSessions);
WriteCommandResponse("Clear...");
FiddlerApplication.Log.LogString("Cleared session list.");
break;
case 'd':
FiddlerApplication.Log.LogString("FiddlerApplication::Shutdown.");
FiddlerApplication.Shutdown();
break;
case 'l':
WriteSessionList(oAllSessions);
break;
case 'g':
Console.WriteLine("Working Set:\t" + Environment.WorkingSet.ToString("n0"));
Console.WriteLine("Begin GC...");
GC.Collect();
Console.WriteLine("GC Done.\nWorking Set:\t" + Environment.WorkingSet.ToString("n0"));
break;
case 'q':
bDone = true;
DoQuit();
break;
case 'r':
#if SAZ_SUPPORT
ReadSessions(oAllSessions);
#else
WriteCommandResponse("This demo was compiled without SAZ_SUPPORT defined");
#endif
break;
case 'w':
#if SAZ_SUPPORT
if (oAllSessions.Count > 0)
{
SaveSessionsToDesktop(oAllSessions);
}
else
{
WriteCommandResponse("No sessions have been captured");
}
#else
WriteCommandResponse("This demo was compiled without SAZ_SUPPORT defined");
#endif
break;
case 't':
try
{
WriteCommandResponse("Result: " + Fiddler.CertMaker.trustRootCert().ToString());
}
catch (Exception eX)
{
WriteCommandResponse("Failed: " + eX.ToString());
}
break;
// Forgetful streaming
case 's':
bool bForgetful = !FiddlerApplication.Prefs.GetBoolPref("fiddler.network.streaming.ForgetStreamedData", false);
FiddlerApplication.Prefs.SetBoolPref("fiddler.network.streaming.ForgetStreamedData", bForgetful);
Console.WriteLine(bForgetful ? "FiddlerCore will immediately dump streaming response data." : "FiddlerCore will keep a copy of streamed response data.");
break;
}
} while (!bDone);
}
/*
/// <summary>
/// This callback allows your code to evaluate the certificate for a site and optionally override default validation behavior for that certificate.
/// You should not implement this method unless you understand why it is a security risk.
/// </summary>
static void CheckCert(object sender, ValidateServerCertificateEventArgs e)
{
if (null != e.ServerCertificate)
{
Console.WriteLine("Certificate for " + e.ExpectedCN + " was for site " + e.ServerCertificate.Subject + " and errors were " + e.CertificatePolicyErrors.ToString());
if (e.ServerCertificate.Subject.Contains("fiddler2.com"))
{
Console.WriteLine("Got a certificate for fiddler2.com. We'll say this is also good for any other site, like https://fiddlertool.com.");
e.ValidityState = CertificateValidity.ForceValid;
}
}
}
*/
/*
// This event handler is called on every socket read for the HTTP Response. You almost certainly don't want
// to add a handler for this event, but the code below shows how you can use it to mess up your HTTP traffic.
static void FiddlerApplication_OnReadResponseBuffer(object sender, RawReadEventArgs e)
{
// NOTE: arrDataBuffer is a fixed-size array. Only bytes 0 to iCountOfBytes should be read/manipulated.
//
// Just for kicks, lowercase every byte. Note that this will obviously break any binary content.
for (int i = 0; i < e.iCountOfBytes; i++)
{
if ((e.arrDataBuffer[i] > 0x40) && (e.arrDataBuffer[i] < 0x5b))
{
e.arrDataBuffer[i] = (byte)(e.arrDataBuffer[i] + (byte)0x20);
}
}
Console.WriteLine(String.Format("Read {0} response bytes for session {1}", e.iCountOfBytes, e.sessionOwner.id));
}
*/
/// <summary>
/// When the user hits CTRL+C, this event fires. We use this to shut down and unregister our FiddlerCore.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
DoQuit();
}
}
}
You can grant the certificate full trust at:
Settings > General > About > Trust Cert

Prosody muc chat history is not complete

I try to make conference chat using prosody, and for the client I use strophe.js. Everything works great except one thing that the chat history shown to user when they just join in to the room is not complete. For example:
One client has already sent messages to the room like this:
1
2
3
4
5
6
7
8
9
10
But when new client join in to the room, they only get messages like this:
1
3
5
7
9
I try to set max_history_messages = 10 in prosody config, and set maxstanzas = 10 from client. But still the same.
Here is my config file
admins = { "agent#localhost" }
modules_enabled = {
"message_logging";
"roster";
"saslauth";
"tls";
"dialback";
"disco";
"private";
"vcard";
"version";
"uptime";
"time";
"ping";
"pep";
"register";
"admin_adhoc";
"admin_telnet";
"bosh";
"posix";
};
bosh_ports = { 5280 }
bosh_max_inactivity = 60
consider_bosh_secure = true
cross_domain_bosh = true
http_paths = {
bosh = "/http-bind"; -- Serve BOSH at /http-bind
files = "/"; -- Serve files from the base URL
}
allow_registration = true;
daemonize = true;
pidfile = "/var/run/prosody/prosody.pid";
ssl = {
key = "/etc/prosody/certs/localhost.key";
certificate = "/etc/prosody/certs/localhost.crt";
}
c2s_require_encryption = false
s2s_secure_auth = false
authentication = "internal_plain"
log = {
info = "/var/log/prosody/prosody.log";
error = "/var/log/prosody/prosody.err";
{ levels = { "error" }; to = "syslog"; };
}
VirtualHost "localhost"
enabled = true -- Remove this line to enable this host
ssl = {
key = "/etc/prosody/certs/localhost.key";
certificate = "/etc/prosody/certs/localhost.crt";
}
Component "conference.localhost" "muc"
restrict_room_creation = true
max_history_messages = 10
Include "conf.d/*.cfg.lua"
Is there something need to set in config?
Here's how I handle message in Strophe.js:
function onLoginComplete(status) {
console.log(status);
if (status == Strophe.Status.CONNECTING) {
console.log('Strophe is connecting.');
} else if (status == Strophe.Status.CONNFAIL) {
console.log('Strophe failed to connect.');
} else if (status == Strophe.Status.DISCONNECTING) {
console.log('Strophe is disconnecting.');
} else if (status == Strophe.Status.DISCONNECTED) {
console.log('Strophe is disconnected.');
} else if (status == Strophe.Status.CONNECTED) {
console.log('Strophe is connected.');
connection.addHandler(onMessage, null, 'message', null, null, null);
if (!chat_room) {
// join to chatroom
}
}
/**
* on new message handler
**/
function onMessage(message) {
console.log(message);
var type = $(message).attr('type');
var body = $(message).find('body').text();
switch (type) {
case 'groupchat':
console.log(body);
// todo append message to the list
appendMessage(message);
break;
}
return true;
}
Here's one message of the history when user just join the room:
<message xmlns="jabber:client" type="groupchat" to="subkhan#localhost/edff55f2-2980-4d01-bf65-0d2c0b011845" from="test#conference.localhost/subkhan"><body>8</body><delay xmlns="urn:xmpp:delay" stamp="2017-04-12T02:54:48Z"></delay><x xmlns="jabber:x:delay" stamp="20170412T02:54:48"></x></message>
Is there something to do with the delay?
Thank you in advance.
Turns out, all this time client already gets all the complete messages history, except it goes to rawInput(data), not to onMessage() handler. So I just remove the handler and handle the incoming message through rawInput(data).

Unity check internet connection availability

I am porting our game to Unity, and need some help regarding internet connectivity check in Unity.
Official Unity Documentation says 'do not use Application.internetReachability.
So i am confused which code will work here.
Didn't find any prominent solution in any forum.
I want to check whether wi-fi or GPRS is on or not which should work for iOS and Android.
Thanks in advance.
Solution
Application.internetReachability is what you need. In conjunction with Ping, probably.
Here's an example:
using UnityEngine;
public class InternetChecker : MonoBehaviour
{
private const bool allowCarrierDataNetwork = false;
private const string pingAddress = "8.8.8.8"; // Google Public DNS server
private const float waitingTime = 2.0f;
private Ping ping;
private float pingStartTime;
public void Start()
{
bool internetPossiblyAvailable;
switch (Application.internetReachability)
{
case NetworkReachability.ReachableViaLocalAreaNetwork:
internetPossiblyAvailable = true;
break;
case NetworkReachability.ReachableViaCarrierDataNetwork:
internetPossiblyAvailable = allowCarrierDataNetwork;
break;
default:
internetPossiblyAvailable = false;
break;
}
if (!internetPossiblyAvailable)
{
InternetIsNotAvailable();
return;
}
ping = new Ping(pingAddress);
pingStartTime = Time.time;
}
public void Update()
{
if (ping != null)
{
bool stopCheck = true;
if (ping.isDone)
{
if (ping.time >= 0)
InternetAvailable();
else
InternetIsNotAvailable();
}
else if (Time.time - pingStartTime < waitingTime)
stopCheck = false;
else
InternetIsNotAvailable();
if (stopCheck)
ping = null;
}
}
private void InternetIsNotAvailable()
{
Debug.Log("No Internet :(");
}
private void InternetAvailable()
{
Debug.Log("Internet is available! ;)");
}
}
Things to note
Unity's ping doesn't do any domain name resolutions, i.e. it only accepts IP addresses. So, if some player has Internet access but has some DNS problems, the method will say that he has Internet.
It's only a ping check. Don't expect it to be 100% accurate. In some rare cases it will provide you with false information.
What I do is Network.TestConnection which tests for connectivity, whether or not it can be a server, and whether or not NAT punch through can be used successfully.
This is the sample code they have given us. If the result is ConnectionTesterStatus.Error, chances are there is no internet access.
var testStatus = "Testing network connection capabilities.";
var testMessage = "Test in progress";
var shouldEnableNatMessage : String = "";
var doneTesting = false;
var probingPublicIP = false;
var serverPort = 9999;
var connectionTestResult = ConnectionTesterStatus.Undetermined;
// Indicates if the useNat parameter be enabled when starting a server
var useNat = false;
function OnGUI() {
GUILayout.Label("Current Status: " + testStatus);
GUILayout.Label("Test result : " + testMessage);
GUILayout.Label(shouldEnableNatMessage);
if (!doneTesting)
TestConnection();
}
function TestConnection() {
// Start/Poll the connection test, report the results in a label and
// react to the results accordingly
connectionTestResult = Network.TestConnection();
switch (connectionTestResult) {
case ConnectionTesterStatus.Error:
testMessage = "Problem determining NAT capabilities";
doneTesting = true;
break;
case ConnectionTesterStatus.Undetermined:
testMessage = "Undetermined NAT capabilities";
doneTesting = false;
break;
case ConnectionTesterStatus.PublicIPIsConnectable:
testMessage = "Directly connectable public IP address.";
useNat = false;
doneTesting = true;
break;
// This case is a bit special as we now need to check if we can
// circumvent the blocking by using NAT punchthrough
case ConnectionTesterStatus.PublicIPPortBlocked:
testMessage = "Non-connectable public IP address (port " +
serverPort +" blocked), running a server is impossible.";
useNat = false;
// If no NAT punchthrough test has been performed on this public
// IP, force a test
if (!probingPublicIP) {
connectionTestResult = Network.TestConnectionNAT();
probingPublicIP = true;
testStatus = "Testing if blocked public IP can be circumvented";
timer = Time.time + 10;
}
// NAT punchthrough test was performed but we still get blocked
else if (Time.time > timer) {
probingPublicIP = false; // reset
useNat = true;
doneTesting = true;
}
break;
case ConnectionTesterStatus.PublicIPNoServerStarted:
testMessage = "Public IP address but server not initialized, "+
"it must be started to check server accessibility. Restart "+
"connection test when ready.";
break;
case ConnectionTesterStatus.LimitedNATPunchthroughPortRestricted:
testMessage = "Limited NAT punchthrough capabilities. Cannot "+
"connect to all types of NAT servers. Running a server "+
"is ill advised as not everyone can connect.";
useNat = true;
doneTesting = true;
break;
case ConnectionTesterStatus.LimitedNATPunchthroughSymmetric:
testMessage = "Limited NAT punchthrough capabilities. Cannot "+
"connect to all types of NAT servers. Running a server "+
"is ill advised as not everyone can connect.";
useNat = true;
doneTesting = true;
break;
case ConnectionTesterStatus.NATpunchthroughAddressRestrictedCone:
case ConnectionTesterStatus.NATpunchthroughFullCone:
testMessage = "NAT punchthrough capable. Can connect to all "+
"servers and receive connections from all clients. Enabling "+
"NAT punchthrough functionality.";
useNat = true;
doneTesting = true;
break;
default:
testMessage = "Error in test routine, got " + connectionTestResult;
}
if (doneTesting) {
if (useNat)
shouldEnableNatMessage = "When starting a server the NAT "+
"punchthrough feature should be enabled (useNat parameter)";
else
shouldEnableNatMessage = "NAT punchthrough not needed";
testStatus = "Done testing";
}
}
This is a simple solution that I am already using for Internet check. It works for both IOS and Android. I know that it may need improvements, but here it is:
public static bool InternetStatus ()
{
if (Application.internetReachability != NetworkReachability.NotReachable)
{
return true;
}else{
return false;
}
}

Grails Issue Dealing With Tcp Client & Tcp Server

I created a Tcp Client & Tcp Server in Groovy awhile back and had no issues with it. I was only connecting to one machine at the time to gather data. This time I am attempting to connect to the script on multiple hosts and it is only saving one of the hosts information in my grails app.
My Grails application is simple, it has a domain class for Machines (basically the computers and the information on them that I seek) and it will use my TcpClient.groovy script to connect and gather information from the TcpServer.groovy on the other computers. For each host, it should save the information gathered, however, it seems to skip right over saving any host aside from the last one.
Tcp Client :
//TCP CLIENT
public void queryData(def hosts) {
for(int aHost = 0; aHost < hosts.size; aHost++) {
cristalClient(hosts[aHost]);
}
}
public void cristalClient(String host) {
commands = ["dateScan", "computerName", "ip", "quit"]
answers = [commands.size]
requestSocket = new Socket(host, 2000)
r = new BufferedReader(new InputStreamReader(requestSocket.getInputStream()));
w = new BufferedWriter(new OutputStreamWriter(requestSocket.getOutputStream()));
String message = "Connection was successful"
message = readAvailable(r)
println("Sever>" + message)
for(int n = 0; n < commands.size; n++) {
sendMessage(commands[n]);
answers[n] = readAvailable(r)
}
lastRead = answers[0]
machineName = answers[1]
ipAddress = answers[3]
w.flush()
w.close()
}
public String readAvailable(r) {
String out = ""
String dum = null
while((dum = r.readLine()) !=null) {
if(dum == ">>EOF<<") return out
if(out.length() > 0) out += "\r\n"
out += dum
}
return out
}
public void sendMessage(msg) {
w.write(msg+"\r\n");
w.flush();
println("Client>" + msg);
}
public void printData(abc) {
abc.eachWithIndex { it, index ->
println "Drive $index"
it.each { k, v ->
println "\t$k = $v"
}
}
}
Tcp Server :
//TCP Server
def server = new ServerSocket(2000)
println("Waiting for connection")
server.accept() { socket ->
socket.withStreams { input, output ->
w = new BufferedWriter(new OutputStreamWriter(output))
String message = "Connection was successful"
r = new BufferedReader(new InputStreamReader(input))
while(true) {
if(message != null) {
sendMessage(message)
message = null
}
String a = r.readLine()
if(a == "dateScan") {
message = new Date
} else if(a == "computerName") {
message = InetAddress.getLocalHost().hostName
} else if(a == "ip") {
message = InetAddress.getLocalHost().getHostAddress()
} else if(a == "quit") {
server.close()
return
} else {
message = "$a command unknown."
println message
}
}
}
}
def sendMessage(String msg) {
println( "sending: >" + msg + "<" )
w.writeLine(msg)
w.writeLine(">>EOF<<")
w.flush();
}
Grails Controller :
//Grails Controller
CollectMachines {
def w = new tcpClient()
def hosts = ["winXp", "Win7"]
w.queryData(hosts)
def abc = w.hardDrive
abc.each { println it }
int numberOfDrives = abc.size()
//add new machine
numberOfDrives.times {
def machineName = abc.computerName[it]
def machineInstance = Machine.findByMachineName(machineName)
if (!machineInstance) {
machineInstance = new Machine(machineName)
}
def lastScan = abc.lastScan[it]
def scanDate = new Date().parse("E MMM dd H:m:s z yyyy", lastScan)
def ipAddress = abc.ipAddress[it]
machineInstance.setIpAddress(ipAddress)
machineInstance.setDateScanned(scanDate)
machineInstance.save()
}
redirect(action: "list")
}
Do I need to put a pause in so that the server has time to send a response? My Tcp Client does send out all the commands but only gets responses for the last set of commands.
Also, sorry for the indentation issues with my code snippets, I'm not sure why they are messed up.
.
There are a few problems with your code. tcpClient never assigns to hardDrive, for example. Assuming this is an oversight, I think the real problem is that tcpClient is querying data for multiple hosts, and storing all the results in the same instance variables answers, and ultimately lastRead, machineName, and ipAddress.
You need to store the results for each host separately. One way would be to have answers be a map of lists. For example, answers[host][0] would be the first answer for a given host.
I don't think any kind of pause is necessary.

Resources