DesignBais Tip – Getting Client Info

A question came up in the DesignBais forum : "Is there any way for me to find the IP Address or Hostname of the requesting machine?" There are a couple "unorthodox" ways to do this. With the information provided here you will get an idea of how to get any data into your application from other sources in your network.

This may not work in v4, or there may be a better solution in v4, and this article may go obsolete quickly. I’ll post timely updates as required. We can get the client IP address and hostname from the IIS activity log. The trick is to take information we know and use it to find information we want.

Configure IIS

To start, we need to set the logging in IIS:

  • In IIS, go to website properties and enable logging.
  • Set the Active Log Format to W3C Extended.
  • Click Properties for the log format, set the log time period to Hourly (this gives us smaller buffers to look at).
  • Under the Extended Properties tab, click the Extended Properties checkbox, then click the Cookie and Host properties.

IIS will now save the "DesignBAIS" cookie in logs. I think the only time a log is written by DB is when we first login. Each log entry for DB has this data (depending on other settings in your properties setup):

Time (GMT) 04:31:35
IP Address 192.168.1.116
Username
Get/Post GET
URI /jspellhtml2k4/jspell.js
Status 404
Host clientpc
Cookie DesignBAIS=machine=
%7BD0E8B9BF%2D53D9%2D4A72%2D8775%2D224E11702069%7D
%2E15868;
+ASPSESSIONIDCAAQQDAB=PHLDAAEBIOOJODDMDLCFGHCJ

I don’t know why DB logs a 404 error for jspell.js, maybe I don’t have something configured properly on this system, but I get this error all the time, which may be a good thing for our purposes. I also don’t know why the Username isn’t recorded either, but these things aren’t important at the moment.

Accessing the logs

Note the time is recorded in GMT, so you get consistent logging no matter where your server is and no matter where the client is. The ID to the log file also uses the GMT Hour value, "04" in the case above, along with the current GMT date. The format of the log filename is:
   exYYMMDDHH.log
An example for today, when I am writing this article is:
   ex06082204.log
Note that the date and time in the UK (GMT) is the 22nd at 4am, even though here in the US when I wrote this it was still the 21st at 9pm PST. Using this information you should be able to figure out what the log filename is for any give time.

IIS logfiles are stored wherever the logging properties says. The default is:
  C:\WINDOWS\system32\LogFiles\W3SVC1
So once you’re changed the settings and restarted IIS, you can expect to find logs in that folder.

The next step is to get from your MV environment to the logs. (This information applies for any application that requires getting data from a remote environment.) You need to reach from BASIC into your web server, read the logfile, then you can parse it for the data you want.

If your DBMS is on the web server localhost then it should be no problem to use a statement like OPENSEQ, or with D3 use the OSFI to open "c:/windows/system32…".

If your DBMS is on another Windows server, then you may want to setup a share to the web server. You can use a command like this:
  net use w: \\websvr\windows\system32… psw /user:administrator
That can be executed with a "!" or other shell command, or from a script when your Windows OS boots. The idea is to create a mapped drive "w:" that points into the \\websvr system, folder \windows… To login and get access to that path you need a username and password. The resulting OPENSEQ would open "w:" and read the "ex06…log" file. In D3 you need to create an item in the dm,hosts, file called "w", so that you can open "w:" to logpath. As you can see I’m trying to get away from going into detail on this topic which is documented elsewhere.

If your DBMS in in Linux or Unix then you can setup a Samba share.

Extracting desired data from the logs

So at this point let’s assume that the log is being generated and you can access it from BASIC. Now how do we link a given user request to their data in the logs?

Take a look at that Cookie field in the log:
DesignBAIS=machine=
%7BD0E8B9BF%2D53D9%2D4A72%2D8775%2D224E11702069%7D%2E15868;
+ASPSESSIONIDCAAQQDAB=PHLDAAEBIOOJODDMDLCFGHCJ

That cookie is the very same value returned by the DBCOOKIE variable in DesignBais! There are some differences of course:

  • The log entry is URL encoded.
  • The DBCOOKIE doesn’t include the "machine=" text.
  • It also doesn’t include the ASPSESSIONID info, which by the way, this is not the same as the SESSIONID variable available in DesignBais.

The DBCOOKIE for that above value looks like this:
  {D0E8B9BF53D94A728775224E11702069}.15868

To encode the DBCOOKIE, we need to translate the non-numeric values as follows. These and other character translations are found here and on many other sites:

Character Encoded Value
{ %7B
} %7D
%2D
. %2E

So, taking the DBCOOKIE variable and using a SWAP or CHANGE function in BASIC, we can get the same value found in the log. The only thing left is to loop on all lines (attributes) in the log and use an INDEX function to see if the cookie we want is in the line we’re testing. If it is, we can use a FIELD statement to extract the IP address, hostname, or other data. In my example data in the table above, the IP address is in field 2 and the host is in field 7.

Considerations:

  • If you have a high-activity site, the logs will have a lot of data to look through, even if the files are recycled hourly. This can slow down this operation, so don’t do it too often.
  • If someone changes your IIS logging this process may fail.
  • If DBI updates the DesignBais software to provide this data, it would be much better to use DB tools than this cumbersome process.

I mentioned in the opening that there is another way to do this. Rather than having BASIC operate on your server logs it might be more "elegant" to have your BASIC program execute a routine on the web server which returns the desired values. This separates the request for data from the implementation of the request. Of course this means writting a little server-side code in whatever language you find convenient. The article on Alternative Graphs describes this sort of process at-length.

When I come up with this stuff it doesn’t mean I like or advocate any specific solution, I’m simply providing answer to problems that otherwise didn’t seem solvable. Let me know if you’d like to me to implement these or similar solutions for you. I can’t guarantee they’ll be elegant but we’ll get the job done.

5 thoughts on “DesignBais Tip – Getting Client Info

    • Alternativley, you can use the approach already documented on here for file uploads (ie. you create a work variable and set  to html code to insert an iframe in your page with source of an asp or asp.net page on your IIS box and with the designbais session id passed in). The asp or asp.net code then needs to get the client ip address using request.ServerVariables("REMOTE_ADDR") and then use the filesystem object to write this to disk with an id of the designbais session id. Your Databasic can then read this in.rgdsSym.

    • According to DBI today: "Version 4 will keep the users IP in DBSOURCEIP – you will also be able to pass a query string through to DBW3CQSTRING".

    • Yow! Passing the query string to DBW3CQSTRING is GREAT news! I’ve been thinking about how to get our MV app to RESPOND to an incoming call with caller ID through TAPI. Having the query string available solves half the problem.
      NOW all I need is an app sitting in the background that listens for incoming calls in TAPI, then when one with a caller ID number comes in, fire up an IE session to an appropriate URL with the number in the query string, then design the form (contact management) to pull up the contact (if only 1 found), choice of contacts (if more than 1 found) or create contact (if not found!)

    • Sounds like you still need to work out another issue though. Unless you have the client polling the server you have no way of getting the call from the server to the end-user. There is the DBTIMER variable which will fire an After Display event on each timeout, and from there you can check to see if there is a call waiting, but this isn’t appropriate for a real-time app. You can, however, load an executable on the end-user’s PC which will respond to server events via mv.NET. This can fire up a browser instance to your DB app which the user can use to process the call. Really, it doesn’t need to fire up a new browser instance, this component can be a thick container which displays a browser interface. It’s a thin client within a thick client, so to speak, and can be deployed using SmartClient technology.

      Real-time processing of server-initiated transactions over the internet can be very tricky. There are issues with latency, security, deployment, and error handling. This won’t be a slam-dunk. To make sure your end product is stable for various environments I think you’re looking at a thicker solution than you had hoped.

    • Tony,
      I never envisioned that handling INCOMING calls could do without a process running on the client’s desktop (whether it’s a thick desktop or a desktop on a Windows Server accessed through a thin client.) There obviously has to be some process that responds to the incoming call notification and fires up the URL. Nice thing about DB vs Accuterm (what we’re currently using, NOT the GUI) is that firing up another window doesn’t take up another seat.
      As far as HOW this applet logs on to/establishes a connection with our phone system, we’ve got a few choices of communication path. TAPI is one (and you end up talking with the phone system’s GUI client – Doesn’t work unless the client is running, but this is actually a GOOD thing in our case, since we don’t want a DB page to fire up UNLESS the user is logged into the phone system!) and there is another that connects directly to the server.
      I actually haven’t done much research, just a general knowledge of what’s necessary, with further refinements based on "Aha!" moments when people (such as yourself) talk about something that triggers an "Oh! That’s how I can do this." thought.
      –Steve

Leave a Reply