10

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

Community
  • 1
  • 1
Vi.
  • 37,014
  • 18
  • 93
  • 148

4 Answers4

4

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.

Newton Falls
  • 2,148
  • 3
  • 17
  • 22
  • No, I wasn't aware of `splice` (I only theoretically knew about `sendfile`). I'll think and test it. – Vi. Apr 21 '10 at 06:39
  • @Vi.: I guess you were using TCP sockets ? It seems this approach won't work for UDP sockets ? – Paul Praet Mar 06 '13 at 11:57
  • 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. – Vi. Mar 06 '13 at 17:52
2

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.

Community
  • 1
  • 1
caf
  • 233,326
  • 40
  • 323
  • 462
  • 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). – Vi. Apr 21 '10 at 06:38
  • 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). – caf Apr 21 '10 at 06:46
  • 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. – Vi. Apr 21 '10 at 08:23
  • With `read`/`write` it remains in the buffer that you did the `read` into (which would typically be a stack-allocated local). – caf Apr 21 '10 at 21:39
0

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

  • 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. – Vi. Aug 23 '12 at 21:39
0

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

man unix
Bryan Drewery
  • 2,569
  • 19
  • 13
  • 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. – Vi. Apr 20 '10 at 18:22