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.
(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)))