home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vptcp110.zip / TELNETD.PAS < prev    next >
Pascal/Delphi Source File  |  1996-06-11  |  7KB  |  278 lines

  1. Program TelnetD;
  2. (* Simple Telnet Daemon for OS/2
  3.  * Copyright 1996 Antony T Curtis
  4.  *
  5.  * This program employs two threads per telnet session.
  6.  *
  7.  * I wish that System.Input and System.Output were threadvars....
  8.  *
  9.  *)
  10. Uses Os2Def,Os2Base,Use32,Sockets,Strings,Dos;
  11.  
  12. {$PMTYPE VIO}
  13.  
  14. Const
  15. {  Port      :UShort = 23;}
  16.   Service        ='telnet';
  17.   Protocol        ='tcp';
  18.  
  19.   Signon    :PChar    ='Simple TELNETD v1.00'#10#13+
  20.              'Copyright 1996 Antony T. Curtis'#10#13#10;
  21.   BadTelnet    :PChar    ='Unable to create telnet thread'#10#13#7;
  22.   BadMonitor    :PChar    ='Unable to create monitor thread'#10#13#7;
  23.  
  24.   MaxConnects        = 2;        (* Change this to whatever you like >= 1 *)
  25.  
  26. Type
  27.   PSocketInfo    =^SocketInfo;
  28.   SocketInfo    =record         (* This is data per telnet session *)
  29.     Active,Kill :Boolean;
  30.     Telnet    :TID;
  31.     Sock    :TSocket;
  32.     Client    :TSockAddr_in;
  33.     Terminate    :Boolean;
  34.     ttyin,ttyout:Text;
  35.   end;
  36.  
  37.   MyData    =record         (* UserData structure in TextRec *)
  38.     case boolean of
  39.       FALSE:(_    :Array[1..32] of Byte);
  40.       TRUE:(
  41.       Socket    :TSocket;
  42.       IOError    :Boolean);
  43.   end;
  44.  
  45.  
  46. Procedure Terminal(var i,o:Text);        (* The grand Telnet session! *)
  47. var
  48.   User,st    :string;
  49. begin                        (* Change this lot to whatever you like *)
  50.   writeln(o);
  51.   write(o,'username:');readln(i,User);
  52.   writeln(o);
  53.   writeln(o,'Hello ',User);
  54.   repeat
  55.     write(o,'>');
  56.     readln(i,st);
  57.   until st='exit';
  58.   writeln(o,'Bye!');
  59. end;
  60.  
  61. (*
  62.  * Socket Routines for Pascal Text files...
  63.  *)
  64.  
  65. function ConOutput(var F: TextRec): Integer; far;
  66. var
  67.   i        :Integer;
  68. begin
  69.   if F.BufPos <> 0 then
  70.   Sock_Write(MyData(F.UserData).Socket,F.BufPtr^,F.BufPos,i);
  71.   if SockError<0 then MyData(F.UserData).IOError:=True;
  72.   F.BufPos := 0;
  73.   F.BufEnd := 0;
  74.   ConOutput := 0;
  75. end;
  76.  
  77. function ConInput(var F: TextRec): Integer; far;
  78. var
  79.   i        :Integer;
  80. begin
  81.   Sock_Read(MyData(F.UserData).Socket,F.BufPtr^,F.BufSize,F.BufEnd);
  82.   if SockError<0 then MyData(F.UserData).IOError:=True;
  83.   F.BufPos := 0;
  84.   ConInput := 0;
  85. end;
  86.  
  87. function ConClose(var f:TextRec):Integer;far;
  88. begin
  89.   ConClose:=0;
  90. end;
  91.  
  92. function ConOpen(var f:TextRec):Integer;far;
  93. begin
  94.   if F.Mode=fmInput then begin
  95.     F.InOutFunc := @ConInput;
  96.     F.FlushFunc := nil;
  97.   end else begin
  98.     F.InOutFunc := @ConOutput;
  99.     F.FlushFunc := @ConOutput;
  100.   end;
  101.   F.CloseFunc := @ConClose;
  102.   ConOpen:=0;
  103. end;
  104.  
  105. Procedure AssignSocket(var f:Text;Sock:TSocket);
  106. begin
  107.   FillChar(f,sizeof(f),0);
  108.   with TextRec(f) do begin          // I learnt this from the TP4 manual
  109.     Handle:=$FFFFFFFF;               // It works alright...
  110.     MyData(UserData).Socket:=Sock;
  111.     Mode:=fmClosed;               // Nice to see that it still works in VP.
  112.     BufSize:=SizeOf(Buffer);
  113.     BufPtr:=@Buffer;
  114.     OpenFunc:=@ConOpen;
  115.     Name[0]:=#0;
  116.   end;
  117. end;
  118.  
  119. (*
  120.  * Session Threads
  121.  *)
  122.  
  123. Function MonitorThread(param1:Pointer):Longint;far;
  124. var
  125.   Info            :PSocketInfo absolute param1;
  126. begin
  127.   while not Info^.Terminate do begin
  128.                     (* Check for problems *)
  129.     if Info^.Kill or (MyData(TextRec(Info^.ttyin).UserData).IOError) then
  130.                     (* Kill if there is *)
  131.     if KillThread(Info^.Telnet)<>170 then begin
  132.       Info^.Terminate:=True;        (* Signal the death... *)
  133.       Sock_Close(Info^.Sock);
  134.     end;
  135.     DosSleep(1000);            (* Don't want this to tie up CPU... *)
  136.   end;
  137.   Info^.Active:=False;
  138. end;
  139.  
  140. Function TelnetThread(param1:pointer):Longint;far;
  141. var
  142.   Info            :PSocketInfo absolute param1;
  143.   Monitor        :Tid;
  144.   i            :Integer;
  145. begin
  146.   Info^.Terminate:=False;            (* Start the monitor thread *)
  147.   if BeginThread(nil,8192,MonitorThread,param1,
  148.          Create_Ready or Stack_Committed,Monitor)=0 then begin
  149.  
  150.                         (* Say "hello" to user *)
  151.     Sock_Write(Info^.Sock,Signon^,StrLen(Signon),i);
  152.     with Info^ do begin
  153.       AssignSocket(ttyin,Sock); reset(ttyin);    (* Setup the text files *)
  154.       AssignSocket(ttyout,Sock); rewrite(ttyout);
  155.       Terminal(ttyin,ttyout);             (* Run the terminal... *)
  156.       Close(ttyin);
  157.       Close(ttyout);    (* Could be an idea to use OS/2 Pipes instead of these? *)
  158.     end;
  159.   end else begin
  160.                         (* Tell user to go away *)
  161.     Sock_Write(Info^.Sock,BadMonitor^,StrLen(BadMonitor),i);
  162.   end;
  163.   Info^.Terminate:=True;
  164.   Sock_Close(Info^.Sock);            (* Close the session *)
  165. end;
  166.  
  167. var
  168.   Slot            :Array[0..MaxConnects-1] of SocketInfo;
  169.  
  170. Procedure Main;                  (* Gee, guess what this is? *)
  171. var
  172.   Sock,aSock        :TSocket;
  173.   Server,aClient    :TSockAddr_in;
  174.   i,j            :Integer;
  175.   Host            :THostEnt;
  176.   Serv            :TServEnt;
  177. begin
  178.   Writeln(Signon);                 (* Signon messsage *)
  179.  
  180.   FillChar(Slot,SizeOf(Slot),0);         (* Clear the sessions *)
  181.  
  182.   Sock_Init;
  183.   if SockError<>0 then begin
  184.     Writeln('Unable to initilise sockets');
  185.     halt;
  186.   end;
  187.  
  188.   if not GetServiceByName(Serv,Service,Protocol) then begin
  189.     Writeln('Service [',Service,'/',Protocol,'] not available');
  190.     halt;
  191.   end;
  192.   Writeln(' Using service ',Serv.s_name,'/',Serv.s_proto,' on port ',Serv.s_port);
  193.  
  194.   Sock:=Sock_New(AF_INET,SOCK_STREAM,0);    (* Open a socket *)
  195.   if Sock_Error then halt(1);
  196.  
  197.   Server.sin_family     := AF_INET;
  198.   Server.sin_port     := Serv.s_Port;
  199.   Server.sin_addr.s_addr := INADDR_ANY;
  200.  
  201.   Sock_Bind(Sock,TSockAddr(Server));         (* Bind the socket to the port *)
  202.   if Sock_Error then begin
  203.     Sock_Close(Sock);
  204.     halt(2);
  205.   end;
  206.   Writeln('Listening on socket ',Sock);
  207.  
  208.   while Sock_Listen(Sock,1) do begin        (* Listen for anything interesting *)
  209.  
  210.     i:=0;                    (* Look for a free session *)
  211.     while Slot[i].Active and (i<MaxConnects-1) do inc(i);
  212.  
  213.     if Slot[i].Active then begin        (* If there is none free *)
  214.  
  215.       aSock:=Sock_Accept(Sock,TSockAddr(aClient));
  216.       if Sock_Error then continue;
  217.                         (* Accept the connection anyway... *)
  218.       Sock_Write(aSock,BadTelnet^,StrLen(BadTelnet),j);
  219.                         (* and tell the user to bugger off *)
  220.       Sock_Close(aSock);
  221.       continue;
  222.     end;
  223.  
  224.     FillChar(Slot[i],SizeOf(Slot[i]),0);    (* Clear session entry *)
  225.  
  226.                         (* Accept it *)
  227.     Slot[i].Sock:=Sock_Accept(Sock,TSockAddr(Slot[i].Client));
  228.     if Sock_Error then continue;
  229.  
  230.     with Slot[i] do begin
  231.       Active:=True;                (* Flag as "in use" *)
  232.  
  233.       Write('Telnet request from ',inet_ntoa(Client.sin_addr));
  234.       if GetHostByAddr(Host,Client.sin_addr,AF_INET) then
  235.     Write(' [',Host.h_name,']');
  236.  
  237.       if BeginThread(nil,16384,TelnetThread,@Slot[i],
  238.            Create_Ready or Stack_Committed,Telnet)=0 then begin
  239.                         (* Start the session thread *)
  240.     writeln(' - Accepted. Slot ',i);
  241.       end else begin
  242.     writeln(' - declined.');
  243.  
  244.     Sock_Write(aSock,BadTelnet^,StrLen(BadTelnet),j);
  245.     Sock_Close(aSock);            (* Tell user to go away... *)
  246.  
  247.     Active:=False;
  248.  
  249.     continue;
  250.       end;
  251.     end;
  252.   end;
  253.   Sock_Error;
  254.   Sock_Close(Sock);
  255. end;
  256.  
  257. var
  258.   OldExit        :pointer;
  259. procedure MyExit;far;
  260. var
  261.   i,j            :Integer;
  262. begin
  263.   ExitProc:=OldExit;                (* Flag sessions to quit *)
  264.   for i:=0 to MaxConnects-1 do if Slot[i].Active then begin
  265.     Slot[i].Kill:=True;
  266.     Writeln('Signalled slot ',i);
  267.   end;
  268.   repeat
  269.     j:=0;                    (* Wait for them to quit *)
  270.     for i:=0 to MaxConnects-1 do if Slot[i].Active then inc(j);
  271.     write(#13,j:8,' active slots');
  272.   until j=0;
  273. end;
  274.  
  275. begin
  276.   Main;
  277. end.
  278.