cURL / Mailing Lists / curl-library / Single Mail


Re: no custom read() write() callbacks

From: Leon Winter <>
Date: Sun, 24 Oct 2010 15:58:39 +0200


So this topic is interesting for me again after quite a long time ;)

Short reminder of the topic: Using CURL for HTTP operations using SSH
tunneled TCP connections set up by libssh2.

> > Good point again, we could indeed use CURLOPT_OPENSOCKETFUNCTION
> > along with CURLOPT_SOCKOPTDATA to pass our e.g. ssh channel.
> > However there is no "socket close function callback" atm but also i
> > macro sclose(). Since we are going to replace sread()/swrite() with
> > callbacks, we should probably to that with sclose() too.
> Yeah, I think so too.
> > Hopefully I havent missed something again ;)
> I think the best way forward from this point is to actually proceed
> and try to write your application and then see what kind of hooks
> libcurl needs to offer for it to work, and do some first basic shots
> at implementing them to see that the app lives.

In lib/connect.c, at line 842 the socket is setup by our custom
fopensocket (which is set beforehand via CURLOPT_OPENSOCKETFUNCTION)
and therefore it is assumed a normale socket is returned (this is also
required by specification for CURLOPT_OPENSOCKETFUNCTION).
(1) Therefore operations are done on this socket pointer like
tcpnodelay(), nosigpipe(), Curl_sndbufset() and verifyconnect().

When using libssh2 to setup a TCP channel we however does not have a
standard socket interface. We could save the raw socket which is used
for SSH operations and return it in CURLOPT_OPENSOCKETFUNCTION, but
this is probably not a good idea, since libcurl assume its the real
socket read/write operations take place - which it is not.
For further operations like read()/write() we will not use the raw
socket but the libssh2 channel, so it would be more reasonable to save
LIBSSH2_CHANNEL* instead of the channel struct, but we cannot return it
via CURLOPT_OPENSOCKETFUNCTION since a socket is expected to be

So now I am trying to figure out a sane approach to solve this things.
Unfortunately I am new to the libcurl codebase and hope for feedback.

My thoughts so far:

A new CURLoption "CURLOPT_SOCKPTR" which is a void* and point to our
libssh2 channel (or probably something else useful in the future).
The CURL easy code then checks CURLOPT_SOCKPTR. If is not set (== NULL)
it assumes its does things the normal way (like its done at the time).
If its set, no socket modifying functions are called on the socket,
like the ones in (1).
Additionally we need new CURLoption callbacks:
Which should fit fine to the already existing:

The read()/write()/close() replacements will operate on the libssh2
channel saved in CURLOPT_SOCKPTR and the real sockfd (which is returned

The weaknesses of this approach are:
- it is not really generic and awesome
- the internal socket pointer is never used (it is however intended to
  point to the socket that should be used), therefore we will need a
  lot of conditional checking for performing socket operations which is
  pretty bad
- at the moment this approach will not use any of CURLs libssh2
  integration, which also provide nice handling for fingerprint
  matching and stuff

On another note, there is an example shipped with libssh2 that sets up
SSH TCP forwarding and listens on a local socket for raw TCP. So we
could use CURLOPT_OPENSOCKETFUNCTION to fire up new TCP channels and
open up local ports. This solution would be pretty cheap and would not
require modifications to libcurl but would come with overhead for
establishing and maintaining our fake tcp sockets. Additionally we bind
lots of local ports which we would not need if we could do it the
direct way.

Leon Winter
List admin:
Received on 2010-10-24