Solved

Port Mapping (Winsock API)

Posted on 2002-05-25
5
440 Views
Last Modified: 2010-04-04
Just wondering if anyone can provide me with an example on how to map a tcp port to a remote host/port. i need it to allow multiple clients to connect to the port, and redirect data to/from the remote host. a feature that isn't neccesary, but would help would be the ability to have multiple mappings, and an ability to enumerate/stop them. i've been trying to do something like this for a while, with no luck. thank you for any help. (please note i am doing this in Winsock API, i am not interested in code which uses components).
0
Comment
Question by:freedumb
  • 4
5 Comments
 
LVL 14

Expert Comment

by:AvonWyss
ID: 7035171
0
 
LVL 14

Accepted Solution

by:
AvonWyss earned 200 total points
ID: 7035173
(EE sometimes has this "No Text" problem. Hopefully it will work now.)

The following should do it. Note that I don't use anything from the VCL, its all pure Windows-API, Winsock-API and RTL (RunTime Library). Even so, it's object-oriented, multi-threaded, small and pretty fast.

Ta allow you to see the essential parts of the code, I have only included the very necessary error checking. For instance, if the remote host is not reachable, you will not get an error. Therefore, I strongly suggest to add more error checking for a serious application.

The useage is displayed in the bottom part. In this example, I map the port 1025 to the FTP port on the local machine. Of course, you can use any other IP address/port combination.

{$APPTYPE CONSOLE}

program PortMapper;

uses
     SysUtils, Windows, Winsock;

type
     TPortMapper=class
     private
          FLocalEP, FRemoteEP: TSockAddrIn;
          FThreadHandle, FSyncEvent: THandle;
          FThreadID: Cardinal;
          FPending, FListener: TSocket;
          procedure Listener;
          procedure Transfer;
     public
          constructor Create(const LocalEndPoint, RemoteEndPoint: TSockAddrIn);
          destructor Destroy; override;
     end;

{ TPortMapper }

constructor TPortMapper.Create(const LocalEndPoint,     RemoteEndPoint: TSockAddrIn);
begin
     inherited Create;
     FLocalEP:=LocalEndPoint;
     FRemoteEP:=RemoteEndPoint;
     FThreadHandle:=BeginThread(nil, 0, Pointer(@TPortMapper.Listener), self, 0, FThreadID);
end;

destructor TPortMapper.Destroy;
begin
     CloseSocket(FListener);
     WaitForSingleObject(FThreadHandle, INFINITE);
     CloseHandle(FThreadHandle);
     inherited;
end;

procedure TPortMapper.Listener;
begin
     FSyncEvent:=CreateEvent(nil, False, False, nil);
     FListener:=Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // internet socket, stream, TCP protocol
     Bind(FListener, FLocalEP, SizeOf(FLocalEP));
     Listen(FListener, 5);
     repeat
          FPending:=Accept(FListener, nil, nil); // wait for incoming connection
          if FPending<>INVALID_SOCKET then begin // if valid socket, create connection thread
               CloseHandle(BeginThread(nil, 0, Pointer(@TPortMapper.Transfer), self, 0, FThreadID));
               WaitForSingleObject(FSyncEvent, INFINITE);
          end;
     until FPending=INVALID_SOCKET;
     CloseHandle(FSyncEvent);
end;

procedure TPortMapper.Transfer;
var
     Local, Remote: TSocket;
     FD: TFDSet;
     function TransferData(FromSock, ToSock: TSocket): Boolean;
     var
          Buffer: packed array[0..1023] of Byte;
          Waiting, Sent: Integer;
     begin
          IOCtlSocket(FromSock, FIONREAD, Waiting);
          repeat
               Sent:=Send(ToSock, Buffer, Recv(FromSock, Buffer, SizeOf(Buffer), 0), 0);
               Dec(Waiting, Sent);
          until (Sent<=0) or (Waiting<=0);
          Result:=Sent>0;
     end;
begin
     Local:=FPending;
     SetEvent(FSyncEvent);
     Remote:=Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     Connect(Remote, FRemoteEP, SizeOf(FRemoteEP));
     repeat
          FD_ZERO(FD);
          FD_SET(Local, FD);
          FD_SET(Remote, FD);
          Select(0, @FD, nil, nil, nil);
     until (FD_ISSET(Local, FD) and (not TransferData(Local, Remote))) or (FD_ISSET(Remote, FD) and (not TransferData(Remote, Local)));
     CloseSocket(Remote);
     CloseSocket(Local);
end;

var
     WSAData: TWSAData;
     Mapper: TPortMapper;
     LocalEP, RemoteEP: TSockAddrIn;

begin
     WSAStartup($101, WSAData);
     // the local endpoint is the address on which the mapper will listen locally
     LocalEP.sin_family:=AF_INET; // internet protocol
     LocalEP.sin_port:=HToNS(1025); // port 1025
     LocalEP.sin_addr.S_addr:=INADDR_ANY; // listen on all local IP addresses
     // the remote endpoint is the address where the mapper connects to
     RemoteEP.sin_family:=AF_INET;
     RemoteEP.sin_port:=HToNS(21); // remote port: 21 (FTP)
     RemoteEP.sin_addr.S_addr:=HToNL(INADDR_LOOPBACK); // remote IP: 127.0.0.1 (localhost)
     // the mapper object uses its own thread, so that the mapping is active after creation
     Mapper:=TPortMapper.Create(LocalEP, RemoteEP);
     ReadLn; // wait for return key
     Mapper.Free;
     WSACleanup;
end.
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 7035175
Of course, you can create as many instances of TPortMapper as you need for the different mappings, and you can store them in a list or array so that you can enumerate them.
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 7035180
freedumb, while looking at your profile I have seen that you are new to Experts Exchange. Therefore, let me welcome you!

In order to get the most out of Experts Exchange, please make sure to read and understand the guidelines and suggestions provided by the Expert Exchange staff. One point that often lead to misunderstandings is the grading and points distribution. The grade you award does not change the cost of points to you, but it does influence the amount of expert points an expert gets. Therefore, if you are not fully happy with a comment or answer provided, please do first give the expert to refine the comment or answer prior to giving a grade less than A. If you give a lesser grade, please also inform the expert why. This helps everyone here to provide a much higher quality of answers and comments than what you can find on most forums etc. on the net.
0
 

Author Comment

by:freedumb
ID: 7035428
Thanks for all your help, got it all working. :)
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Convert MS Word document to a PDF file 9 92
update joined tables 2 55
Firemonkey allowing RTL on android 6 47
scroll down TListBox component in Delphi 1 19
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

820 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question