[Larceny-users] is this a brain-problem or a bug?
Ray Racine
ray.racine at comcast.net
Mon Jan 7 22:46:58 EST 2008
Regarding the 32 / 64 bit. I have a 2 CPU 64 bit Opteron (Sun
workstation) running 64 bit Fedora Linux and FFI (including sockets) is
working solid.
I outlined the changes necessary in a posting in Nov.
https://lists.ccs.neu.edu/pipermail/larceny-users/2007-November/000163.html
The middle change is in foreign-ctools. CTools invokes the system's C
compiler to determine the C structure layout offset etc.. all it does is
add a -m32 option which puts gcc in 32 compiler mode. This works on
Linux/gcc but I expect this or its analogy would work on other
system/compiler combinations. (You are on Sparc/Solaris??) This may
simplify your debugging environment.
------
Regarding the overall problem of not working. I think you alluded to
what I think is the problem, INET vs DOMAIN sockets.
C sample is AF_UNIX (which is same-as AF_LOCAL). As you pointed out
Larceny defaults to AF_INET. AFAIK everything should work just fine if
you were to set the correct FAMILY-DOMAIN/PROTOCOL explicitly.
Something along the lines of this should work. Note the sockaddr
structure family field is explicitly set to AF_UNIX.
(define server-socket-accept
(lambda (socket flags)
(let ((addr (make-sockaddr_in))
(addrlen (make-bytevector sizeof:int))
(nonblocking? (memq 'nonblocking flags)))
;; SET TO AF_UNIX
(sockaddr_in.sin_family-set! addr AF_UNIX)
(%set-int addrlen 0 SOCKADDR_IN-SIZE)
(let ((sdesc (accept (socket-descriptor socket) addr addrlen)))
(if (invalid? sdesc)
(report-error "accept")
(values (make-socket sdesc flags #f #f
'OK)(sockaddr_in.sin_addr addr)))))))
If you set it to AF_UNIX, I believe no other change would be required.
Hope this helps.
Ray
On Mon, 2008-01-07 at 19:00 +0000, David Rush wrote:
> Hi there,
>
> I have been working with the socket interface on Unix in an attempt to
> build a native FCGI module for Larceny, and I am frankly stumped. As
> far as I can tell, I have two programs which should be functionally
> identical. The difference is that one is written in C using the socket
> interface directly and the other is written in Larceny, using the FFI.
>
> So the C code:
>
> #include <fastcgi.h>
> #include <stdio.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <sys/un.h>
> #include <unistd.h>
> #include <stdarg.h>
> #include <stdlib.h>
> #include <string.h>
>
> int main(int c, char** v) {
> struct sockaddr_un addr;
> socklen_t addrlen = 0;
> int cx = 0;
> FILE* log = fopen("raw-fcgi.log", "w");
> fprintf(log, "started FCGI process\n");
> fflush(log);
>
> addr.sun_family = AF_UNIX;
> for(cx = accept(FCGI_LISTENSOCK_FILENO, (struct sockaddr*)&addr, &addrlen);
> cx >= 0;
> cx = accept(FCGI_LISTENSOCK_FILENO, (struct sockaddr*)&addr,
> &addrlen)) {
> FCGI_Header hdr;
> fprintf(log, "got a request, sockaddr family = %d\n", addr.sun_family);
> fflush(log);
> read(cx, (char*)&hdr, sizeof(hdr));
>
> fprintf(log, " version = %d\n", hdr.version);
> fprintf(log, " type = %d\n", hdr.type);
> fprintf(log, " reqID(B1) = %d\n", hdr.requestIdB1);
> fprintf(log, " reqID(B0) = %d\n", hdr.requestIdB0);
> fprintf(log, " reqID = %d\n", hdr.requestIdB1 * 256 + hdr.requestIdB0);
> fprintf(log, " length(B1) = %d\n", hdr.contentLengthB1);
> fprintf(log, " length(B0) = %d\n", hdr.contentLengthB0);
> fprintf(log, " length = %d\n", hdr.contentLengthB1 * 256 +
> hdr.contentLengthB0);
> fflush(log);
> close(cx); }
>
> fprintf(log, "all done\n");
> return 0; }
>
> produces the the following output in raw-fcgi.log
>
> started FCGI process
> got a request, sockaddr family = 1
> version = 1
> type = 1
> reqID(B1) = 0
> reqID(B0) = 1
> reqID = 1
> length(B1) = 0
> length(B0) = 8
> length = 8
>
> and the larceny code:
>
> (require 'foreign-ctools)
> (require 'foreign-stdlib)
> (require 'socket)
> (require 'time)
> (require 'srfi-9)
>
>
> (define (ftimestamp)
> (call-with-values current-utc-time
> (lambda (secs fracs)
> (let ((fracs* (number->string fracs)))
> (call-with-output-string
> (lambda (p)
> (display secs p)
> (display #\. p)
> (display (make-string (- 6 (string-length fracs*)) #\0) p)
> (display fracs* p)
> )))
> )))
>
>
> (define (flog s)
> (let ((entry
> (call-with-output-string
> (lambda (p)
> (display `(,(ftimestamp)
> , at s) p)
> (newline p)
> )))
> (f ((foreign-procedure "fopen" '(string string) 'void*)
> "fcgi.log" "a")))
> ((foreign-procedure "fputs" '(string void*) 'int) entry f)
> ((foreign-procedure "fclose" '(void*) 'void) f)
> (display entry (current-output-port))
> (display entry (current-error-port))
> ))
>
>
> (define-c-struct ("struct sockaddr_un" make-sockaddr_un
> (include<> "sys/un.h"))
> ("sun_family"
> (sockaddr_in.sun_family %get-ushort))
> ("sun_path"
> (sockaddr_in.sun_path %get-string))
> )
>
>
> (define (fastcgi argv)
> (flog `(starting fcgi listen process))
> (let accept-requests ()
> (let ((addr (make-sockaddr_un))
> (addrlen (make-bytevector sizeof:int)))
> (flog `(got the blinking structures allocated))
> (let ((s ((foreign-procedure "accept" '(int boxed boxed) 'int)
> 0 addr addrlen)))
> (flog `(received connection on ,s))
> (let* ((bytes (make-bytevector 8))
> (got ((foreign-procedure "read" '(int boxed int) int)
> fd bytes 8)))
> (flog `(read ,got header bytes from ,fd))
> (if (>= got 8)
> (let ((version (bytevector-ref bytes 0))
> (type (bytevector-ref bytes 1))
> (id (+ (bytevector-ref bytes 2)
> (* 256 (bytevector-ref bytes 3))))
> (length (+ (bytevector-ref bytes 4)
> (* 256 (bytevector-ref bytes 5))))
> (padding (bytevector-ref bytes 6)))
> (flog `((version ,version)
> (type ,type)
> (request-id ,id)
> (length ,length))))
> (flog `(no header))
> ))
> (close-output-port out)
> (close-input-port in)
> (flog `(finished transaction))
> (accept-requests)
> )))
> (flog `(all done now))
> (exit 0)
> )
>
> (dump-heap "fcgi.image" fastcgi)
> (exit 0)
>
> When appropriately packaged up and run produces the following output
> in fcgi.log (timestamps are seconds.micros)
>
> (1199729962.355512 starting fcgi listen process)
> (1199729962.400555 got the blinking structures allocated)
> (1199729962.406820 received connection on 4)
> (1199729971.981496 starting fcgi listen process)
> (1199729971.992796 got the blinking structures allocated)
>
> which since I don't print the PIDs to the log makes it a little bit
> hard to interpret, but I am fairly convinced (by looking at the server
> error logs and ps output) that what is happening that the original
> FCGI process starts and receives a connection, then hangs trying to
> read from that connection. When the FCGI watchdog in the Apache server
> notices the hung process it starts another instance (usually after
> about 10 seconds).
>
> Now it is clear from the raw-fcgi.c output that the Apache FCGI module
> is using Unix domain sockets to talk to the FCGI process, and I'm
> wondering if this is a case that is somehow broken in larceny (the
> socket.sch code pretty clearly only knows about AF_INET), or if there
> is some other I/O configuration difference between the Larceny
> run-time and the raw C code.
>
> Can anybody point me in the right direction here? This has been
> extremely hard to debug, since - for reasons I do not fully understand
> - my 32-bit larceny image can't load the socket library on my x86_64
> system which means I am debugging remotely on Dreamhost's servers
> underneath the Apache server. Talk about debugging at the end of a
> ten-foot pole!
>
> Thanks in advance -
>
> david rush
More information about the Larceny-users
mailing list