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.