How can I "interconnect" two sockets in Linux?
Asked Answered
M

4

11

There are two connected sockets. How can I interconnect them?

  1. Data appeared on the one socket should be written to the other.
  2. EOF/FIN should propogate well. If one is half-closed, the other should also be half-closed.
int client = get_connected_client_socket();
int proxy = get_connected_proxy_socket();
negotiate_with_proxy(proxy);
iterconnect(client, proxy); 
// Now forgot about both client and proxy. 
// System should handle IO/shutdown/close. 
// Ideally even without any support of the user-space process.

Can Linux do it? Can it be done by tricking connection tracking to change tracking status of existing connection?

@related Determine how much can I write into a filehandle; copying data from one FH to the other

Manizales answered 20/4, 2010 at 17:29 Comment(0)
C
5

Are you aware of splice(). Based on your two questions I think this is where you are headed. Last I checked you can't do this in one splice call because both of file descriptors can't be sockets. But you should be able to do it in 2 calls (sockin->pipe->sockout). Also take a look at tee(). These may not be exactly what you want but from what I can figure they are in the ballpark.

Charland answered 20/4, 2010 at 19:43 Comment(3)
No, I wasn't aware of splice (I only theoretically knew about sendfile). I'll think and test it.Manizales
@Vi.: I guess you were using TCP sockets ? It seems this approach won't work for UDP sockets ?Unofficial
I'm not sure about UDP. If you know good approach (especially if it does not require process being still available for sockets to be still connected), you can tell it.Manizales
F
3

You will need a userspace process to hang around and do the copying of data from one socket to the other. It's pretty simple though:

  • Any data read from socket A, write to socket B;
  • Any data read from socket B, write to socket A;
  • If read returns 0 on socket A, call shutdown(SHUT_WR) on socket B;
  • If read returns 0 on socket B, call shutdown(SHUT_WR) on socket A;
  • Once both sockets have returned 0 from read, close both sockets and exit;
  • If either socket returns EPIPE, close both sockets and exit.

As Newton Falls mentions, you can use splice() to do this in a zero-copy manner, but that's just a performance enhancement; get it working with read/write first. You should be able to just fork() off a child to do this, which will make it "fire and forget" for your main process.

Ferriter answered 21/4, 2010 at 1:35 Comment(4)
Looks like splice is the thing can help. write is not good, because it can write less then I requested and I must save the rest somewhere. fork is not good, because of new connection => new process, also it needs careful handling of FDs (inherited/non-inherited).Manizales
As I said, splice() is just a performance enhancement - it too can splice less than you requested, and it won't make fork() any more or less useful (you still have to keep splice()ing until the connection is finished).Ferriter
If splice spliced less than I requested, the rest (size_I_requested - size_actually_spliced) will remain in a read FD, so I can splice it later when output will unblock without storing the data in my process. So pipe buffer will be used and I don't need to allocate/deallocate things in my program.Manizales
With read/write it remains in the buffer that you did the read into (which would typically be a stack-allocated local).Ferriter
C
0

A unix domain socket may help. See the man page:

man unix
Carty answered 20/4, 2010 at 17:39 Comment(1)
Not found anything useful in man 7 unix. I want my sockets to gain similar inter-influence as socketpair sockets have. I expect that interconnect to work with TCP, UNIX sockets and file descriptors.Manizales
T
0

Checkout the socat tool. That's the best tool to solve this kind of problems.

Thing answered 23/8, 2012 at 21:31 Comment(1)
I know and use it often. But the question is about how to do it in the program. Spawning socat - - for this is is too wasteful.Manizales

© 2022 - 2024 — McMap. All rights reserved.