[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 483
  • Last Modified:

Port Mapping (Winsock API)

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
freedumb
Asked:
freedumb
  • 4
1 Solution
 
AvonWyssCommented:
0
 
AvonWyssCommented:
(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
 
AvonWyssCommented:
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
 
AvonWyssCommented:
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
 
freedumbAuthor Commented:
Thanks for all your help, got it all working. :)
0

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now