Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Newbie needs help porting C sharp Ajax to VCL or Windows sockets


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 1 - Last Post: Feb 29, 2016 11:00 AM Last Post By: Remy Lebeau (Te...
Dan Ambrose

Posts: 87
Registered: 12/11/03
Newbie needs help porting C sharp Ajax to VCL or Windows sockets  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 27, 2016 7:16 PM
Hello, this is Dan in St. Louis, MO. I need some help porting some communications code form C sharp to C++ Builder. The attached code below is from a c sharp application
Below is the code. I'm not 100% sure what it is exactly. I'm guessing that is using ajax, xml and other technologies. I know how to use lower level Berkley sockets for reading and writing. Is there a way to make something with C++ builder that can be hidden so I can get the strings of real time data from the gateway box with the zigbee module.
I would appreciate any clues, tips, suggestions that RELATE TO USING C++ Builder and the VCL and/or Berkley sockets. Here is the CS code ..

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace Sample.Service
{
internal class IpService
{
private readonly string[] _localIps;
private string _gatewayIp;


public IpService()
{
_localIps = GetLocalIps().Split(',');
}

private string GetLocalIps()
{
var result = "";
var localIPs = Dns.GetHostAddresses(Dns.GetHostName());
foreach (var addr in localIPs)
{
if (addr.AddressFamily == AddressFamily.InterNetwork)
{
if (string.IsNullOrEmpty(result))
result = addr.ToString();
else
result = result + "," + addr;
}
}
return result;
}

public async Task<string> ValidateIpAsync(string gatewayIp)
{
await Task.Run(() => PingService(gatewayIp, null));

if (string.IsNullOrEmpty(_gatewayIp))
{
await GetGatewayIp();
}

return _gatewayIp;
}

public async Task<string> GetGatewayIp()
{
await Task.Run(() => PingServiceParallel());
return _gatewayIp;
}

private void PingServiceParallel()
{
while (string.IsNullOrEmpty(_gatewayIp))
{
foreach (var localIp in _localIps)
{
var ipTrim = localIp.Substring(0, localIp.LastIndexOf("."));
Parallel.For(1, 255, (i, parallelLoopState) => { PingService(ipTrim + "." + i,parallelLoopState); });
if (!string.IsNullOrEmpty(_gatewayIp))
{
return;
}
}
Thread.Sleep(5000);

}
}

private void PingService(string ip, ParallelLoopState state)
{
HttpWebRequest request = null;
HttpWebResponse response = null;
var reqUrl = "http://" + ip + "/ajax.xml";
request = (HttpWebRequest) WebRequest.Create(reqUrl);
request.Timeout = 20000;
request.AllowAutoRedirect = false;
Debug.WriteLine(reqUrl);

var flag = -1;
try
{
response = (HttpWebResponse) request.GetResponse();
flag = 1;
}
catch
{
flag = -1;
}

if (flag == 1)
{
if (response != null && response.ContentType.Equals("text/xml"))
{
_gatewayIp = ip;
if (state != null)
{
state.Stop();
}
}
}
}
}
}

Edited by: Dan Ambrose on Feb 28, 2016 6:24 AM

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Newbie needs help porting C sharp Ajax to VCL or Windows sockets [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 29, 2016 11:00 AM   in response to: Dan Ambrose in response to: Dan Ambrose
Dan wrote:

I'm guessing that is using ajax, xml and other technologies.

It is not using Ajax, just plain HTTP.

I know how to use lower level Berkley sockets for reading and writing.
Is there a way to make something with C++ builder that can be hidden
so I can get the strings of real time data from the gateway box with the
zigbee module.

Basically, the C# code is retreiving a list of local IPv4 addresses, and
then for each local IP it sends an HTTP request to download an ajax.xml file
from every IP address on that local subnet (but not very accurately, as it
is assuming the subnet mask is always 255.255.255.0, which is not always
the case). It is using background tasks for the actual requests, until it
gets an XML response from one of them. The first successful response is
assumed to the IP of the Gateway box.

For instance, if a given local IP is 192.168.0.100, the code sends an HTTP
request to every IP from 192.168.0.1 to 192.168.0.255. If no match is found,
it moves on to the next local IP and repeats.

Basically, it is port-scanning the entire local network looking for any HTTP
server that has an ajax.xml file on it.

The easiest way to accomplish the same thing is to use an HTTP VCL component,
such as the one in Indy or ICS, or an HTTP API, like Microsoft's WinInet
or WinHTTP, or an HTTP-enabled library, like libcurl. You should not code
HTTP by hand, it is actually more complex than most people realize.

If you are using Indy, for example, its TIdStack class has a GetLocalAddressList()
method (which includes IPv4 subnet masks), and then you can use its TIdHTTP
component for the requests. And if you are using a fairly up-to-date version
of C++Builder, you can use Embarcadero's Parallel Processing Library (http://docwiki.embarcadero.com/RADStudio/en/Using_the_Parallel_Programming_Library),
which has a similar API to the one the C# code is using.

#include <IdHTTP.hpp>
#include <IdStack.hpp>
#include <System.Threading.hpp>
 
class IpService
{
private:
    TStrings *_localIps;
    String _gatewayIp;
 
public:
    IpService()
    {
        _localIps = new TStringList;
        GetLocalIps();
    }
 
    ~IpService()
    {
        delete _localIps;
    }
 
private:
    void GetLocalIps()
    {
        TIdStack::IncUsage();
        try
        {
            TIdStackLocalAddressList *addrs = new TIdStackLocalAddressList;
            try
            {
                GStack->GetLocalAddressList(addrs);
                for (int i = 0; i < addrs->Count; ++i)
                {
                    if (addrs->Addresses[i]->IPVersion == Id_IPv4)
                        _localIps->Add(addrs->Addresses[i]->IPAddress);
                }
            }
            __finally
            {
                delete addrs;
            }
        }
        __finally
        {
            TIdStack::DecUsage();
        }
    }
 
public:
    String ValidateIpAsync(const String &gatewayIp)
    {
        PingService(gatewayIp, NULL))
        if (_gatewayIp.IsEmpty())
            GetGatewayIp();
        return _gatewayIp;
    }
 
public:
    String GetGatewayIp()
    {
        PingServiceParallel();
        return _gatewayIp;
    }
 
private:
    void PingServiceParallel()
    {
        while (_gatewayIp.IsEmpty())
        {
            for (int i = 0; i < _localIps->Count; ++i)
            {
                String localIp = _localIps->Strings[i];
                String ipTrim = localIp.SubString(1, localIp.LastDelimiter(".")-1);
                TParallel::For((TObject*)&ipTrim, 1, 255, &PingServiceProc);
                if (!_gatewayIp.IsEmpty())
                    return;
            }
            ::Sleep(5000);
        }
    }
 
private:
    void __fastcall PingServiceProc(TObject *Sender, int AIndex, TLoopState* 
const LoopState)
    {
        PingService(*((String*)ipTrim) + "." + String(AIndex), LoopState);
    }
 
    void PingService(const String &ip, TLoopState* const state)
    {
        TIdHTTP *http = new TIdHTTP(NULL);
        try
        {
            http->ConnectTimeout = 20000;
            http->ReadTimeout = 20000;
            http->HandleRedirects = false;
 
            try
            {
                http->Get("http://" + ip + "/ajax.xml", (TStream*)NULL);
                if (IsHeaderMediaType(http->Response->ContentType, "text/xml"))
                {
                    _gatewayIp = ip;
                    if (state)
                        state->Stop();
                }
            }
            catch(const Exception &)
            {
            }
        }
        __finally
        {
            delete http;
        }
    }
};


--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02