Solved

Port Mapping (Winsock API)

Posted on 2002-05-25
5
412 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
Comment Utility
0
 
LVL 14

Accepted Solution

by:
AvonWyss earned 200 total points
Comment Utility
(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
Comment Utility
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
Comment Utility
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
Comment Utility
Thanks for all your help, got it all working. :)
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This video discusses moving either the default database or any database to a new volume.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

763 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

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now