• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Help with TCPExample in Pascal

mactjaap

Well-known member
I would like to make a ultra light version of a web server for Macintosh. I really would like that it runs on System 6.

It has to serve only one page or one small string of html. Just for the fun of running a web server on an old Mac.

This is how I started.

I have found an old peace of code called TCPExample. It is written in Pascal. The actuel code starts a connection to port 79 of the finger daemon and gives you information from the finger server about a user. Like this:

Code:
Login: macipgw                          Name: MacIPgw
Directory: /home/macipgw                Shell: /bin/sh
Last login Wed Oct 16 21:56 (UTC) on pts/1 from 192.168.62.201
No Mail.
No Plan.
My first goal was to get the code do something else, like a telnet connection to port 23 and login. I added a passwd variable and sending it to the server.

Code:
passwd = 'test123';

s := concat(user_name, cr, lf); { Send the line that telnet wants, complete with crlf }
p := concat(passwd, cr, lf); { Send the line that telnet wants, complete with crlf }
But no success. I guess, I’m missing the point.. I do get a connection, because I get:

Connection Established

This is the part if a connection is a succes.

Code:
C_Established:  begin { Happens once per succesful connection establishment }
writeln('Connection Established');
I also see something happening with a tcpdump

Code:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on em0, link-type EN10MB (Ethernet), capture size 96 bytes
23:36:17.470695 IP 192.168.62.9.dls-monitor > 192.168.62.10.telnet: Flags [s], seq 2856448, win 16616, options [mss 1460,wscale 0,eol], length 0
23:36:17.470750 IP 192.168.62.10.telnet > 192.168.62.9.dls-monitor: Flags [s.], seq 3540554349, ack 2856449, win 65535, options [mss 1460,nop,wscale 3], length 0
23:36:17.575401 IP 192.168.62.9.dls-monitor > 192.168.62.10.telnet: Flags [.], ack 1, win 17520, length 0
23:36:17.638188 IP 192.168.62.10.telnet > 192.168.62.9.dls-monitor: Flags [P.], ack 1, win 8212, length 3
23:36:17.698518 IP 192.168.62.9.dls-monitor > 192.168.62.10.telnet: Flags [.], ack 4, win 17520, length 0
My question is.. Could someone help me a little bit getting this code run. I’m not much of a programmer, but willing to learn!

This is the link on Internet: http://www.macgui.com/usenet/?group=17&id=8393

Turbo Pascal: http://macintoshgarden.org/apps/turbo-pascal-10

Send me a PM if you need more. I use Turbo Pascal 4.5

This is the code I have.

Code:
program KenExampleCode;

{ You can do anything you want with this code - if you can make any money out of it, you'll be doing well! }

uses
 TCPTypes, TCPStuff, TCPConnections;

const
 user_name = 'mactjaap';
 dest_name = '192.168.62.10';
 dest_port = 23;
 passwd = 'test123';
 nul = chr(0);
 lf = chr(10);
 cr = chr(13);

var
 oe: OSErr;
 cp: connectionIndex;
 quitNow: boolean;
 cer: connectionEventRecord; { Event record for TCP events, simmilar to EventRecord }
 s: str255;
 p: str255;
 count: longInt;
 gotlinefeed: boolean;
begin
ShowText;
quitNow := false;
oe := InitConnections; { Startup the TCP units }
if oe = noErr then begin
 oe := FindAddress(cp, dest_name, nil);
 if oe = noErr then begin
  count := 0;
  while not quitNow do begin
   if GetConnectionEvent(any_connection, cer) then begin { Get the next TCP event }
    case cer.event of
     C_Found:  begin
      writeln('Found ', dest_name, ' has address ', pointer(cer.value));
      oe := NewActiveConnection(cp, Default_TCPBUFFERSIZE, cer.value, dest_port, nil);
{ Open an active connection to the Finger port on dest_name }
     end;
     C_SearchFailed:  begin
      writeln('Couldn''t fine the address for ', dest_name);
      quitNow := true;
     end;
     C_Established:  begin { Happens once per succesful connection establishment }
      writeln('Connection Established');
      s := concat(user_name, cr, lf); { Send the line that telnet wants, complete with crlf }
      p := concat(passwd, cr, lf); { Send the line that telnet wants, complete with crlf }
      if oe <> noErr then
      CloseConnection(cp); { Better close the connection if we can't send anything to it! }
     end;
     C_FailedToOpen: 
      writeln('Ooops, connection failed to open... Error is ', cer.value, ' Timed out is ', cer.timedout);
{ Example, network unreachable etc.  Error code is in cer.value }
     C_Closing:  begin
      writeln('Connection closing');{ Gets called when the connection starts closing down}
      CloseConnection(cer.connection); { Close our side of the connection }
     end;
     C_Closed:  begin
      writeln('Connection closed, quit now');
      quitNow := true; { The connection is closed, quit the program }
     end;
     C_CharsAvailable:  begin
{$PUSH}
{$R-}
      oe := TCPReceiveUpTo(cer.tcpc, 10, 60, @s[1], 255, count, gotlinefeed);
{ Recieve characters up to a line feed }
      if (count > 0) & (s[count] = lf) then { strip off linefeed }
      count := count - 1;
      if (count > 0) & (s[count] = cr) then { strip off cr }
      count := count - 1;
      s[0] := chr(count);
{$POP}
      if gotlinefeed then begin { if we got a linefeed, print the string, otherwise go round again and wait for more characters }
      writeln(s);
      count := 0;
      end;
     end;
    end;
   end;
  end;
 end;
 FinishEverything; { Close everything, clean up }
{ ALWAY CALL THIS, OR YOU WILL BE SORRY! }
end;
writeln('Click to quit');
while not Button do
 ;
end.
 

bbraun

Well-known member
It might be helpful to take a step back first.

telnet may not be the best protocol to try implementing first, since there's some preliminary option negotiation as part of the telnet protocol. If you're using tcpdump, you might try something like "tcpdump -n -i -s 0 -X" to capture complete packets (-s 0) and view them as both hexadecimal and ascii (-X). If you try that, you might see the option negotiation happening within the body of the packets.

You might also want to look at using netcat (nc). That will let you establish raw connections from a shell, and if you run it in listening mode, your code will probably connect and you'll see the output.

You can also test with nc as a client to verify what you're doing in code. For instance, this is what I get when using nc to do a raw tcp connection to my telnet server:

Code:
id 11:49:44 ~> nc localhost 23
���� ��#��'mactjaap
test123

^C
Which is pretty different from the server greeting and username/password prompt you'd see from a telnet client.

 

mactjaap

Well-known member
Thanks bbraun for the help! I now understand better!

I changed to your advice. I started to use nc, the "Swiss knife" network tool. This is indeed more transparent.

I started it up as a kind of mini web server with the command:

Code:
while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; cat index.html; } | nc -l 84; done
This will send the file index.html with an HTTP header to anything what connects to port 84. This could also be my TCPExample. I tested it first with nc itself in an other console:

Code:
nc localhost 84
Then I edited my pascal code like this:

Code:
 const

 dest_name = 'live.net2service.com';
 dest_port = 84;

 nul = chr(0);
 lf = chr(10);
 cr = chr(13);
Test the new executable:

TCPExample as a Browser App.zip

See all the code:

TCPExample as a Browser.zip

Now I'm on my way!

I would like to know if I can switch the current code to something what listens to a port and sendout a file if asked. Just like nc is doing in my mini web server?

 

Attachments

  • TCPExample as a Browser App.zip
    98.1 KB · Views: 22
  • TCPExample as a Browser.zip
    76.6 KB · Views: 19

bbraun

Well-known member
I'm not very familiar with this MacTCP wrapper library you're using, but it looks like the way you create a listening socket instead of connecting to another machine is with NewPassiveConnection, and then the C_Established event will be when a client connects.

For the file access, you might look at using FSpOpenDF to open the file's data fork, FSRead to read the data, then FSClose.

 

mactjaap

Well-known member
Ok. Before I start on such a major change I would like to send data to my opened nc port. Now it is working that on a connection data is send back. I would like to manipulate the TCPexample so that it can send data.

I listen on port 84

Code:
#nc -l 84
Thenm I connect with TCPexample to the port.... How to send over data?

I tried just the part where the finger username is in the example, but nothing happens:

Code:
     C_Established:  begin { Happens once per succesful connection establishment }
      writeln('Connection Established');

      s := concat(user_name, cr, lf, cr, lf);

      if oe <> noErr then
      CloseConnection(cp); { Better close the connection if we can't send anything to it! }
     end;
teh I looked in the origional code and saw that I just forgot one line after ....s := concat(user_name, cr, lf, cr, lf);

Code:
s := concat(user_name, cr, lf, cr, lf);
oe := TCPSend(cer.tcpc, @s[1], length(s), true);
So now I changed the username variable to

Code:
get /
and the port to 80.

Now TCP Example becomes a browser. It will get the default page on my server.

Later.... I will let it get the home page of 68kmla.org.... the we have a very simple browser!

 

mactjaap

Well-known member
Ok... I tried this as NewPassiveConnection:

Code:
oe := NewPassiveConnection(cp, Default_TCPBUFFERSIZE, localport);
these are my const

Code:
 const
 user_name = 'get /';
 dest_name = '192.168.62.9';
 dest_port = 84;
 localport = 84;
 nul = chr(0);
 lf = chr(10);
 cr = chr(13);
Doesn't work. I get a complaint about: Too few parameters are used in procedure or function call

I found what could be in NewPassiveConnection

Code:
function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
How to construct a correct one?

 

bbraun

Well-known member
Code:
function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
That's the declaration of the function, it has 6 arguments and returns an OSErr. OSErr is a 16bit number, and is the typical Mac OS error code you see everywhere, including in system dialog boxes when something goes wrong. You can google for the error code, and it should also be defined in a header file with your compiler somewhere. Here is also an old KB article with some of the codes defined.

var cp: connectionIndex - the 'var' means it is a pass by reference, or a pointer, for a type 'connectionIndex'. The 'cp' is just a name, although in the example this would also be the variable 'cp' that is being passed to NewActiveConnection.

buffersize: longInt - the argument is of type longInt, which would be a 32bit value. The name is 'buffersize', and it looks like you can just use the constant Default_TCPBUFFERSIZE that is being passed to NewActiveConnection.

localport: integer - 'integer' being a 16bit value. This is the local port you want to listen on.

remotehost: longInt - longInt being the same size as an IP address, this is the address you want to accept connections from, although you can pass 0 in to accept connections from anywhere.

remoteport: integer - the remote port you want to accept connections from, although you probably want to pass in 0 to accept from any port.

dataptr: univ ptr - This is a pointer to "anything". It appears the wrapper is letting you associate your own data with the connection, and you can get it back when processing events returned by GetConnectionEvent. The sample code calls NewActiveConnection with this parameter as 'nil', or "no value", and you can probably do the same thing for NewPassiveConnection for now.

The way I figured out what the arguments are is I looked in the TCP Libraries folder of the example, at TCPConnections.unit, and what that was doing. Ultimately, it is making a MacTCP call to open a new passive connection, and the arguments for that are described in the MacTCP Programmer's Guide.

 

mactjaap

Well-known member
I try to construct a NewPassiveConnection:

Code:
oe := NewPassiveConnection(cp, Default_TCPBUFFERSIZE, localport, nil);
This gives an error:

Type incompatibility between an actual and formal value parameter
So I'm stuck.... What to try next?

 

mactjaap

Well-known member
YES!!!! This is it!! Thanks a lot!

I just added the values 0 for remotehost and remote port and nil and then it works.

This is my code now. Please do understand that I'm not much of a programmer, but trying hard to do my best! Some variables are still in it but only relevant for NewActiveConnection.

Code:
program MacTjaapExampleCode;

{ You can do anything you want with this code - if you can make any money out of it, you'll be doing well! }

uses
 TCPTypes, TCPStuff, TCPConnections;

const
 user_name = 'GET / HTTP/1.0';
 dest_name = 'www.apache.org';
 dest_port = 80;
 nul = chr(0);
 lf = chr(10);
 cr = chr(13);
 localport = 80;
 remotehost = 0;
 remoteport = 0;
 dataptr = 0;



var
 oe: OSErr;
 cp: connectionIndex;
 quitNow: boolean;
 cer: connectionEventRecord; { Event record for TCP events, simmilar to EventRecord }
 s: str255;
 count: longInt;
 gotlinefeed: boolean;
begin
ShowText;
quitNow := false;
oe := InitConnections; { Startup the TCP units }
if oe = noErr then begin
 oe := FindAddress(cp, dest_name, nil);
 if oe = noErr then begin
  count := 0;
  while not quitNow do begin
   if GetConnectionEvent(any_connection, cer) then begin { Get the next TCP event }
    case cer.event of
     C_Found:  begin






{function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;}

      oe := NewPassiveConnection(cp, Default_TCPBUFFERSIZE, localport, remotehost, remoteport, nil);
     end;
     C_SearchFailed:  begin
      writeln('Couldn''t fine the address for ', dest_name);
      quitNow := true;
     end;
     C_Established:  begin { Happens once per succesful connection establishment }
      writeln('Connection Established');
      s := concat(user_name, cr, lf, cr, lf); { Send the line that finger wants, complete with crlf }
{oe := TCPSend(cer.tcpc, @s[1], length(s), true);}
      writeln('Name sent with error ', oe);
      if oe <> noErr then
      CloseConnection(cp); { Better close the connection if we can't send anything to it! }
     end;
     C_FailedToOpen: 
      writeln('Ooops, connection failed to open... Error is ', cer.value, ' Timed out is ', cer.timedout);
{ Example, network unreachable etc.  Error code is in cer.value }
     C_Closing:  begin
      writeln('Connection closing');{ Gets called when the connection starts closing down}
      CloseConnection(cer.connection); { Close our side of the connection }
     end;
     C_Closed:  begin
      writeln('Connection closed, quit now');
      quitNow := true; { The connection is closed, quit the program }
     end;
     C_CharsAvailable:  begin
{$PUSH}
{$R-}
      oe := TCPReceiveUpTo(cer.tcpc, 10, 60, @s[1], 255, count, gotlinefeed);
{ Recieve characters up to a line feed }
      if (count > 0) & (s[count] = lf) then { strip off linefeed }
      count := count - 1;
      if (count > 0) & (s[count] = cr) then { strip off cr }
      count := count - 1;
      s[0] := chr(count);
{$POP}
      if gotlinefeed then begin { if we got a linefeed, print the string, otherwise go round again and wait for more characters }
      writeln(s);
      count := 0;
      end;
     end;
    end;
   end;
  end;
 end;
 FinishEverything; { Close everything, clean up }
{ ALWAY CALL THIS, OR YOU WILL BE SORRY! }
end;
writeln('Click to quit');
while not Button do
 ;
end.
It now listens on port 80 (web server port) and recieves the GET request of a browser. This is shown in the textbox of the Mac where my TCPExample is running.

NewPassiveConnection.JPG

Working example listening on port 80. Will show you the browser call in a text box.

TCPExample80.zip

Next challenge..... I will try to send something back to the browser. Will I need this function?

 

function TCPSend (connection: TCPConnectionPtr; writePtr: ptr; writeCount: integer; push: boolean): OSErr;

 

Attachments

  • TCPExample80.zip
    11.3 KB · Views: 19

bbraun

Well-known member
Congrats! Don't worry about not being a programmer, this is how we learn.

TCPSend seems to be what you're looking for, use it the same way as in the initial example. The only real question is when you use it. If you only want to serve up the same document every time someone connects, you can probably get away with just sending it unconditionally when someone connects. Otherwise, you'll need to receive some data, look at it, and choose what to send based on what you received.

 

mactjaap

Well-known member
You are right! I added a cr and lf between header and data and it works!

I also added a

Code:
CloseConnection(cer.connection); { Close our side of the connection }
And my version of the MacTjaapHTTPD server works!

Now the next challange... how to reopen the NewPassiveConnection after a requests is handeld and closed.... so new connections can be made!!!

 

mactjaap

Well-known member
Today I rounded up my experiment to build a small web server. It is working; returning a valid header and a small html page. All hardcoded in the app.

Not very usefull .... but a very nice way to see how one could develop a web server in the early '90s. This code is from around 1992 and that is the same era web servers began do exits.

See some information on Wikipedia about this:

A NeXT Computer was used by Berners-Lee as the world's first web server and also to write the first web browser, WorldWideWeb, in 1990. By Christmas 1990, Berners-Lee had built all the tools necessary for a working Web: the first web browser (which was a web editor as well); the first web server; and the first web pages, which described the project itself.
.............

On 6 August 1991, Berners-Lee posted a short summary of the World Wide Web project on the alt.hypertext newsgroup. This date also marked the debut of the Web as a publicly available service on the Internet, although new users only access it after August 23. For this reason this is considered the internaut's day. Many newsmedia have reported that the first photo on the web was uploaded by Berners-Lee in 1992, an image of the CERN house band Les Horribles Cernettes taken by Silvano de Gennaro;
To add more headers and more html code I had to add some more variables and TCPSend routines.

mactjaaphttpd-v1.0.JPG

Here is my complete code:

Code:
program MacTjaapHTTPD10;

{ From Peter's PNL Libraries }
{ Copyright 1992 Peter N Lewis }
{ This source may be used for any non-commercial purposes as long as I get a mention }
{ in the About box and Docs of any derivative program.  It may not be used in any commercial }
{ application without my permission }

uses
 TCPTypes, TCPStuff, TCPConnections;



const
 header = 'HTTP/1.1 200 OK';
 headerserver = 'Server: MacTjaapHTTPD/0.1';
 headerdate = 'Date: Fri, 25 Oct 2013 23:54:00';
 headerconnection = 'Connection: close';
 headerlast = 'Last-Modified: Fri, 20 Apr 1962 01:30:00';
 headercontent = 'Content-Type: text/html';

 html = 'This is the welcome page of a MacTjaapHTTPD server for Macintosh.
';
 html2 = 'It is based on TCPExample from Peter N Lewis, copyright 1992

';
 html3 = '

On this page is not much, but I will provide a link to the post in the 68kMLA forum:
';
 html4 = 'click here';

 dest_name = 'www.apache.org';
 nul = chr(0);
 lf = chr(10);
 cr = chr(13);
 localport = 80;
 remotehost = 0;
 remoteport = 0;
 dataptr = 0;



var
 oe: OSErr;
 cp: connectionIndex;
 quitNow: boolean;
 cer: connectionEventRecord; { Event record for TCP events, simmilar to EventRecord }
 s: str255;
 t: str255;
 u: str255;
 v: str255;

 count: longInt;
 gotlinefeed: boolean;
begin
ShowText;
quitNow := false;
oe := InitConnections; { Startup the TCP units }
if oe = noErr then begin
 oe := FindAddress(cp, dest_name, nil);
 if oe = noErr then begin
  count := 0;
  while not quitNow do begin
   if GetConnectionEvent(any_connection, cer) then begin { Get the next TCP event }
    case cer.event of
     C_Found:  begin






{function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;}

      oe := NewPassiveConnection(cp, Default_TCPBUFFERSIZE, localport, remotehost, remoteport, nil);





     end;
     C_SearchFailed:  begin
      writeln('Couldn''t fine the address for ', dest_name);
      quitNow := true;
     end;
     C_Established:  begin { Happens once per succesful connection establishment }
      writeln('Connection Established');

      s := concat(header, cr, lf, headerserver, cr, lf, headerdate, cr, lf, headerlast, cr, lf, headercontent, cr, lf, cr, lf, html, cr, lf);
      t := concat(html2, cr, lf);
      u := concat(html3, cr, lf);
      v := concat(html4, cr, lf);

      oe := TCPSend(cer.tcpc, @s[1], length(s), true);
      oe := TCPSend(cer.tcpc, @t[1], length(t), true);
      oe := TCPSend(cer.tcpc, @u[1], length(u), true);
      oe := TCPSend(cer.tcpc, @v[1], length(v), true);

                           {to let the browser know that the page is sendI close the connection}
                           {function TCPClose (connection: TCPConnectionPtr; userptr: OSErrPtr): OSErr;}
      CloseConnection(cer.connection); { Close our side of the connection }



      if oe <> noErr then
      CloseConnection(cp); { Better close the connection if we can't send anything to it! }
     end;
     C_FailedToOpen: 
      writeln('Ooops, connection failed to open... Error is ', cer.value, ' Timed out is ', cer.timedout);
{ Example, network unreachable etc.  Error code is in cer.value }
     C_Closing:  begin
      writeln('Connection closing');{ Gets called when the connection starts closing down}
      CloseConnection(cer.connection); { Close our side of the connection }
     end;
     C_Closed:  begin
      writeln('Connection closed, quit now');
      quitNow := true; { The connection is closed, quit the program }
     end;
     C_CharsAvailable:  begin
{$PUSH}
{$R-}
      oe := TCPReceiveUpTo(cer.tcpc, 10, 60, @s[1], 255, count, gotlinefeed);
{ Recieve characters up to a line feed }
      if (count > 0) & (s[count] = lf) then { strip off linefeed }
      count := count - 1;
      if (count > 0) & (s[count] = cr) then { strip off cr }
      count := count - 1;
      s[0] := chr(count);
{$POP}
      if gotlinefeed then begin { if we got a linefeed, print the string, otherwise go round again and wait for more characters }
      writeln(s);
      count := 0;
      end;
     end;
    end;
   end;
  end;
 end;
 FinishEverything; { Close everything, clean up }
{ ALWAY CALL THIS, OR YOU WILL BE SORRY! }
end;
writeln('Click to quit');
while not Button do
 ;
end.
I will also add this latest version of the MacTjaapHTTPD server version 1.0.

MacTjaapHTTPD-V1.0.zip

For now I want to try to try some more:

- getting it working on System 6. Although System 7 was normal for 1992, System 6 has also MacTCP. So I hope it will run. For now the application starts, but immediately go to "Click to quit". Also the TCPExample App will do the same. My guess it doesn't call MacTCP in a right way. I have no clue what to about this so help is again appreciated!

- Reopen a listener after a connection is done. Now the application asked for "Click to quit" and can only handle one connection.... That is not what I want.... I tried a goto routine, but couldn't get it working....

- Maybe make it a real application. With a menu, about info, etc. Maybe that is possible in Turbo Pascal I use now. I will find out. It is the first Macintosh App I have made... so much to learn!

I specially want to thank bbraun for help with the building of this app!

 

Attachments

  • MacTjaapHTTPD-V1.0.zip
    13.9 KB · Views: 19

mactjaap

Well-known member
BREAKING NEWS ( well.. for me it is :lol: )

I managed to get the code running on System 6. I think I can say now that it is worlds first web server able to run on System 6.

To be precise, running System 6.0.5 with MacTCP 2.0.6. It doesn't run without any special treat. You first have to start NCSA telnet 2.6. Connect to a host, in my case to the running MacIPgw (see http://www.macip.net). Ones you have connected you can close NCSA Telnet. If you ping to your System 6 macintosh you will see that ICMP traffic is still running even when NCSA Telnet is closed. Now it is save to startup MacTjaapHTTPD ( version 0.3 beta)

For now I'm a happy man! I will see how low I can go with resources!

MacTjaapHTTPD-V03.zip

O yes... what did I changed in my code. Mainly I removed the name lookup what was in the original code. I could see in Turbo Pascal that if there was an error in name lookup it will jump to "click to close". So.... I removed the lookup and ...IT WORKED!

 

Attachments

  • MacTjaapHTTPD-V03.zip
    11.6 KB · Views: 18

mactjaap

Well-known member
Still going strong!!!

I'm currently on version 0.5.

The program now loops. That means that after a connection is made and closed a new listener is openen on port 80. So you can leave the program running and handle more requests. I used a goto routine for this....but it is now endless....

My questions for today:

- How do you make it possible to stop the program. Hitting a certain key would be great, like ...halt if q is hit.... but I don't know how to do that.

- I would like to run it as a real application, so with a menu or in the background. Does anyone has some (very simple) example code for me?

This is the code. Inerested to run MacTjaapHTTPD...just give me a PM and I send you a copy.

Code:
program MacTjaapHTTPD05;

{This is the code for a very simple test only web server. It can be build with Think Pascal and Peter's PNL Libraries and TCPExample}
{Version 0.5 is now capable of looping the opening of port 80, so you can have more then one request....that is nice for a web server }
{MacTjaapHTTPD runs on 6.0.5 and higher with MacTCP}

{ From Peter's PNL Libraries }
{ Copyright 1992 Peter N Lewis }
{ This source may be used for any non-commercial purposes as long as I get a mention }
{ in the About box and Docs of any derivative program.  It may not be used in any commercial }
{ application without my permission }


uses
 TCPTypes, TCPStuff, TCPConnections;




const
 header = 'HTTP/1.1 200 OK';
 headerserver = 'Server: MacTjaapHTTPD/0.5';
 headerdate = 'Date: Fri, 25 Oct 2013 23:54:00';
 headerconnection = 'Connection: close';
 headerlast = 'Last-Modified: Fri, 20 Apr 1962 01:30:00';
 headercontent = 'Content-Type: text/html';

 html = 'This is the welcome page of a MacTjaapHTTPD server for Macintosh.
';
 html2 = 'It is based on TCPExample from Peter N Lewis, copyright 1992

';
 html3 = '

On this page is not much, but I will provide a link to the post in the 68kMLA forum:
';
 html4 = 'click here';


 nul = chr(0);
 lf = chr(10);
 cr = chr(13);
 localport = 80;
 remotehost = 0;
 remoteport = 0;
 dataptr = 0;

label
 1;


var
 oe: OSErr;
 cp: connectionIndex;
 quitNow: boolean;
 cer: connectionEventRecord; { Event record for TCP events, simmilar to EventRecord }
 s: str255;
 t: str255;
 u: str255;
 v: str255;

 count: longInt;
 gotlinefeed: boolean;
 YN: Char;
 Name: string;



begin
ShowText;






1:
writeln('start listening on port 80');
quitNow := false;
oe := InitConnections; { Startup the TCP units }

if oe = noErr then begin
 count := 0;



 while not quitNow do begin

  oe := NewPassiveConnection(cp, Default_TCPBUFFERSIZE, localport, remotehost, remoteport, nil);
{    writeln(' hier ben je 1');    }
{while not Button do}
{;}

  if GetConnectionEvent(any_connection, cer) then begin


   case cer.event of
    C_Found:  begin
     writeln('hier ben je 2');






{---function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;}

     oe := NewPassiveConnection(cp, Default_TCPBUFFERSIZE, localport, remotehost, remoteport, nil);




    end;

    C_Established:  begin { Happens once per succesful connection establishment }
     writeln('Connection Established');

     s := concat(header, cr, lf, headerserver, cr, lf, headerdate, cr, lf, headerlast, cr, lf, headercontent, cr, lf, cr, lf, html, cr, lf);
     t := concat(html2, cr, lf);
     u := concat(html3, cr, lf);
     v := concat(html4, cr, lf);

     oe := TCPSend(cer.tcpc, @s[1], length(s), true);
     oe := TCPSend(cer.tcpc, @t[1], length(t), true);
     oe := TCPSend(cer.tcpc, @u[1], length(u), true);
     oe := TCPSend(cer.tcpc, @v[1], length(v), true);

                           {to let the browser know that the page is sendI close the connection}
                           {function TCPClose (connection: TCPConnectionPtr; userptr: OSErrPtr): OSErr;}
     CloseConnection(cer.connection); { Close our side of the connection }

{doet al wat----while not Button do}
{;}

     if oe <> noErr then
      CloseConnection(cp); { Better close the connection if we can't send anything to it! }
    end;
    C_FailedToOpen: 
     writeln('Ooops, connection failed to open... Error is ', cer.value, ' Timed out is ', cer.timedout);
{ Example, network unreachable etc.  Error code is in cer.value }
    C_Closing:  begin
     writeln('Connection closing');{ Gets called when the connection starts closing down}
     CloseConnection(cer.connection); { Close our side of the connection }
    end;
    C_Closed:  begin
     writeln('Connection closed, quit now');
     quitNow := true; { The connection is closed, quit the program }


{ gaat na klik weer door---while not Button do}
{;}
    end;
    C_CharsAvailable:  begin
{$PUSH}
{$R-}
     oe := TCPReceiveUpTo(cer.tcpc, 10, 60, @s[1], 255, count, gotlinefeed);
{ Recieve characters up to a line feed }
     if (count > 0) & (s[count] = lf) then { strip off linefeed }
      count := count - 1;
     if (count > 0) & (s[count] = cr) then { strip off cr }
      count := count - 1;
     s[0] := chr(count);
{$POP}
     if gotlinefeed then begin { if we got a linefeed, print the string, otherwise go round again and wait for more characters }
      writeln(s);
      count := 0;
     end;
    end;
   end;
  end;

 end;
 FinishEverything; { Close everything, clean up }
{ ALWAY CALL THIS, OR YOU WILL BE SORRY! }

 writeln('Click to quit');
 goto 1;
 while not Button do
  ;
end;
end.
end.
 
Top