The simple Xin Library documentary

INDEX
What is the deal?
How do we do communicate through the Internet in XBasic?
The Keyword and syntax lists
Limitations of the Xin library
Example files


Programming with the Xin library is not as super tough as you may think but the lower you go, the tougher it gets....

A few weeks ago we (Eddie, Cavac, I and a couple of spectators) were a bit brainstorming about the Xin functioning problem with which I was struggling with for a couple months.

The Xin had a problem in the socket-layer that really broke my mind, eventually Eddie came up with a solution I would have never found out because my knowledge on socket programming is way too unexperienced.
 
What is the deal?
You have a couple of levels that you can program on, the Xin Level should be dealing with the most toughest parts of your communications concept.

What you need to study for sure is the methods every separate protocol demands from you in order to communicate.

To know this you need to know what Primitives are.

Primitives are five or four steps that are being taken to build up a communication line.

Lets take SMTP for instance, this is a protocol that allows you to send mail through a server well, I can go way into technical details right now but I can also explain you the way your ordinary post delivery company works with your outgoing mail;

If you want to send an ordinary letter, you get out, go to the outgoing mailbox and drop in your envelope.
The mail-company collects all those mails there and then takes them to the distribution center. From there the mails are sent to the supplied addresses which are given with them (assuming everything is perfectly correct).

The way you send your letter may differ in various countries but I assume that most mail-box collectors have two separate compartment slides:one for local destinations and one for interlocal or even foreign destinations.

Meaning:you can't drop your foreign addressed envelopes in the local destination slide as vice versa for the local addressed mail. Either you get it returned or it will arrive with a major delay.

Those are rules and you have to read and operate according to them.
That's the protocol.

For each message you need to retrieve (POP is the electronical shape of our "snailmail" receiving system) you need to have a mailbox at your home for delivery and your house need to stand in a block, street and must contain a house-number. Those are the data the mailman needs as identification protocol to be sure he delivers your mail at your address and not that of your neighbours or just dropping it somewhere in the neighbourhood.


So we have a special delivery system and a special retrieving system and they both work with different protocols.
That's obvious since you know it has no use to give an outgoing letter to your mailman and ask him to personally deliver it on its destination.

The primitives are the four or five basic elements that build, maintain and disconnect a communication channel between a client and a server. Those primitives count for ANY protocol wether it's SMTP, POP, FTP, HTTP, it all remains the same;

I will name them from 1 to 4:
1 A message is send to the server to request a connection
2 The server returns a message to acknowledge (or refuse) the connection.
3 The client will then open a port and identifies himself
4 The Server will again acknowledge either with by authorising or refusing access.

Messages returned either go by character response or complete keywords / numbers...
To gain access to all the available protocols, you need to know how to set up connections by supplying the right responses.

e.g. HTTP works with pretty simple codes, like a Connect request  is done with a simple GET command and the HTTP server will then respond with a simple 100 (Connect OK) or 101 (Connection Refused) . I might be wrong about the specific return command details but HTTP is pretty simple unlike Telnet which works with character identifiers and combinations of char-sets and a simple Telnet connection is a lot work to do since you need to emulate an old fashioned terminal session method that works with special character sets to communicate and even with Telnet you have sub-protocols that result in different outputs so the Telnet Protocol is definitely different from HTTP and a not as easy.

To get to the point, the specifications you need to communicate with servers are stored in RFCs which can be located here.

 Lets pick out an example by setting up a Client session just to retrieve an HTML page....

For this case I take the Cinema as a similar situation...

For this you need to know where the cinema is located (Address) and where is the entrance? (PORT).
well, the entrance of the cinema is always at front, I hardly have seen people entering through the backdoor as so is with the web, the PORT number used for the HTTP protocol line is by default 80 unless the cinema is not open for public purposes.

HTTP://www.cinema.com:80/

You also have to pick out the movie you want to see, so you go to the lobby first to get some tickets. The web-lobby is generally called index.html by default:

HTTP://www.cinema.com:80/index.html

Then you are instructed which theater your chosen movie is playing (sub-pages) and you will be guided to it by a guiding system (links)

HTTP://www.cinema.com:80/theater1/TheLostWorld.html





Okay, this start to look like what we want, but how do we do this in XBasic?

We import the Xin library in the PROLOG (if necessary, also winsock):
IMPORT "xin"
IMPORT "wsock32" ' (Only in XBasic versions 6.0021 and lower.)

First we take care we share the socket variables that need to be stored in a table, just dimensioning user defined table the way displayed here using the predefined user type HOST:
HOST host


At all sakes, reserve your primary port for the protocol you want to use:

ServerPort = 80 ' Portnumber of the HTTP port.
serverName$ = "www.cinema.com/theater1/TheLostWorld.html"

What you also need to do is preparing buffers and clear states so you can initialise your connection properly:
socket = $$FALSE ' no server socket yet
connected = $$FALSE ' not connected to server yet
buffer$ = NULL$(255) ' place to capture received data
 
At all costs you must enable the Xin before you take any action to it:

Xin()

Note:Your XIN status needs to be set to "TRUE" in the \WINDOWS\XB.INI or the \WINDOWS\XB.INI needs to be erased to have the Xin properly enabled. If you have Winsock 1.1 and your Dial-Up Network version is below 1.3, XBasic will crash when you have NO live internet connection. This only happens in the older versions of Win'95, just do yourself a favor and upgrade to the latest Winsock and DUN for Win'95 now.
 
With the Xin enabled, also your local host info is retrieved including your ISP provided IP number if you are online.
With the following commando you put those values into the table:

XinHostNumberToInfo(0, @host)



You reserve your own IP address into a personal variable:

LocalHost = host.address



Then you check the table if multiple IP addresses are found (If you have a local network with more Network cards) you need to filter out the outgoing IP address you have (provided by your ISP):

The latest added IP address can be a Dynamic IP if you are connected to the internet though it's not guaranteed that this will be your ISP provided IP or the outgoing IP address you wanted to use for communication (take two open ISDN channels for instance or multiple network interfaces on your machine):

FOR X = 0 TO 7

  IF host.addresses[X] > 0 THEN
    LocalHost = host.addresses[X]
  ELSE
    EXIT FOR
  END IF 

NEXT X




To check it you can convert your local IP address (which is in HEX format) to dotted notation (xxx.xxx.xxx.xxx):

XinAddressNumberToString(LocalHost, @addr$)
PRINT "Local host:"; addr$




The thing you do next is opening a socket so the server can connect a plug to your system:


error = XinSocketOpen(@socket, 0, 0, 0)




Error correction and blowback handler if everything fails:

IF error THEN
  Blowback1(error)

  RETURN
END IF


Now that you made the socket, you need to "put the plug" in meaning:you need to bind it, this is what the Xin will do for you, it will seek an empty port and address for you (an unused line) and plug it into your recently made socket:

port = 0
address$$ = 0
error = XinSocketBind(socket, block, @address$$, @port)


Again with the necessary error correction and blowback handler if everything fails:

IF error THEN
  Blowback1(error)

  RETURN
END IF




We are now going to connect to the remote server with the data you inserted above (address and portnumber).
Now we get to a critical part of the Xin, for sure all XBasic versions up to V6.0021 or V6.0.# do not correctly translate the destination port-number for you at which you want to connect.

I can supply you this extra info:
If you getting knocked out with a TIME-OUT error later on when waiting for a connect-status, you need to IMPort the "wsock32" in the PROLOG and you need to unquote the htons() function in the lower particle of the code, this needs to be done to translate your destination port from a regular port value to a hexadecimal port value as network protocols work with the hex form:

' serverPort = htons(serverPort) 'Unquote only if you get a time-out when your destination server works 100%
XinHostNameToInfo(serverName$, @host) 'Get the host-ip-address of the remote server you want to connect to
XinAddressNumberToString(host.address, @addr$) 'Convert Hex address to dotted IP notation
PRINT "Connecting to :" ; addr$ 'Display IP address
error = XinSocketConnectRequest(socket, 0, host.address, serverPort) 'Do the request.



Again with the necessary error correction and blowback handler if everything fails:

IF error THEN
  Blowback1(error)

  RETURN
END IF




Now, ofcourse you need to get an answer so you wait until you get the one you want which is the status Connected (Unless error like TIME-OUT (100061)):

DO UNTIL connected
  error = XinSocketConnectStatus(socket, 100, @connected)

  IF error THEN
    Blowback1(error)

    RETURN
  END IF

LOOP
 

If you are here, this means that your connection became a success, you can start to send your first functional request, I suggest you to read along ftp://ftp.isi.edu/in-notes/rfc2616.txt to understand the nature of HTTP command requests and responses:

request$ = "GET HTTP://" + serverName$ + "/ HTTP/1.1\r\nHost: " + serverName$ + "\r\nAccept: */*\r\nAccept: text/html\r\n\r\n" 'Set up the command to send to the server
address = &request$ 'supply the memory address of the data to be sent.
writebytes = SIZE(request$) 'Set the bytes to write
buffer$ = NULL$(1024) ' Make 1K receive buffer
bytes = 0 'Set received bytes to 0
error = XinSocketWrite(socket, 100, address, writebytes, 0, @bytes) 'Send your command





Again with the necessary error correction and blowback handler if everything fails:

IF error THEN
  Blowback1(error)

  RETURN
END IF



Good now lets wait and see what will be the response:
 
address = &buffer$ 'Set the address where to store the retrieved data
maxbytes = SIZE(buffer$) 'Set the retrieval buffer-size

DO
  ' Wait for incoming data for max 25 * 20 ms (= 0.5 sec), expand when delay is larger
  FOR I = 1 TO 25
    block = 20000
    bytes = 0
    error = XinSocketRead(socket, block, address, maxbytes, 0, @bytes)

    IF error THEN EXIT FOR

      IF bytes > 0 THEN 'Collect all incoming data-bytes
        Page$ = Page$ + LEFT$(buffer$, bytes)

        PRINT LEFT$(buffer$, bytes);
      END IF

  NEXT I

  The next solution is a simple task killer but it can be done way better efficient (like using the Content-Length data as an end-marker) as not all pages and with the last HTML tag I assume below:

  IF INSTR(UCASE$(Page$), "</HTML>") > 0 THEN 'If HTML end marker found, then stop reading bytes.
    EXIT DO
  END IF

  IF error THEN
    Blowback1(error)

    RETURN
  END IF

LOOP




The final closure:

PRINT
PRINT "End of HTML page"



Close the complete session and sockets:

Blowback1(0) 




Here's the blowback function:

FUNCTION Blowback1(errorCode)

XinSocketClose(-1) ' close all my sockets

XinSetDebug(0) ' turn off bug printer

IF errorCode > 0 THEN
  PRINT "errorCode = "; errorCode
END IF

END FUNCTION




If you want to set up a Server application, there is one step you need to change and that is the connect request, there you need to setup a loop that "listens" to the port you opened to the public, like the cinema employees are waiting at the door for you to enter and doing your requests.

The aserver.x delivered with the XBasic package shows you this Server side-step to code.




Keyword and Syntax lists
I've supplied some syntax explanations to Tom Stout, they supply a pretty slim explanation upon each Xin function that is available for your use.
Just open this starting page to get some QuickSpecs about Xin functions.


Limitations of the Xin library
Though, if you get the hang of the Xin Library there are a couple of limitations that are can form an issue problem for your client or server application you want to write:

Xin works on polling-base;
meaning:you can only have ONE live server connection per running XBasic application unlike the general server applications that can just open a new port and reassign the original port to do the job. (There is an experimentation fase going on to test a couple of tricks where you can do multiple connections)
This means:you can't set up a server to listen to a certain PORT and then quickly change the port as soon as a client connects and set the original port to listening state as the XinSocketAccept specs mention otherwise (the way Xin *SHOULD* behave).
In how far this reflects on Linux I don't specificly know but in Windows it works that way.
There is a method where you can use Xin for multithread opportunities but then the Xin requires a couple of add-ons and facelifts.

Xin supports TCP protocol ONLY;
Unless you change the Xin source-code and add it, you can't do UDP connections which you for instance need to design clients for IRC protocols and things like ICQ-servers which work with Virtual datagrams (no live connections), I'm not saying that you can't emulate UDP but serious UDP package sending is pretty hard when TCP requires an answer from the remote site if all arrived while UDP is meant to broadcast without return receipts. (no guarantee that your message really do arrive)
 
If you have a good socket programming experience and you consider it worthy to give the Xin a good facelift then you are invited to experiment with the source-code of it supplied in the XBasic Source distribution available from www.xbasic.org.


Example files

The next links supply you a couple of example files that work with Xin.
They are not 100% waterproof since they work mostly on keyword returns which are not identical between all servers, but you can fool around with it and if you figure something nice or you have something new, you can mail it to me for publication. If you are not a socket wizard, expect the Xin library to change or improve in the next upcoming decade...

A couple of tests:SMTP, FTP and HTTP.