Taylor,
The code attached at the bottom does what you want, without need for linking to os_io.c . In case Gambit would change it might need update.
Mikael
2010/1/17 Taylor Venable taylor@metasyntax.net
Hi, I've been hacking a lot the last couple days to try to figure out how to get the file descriptor for a socket created with open-tcp-client on Linux. I've finally got it figured out, and to do it I obtain the rdevice for the port via the condition variable and in C cast it to a ___device_tcp_client_struct to extract the 's' field (the file descrip- tor). There's only one problem: whereas ___device_stream_struct is defined in os_io.h and I can conveniently include it from my C code, the definition of ___device_tcp_client_struct is in os_io.c and I had to copy it out and paste it into my code. Is there something about that definition that makes its location in the C source (rather than the header) necessary? I'd prefer to just #include something, but if the only way is to copy/paste those lines then I'll just continue to do that. Thanks for any advice.
-- Taylor Venable http://metasyntax.net/
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
-
(c-declare " #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include </usr/local/Gambit-C/current/lib/os_io.h> // I'm well aware this is not the default installation directory for this file. // Though let's use it for convention. Requires os.h and os_time.h . ")
; How to get file descriptor of TCP socket port: ; ##make-device-port on _io.scm 1202 puts its rdevice and wdevice parameters ; as condition-variable-name of ##vector-ref 44 and 45 of the port. ; ##make-device-port is invoked by ##make-device-port-from-single-device of row 1560, ; which is in turn invoked by ##make-tcp-client-port 5767, which is in turn invoked ; by ##open-tcp-client on row 5816. Please note that rdevice and wdevice are the ; same variable. It is generated by ##os-device-tcp-client-open invoked on ; row 5807, that's declared in _kernel.scm row 3966, which calls ___os_device_tcp_client_open ; that's declared in os_io.c row 7272. So the return value contains this. ; The return value is generated by ___NONNULLPOINTER_to_SCMOBJ (defined in c_intf.c 4617) that convers an arbitrary pointer ; to a SCMOBJ. In this case it's the ___device_tcp_client structure dev. ; ; The socket (i.e. the file descriptor) is generated by a call to the OS function socket ; on row 3407 in the function create_tcp_socket. The result is written to the SOCKET_TYPE ; pointer argument that's the first parameter of the function. The function is called by ; ___device_tcp_client_setup_from_sockaddr declared on row 3559. After generation it passes ; the socket into ___device_tcp_client_setup_from_socket declared on row 3472, as third parameter. ; As first parameter, the function takes the ___device_tcp_client. It copies the socket into the ->s ; property of the structure. ; ; ___device_tcp_client is declared on row 2960 in os_io.c . The structure is designed like that first ; in it, there's a ___device_stream, then the socket comes. ___device_stream is defined in os_io.h row 414. ; SOCKET_TYPE is declared in os_io.c and is defined to int on USE_POSIX systems, and to SOCKET on USE_WIN32 ; systems. ; ; Thus, to get the socket file descriptor of an open TCP socket port, take the int sizeof(___device_stream) ; bytes into (condition-variable-name (##vector-ref port 44)) . ; ; ** In case this function stops working with a new version of Gambit, ; ** First check if the ___device_tcp_client structure has been changed, that is, if the first property is not ; ** a ___device_stream and the second the socket anymore. ; ** Second, check if the name parameter of vector-index no. 44 of TCP connection ports aren't ; ** (see macro-device-port-rdevice-condvar's definition) ; ** foreign-objects in general, and ___device_tcp_client values in particular, anymore. Use (##vector->list port).
(define (tcp-socket-port->fd port) (let* ((___device_tcp_client (condition-variable-name (util#device-port-rdevice-condvar port))) (ptr (foreign-address ___device_tcp_client))) ((c-lambda (unsigned-long) int #<<C int ptrv = ___arg1; // fprintf(stderr,"In C now, the pointer value is %i. sizeof(___device_stream) is %i.\n\n",ptrv,sizeof(___device_stream)); // ___device_stream* v = ___CAST(___device_stream*,(int*) ptrv); // fprintf(stderr,"v is %i.\n",(int) v); ptrv += sizeof(___device_stream); int* ptr = (int*) ptrv; // fprintf(stderr,"In C now, after having added to the pointer, it's %i (%i). The value found at its location is %i.\n\n",(int) ptr,ptrv,*ptr); ___result = *ptr; C ) ptr)))
Afficher les réponses par date
On Sun, 2010-01-17 at 13:10 +0100, Mikael wrote:
The code attached at the bottom does what you want, without need for linking to os_io.c . In case Gambit would change it might need update.
Thanks for the alternate approach. Specifically I've been looking at using this for adding libevent support; the code is checked into my CVS repository on my website at
http://metasyntax.net/cgi-bin/cvsweb/Libraries/Scheme/libevent/
A question about your approach: doesn't this assume that the socket file descriptor will always be located in memory immediately after the device stream struct base? It seems like that would be prone to the same problems of a change in Gambit that including the definition of ___device_tcp_client_struct would, but perhaps with less possibility of the compiler warning you.
Is there some trick to accessing util#device-port-rdevince-condvar? When I compile that I get:
WARNING -- "util#device-port-rdevice-condvar" is not defined
for which reason in my code I use (##include "_gambit#.scm") and then call macro-device-port-rdevice-condvar.
(define (tcp-socket-port->fd port) (let* ((___device_tcp_client (condition-variable-name (util#device-port-rdevice-condvar port))) (ptr (foreign-address ___device_tcp_client))) ((c-lambda (unsigned-long) int #<<C int ptrv = ___arg1; // fprintf(stderr,"In C now, the pointer value is %i. sizeof(___device_stream) is %i.\n\n",ptrv,sizeof(___device_stream)); // ___device_stream* v = ___CAST(___device_stream*,(int*) ptrv); // fprintf(stderr,"v is %i.\n",(int) v); ptrv += sizeof(___device_stream); int* ptr = (int*) ptrv; // fprintf(stderr,"In C now, after having added to the pointer, it's %i (%i). The value found at its location is %i.\n\n",(int) ptr,ptrv,*ptr); ___result = *ptr; C ) ptr)))
Thanks,
2010/1/17 Taylor Venable taylor@metasyntax.net
A question about your approach: doesn't this assume that the socket file descriptor will always be located in memory immediately after the device stream struct base?
That's correct. In case this part of Gambit is rewritten, it will need to be updated.
That an update is needed would immediately be noticed, through that tcp-socket-port->fd would return an invalid, unusable return value.
As I get it, there are no plans nor reasons to change this part of Gambit.
It seems like that would be prone to the same problems of a change in Gambit that including the definition of ___device_tcp_client_struct would, but perhaps with less possibility of the compiler warning you.
Correct, the compiler would not warn.
Is there some trick to accessing util#device-port-rdevince-condvar? When I compile that I get:
WARNING -- "util#device-port-rdevice-condvar" is not defined
For the code for that support procedure, please refer to the (std net/tcpip) module of Black Hole's bundled libraries. You may want to remove "util#".
for which reason in my code I use (##include "_gambit#.scm") and then call macro-device-port-rdevice-condvar.