[306] in Pthreads mailing list archive
fd_sysv.c
daemon@ATHENA.MIT.EDU (Stephen Tether)
Wed Apr 24 17:16:23 1996
Date: Wed, 24 Apr 1996 15:37:49 -0500
From: tether@MITLNS.MIT.EDU (Stephen Tether)
To: pthreads@MIT.EDU
In accept_fd() one has (1.60 beta 4 and 5):
/* Get the new kernel entry */
if (!((fd_kern = socket_tcp(fd_new)) < OK)) {
res = (struct T_conn_res *)buf;
res->PRIM_type = T_CONN_RES;
res->QUEUE_ptr = (queue_t *)&fd_kern;
/* Bug! ^^^^^^^^^^^^^^^^^^^ */
res->OPT_length = 0;
res->OPT_offset = 0;
res->SEQ_number = SEQ_number;
strbuf.maxlen = sizeof(union T_primitives) +sizeof(struct
sockaddr);
strbuf.len = sizeof(struct T_conn_ind) + (*namelen);
strbuf.buf = buf;
if (putmsg_timedwait_basic(fd, &strbuf, NULL, 0, NULL) == OK) {
return(fd_new);
}
machdep_sys_close(fd_kern);
}
This doesn't work because the QUEUE_ptr field must contain the actual
address of the read-queue data structure associated with the STREAMS driver
for fd_kern. In fact, if you have strace active, running the above code
will produce complaints from the STREAMS TCP driver that the queue can't be
found. The accept() in fd_sysv.c is used under Solaris, and when I tried to
run a simple threaded server under that OS, it acted as if it got an
endless number of connection requests when in fact there was only one. This
is evidently due at least in part to accept() not working properly.
The queue data structure mentioned exists in kernel space, so you can't get
its address directly. After slogging through the gawdawful STREAMS
Programmer's Guide, I believe I know the solution. You need to use the
I_FDINSERT ioctl to insert the queue address for you and send your message
on its way. In that case the correct code should look something like this:
#include <stropts.h>
/* Get the new kernel entry */
if (!((fd_kern = socket_tcp(fd_new)) < OK)) {
struct strfdinsert insert;
res = (struct T_conn_res *)buf;
res->PRIM_type = T_CONN_RES;
res->OPT_length = 0;
res->OPT_offset = 0;
res->SEQ_number = SEQ_number;
insert.databuf.len = insert.databuf.maxlen = 0;
insert.flags = 0;
insert.fildes = fd_kern;
insert.ctlbuf.maxlen = sizeof(union T_primitives)
+sizeof(struct sockaddr);
insert.ctlbuf.len = sizeof(struct T_conn_ind) + (*namelen);
insert.buf.buf = buf;
insert.offset = (char*)&res->QUEUE_ptr - (char*)res;
if (ioctl(fd, I_FDINSERT, &insert) == OK) {
return(fd_new);
}
machdep_sys_close(fd_kern);
}
The I_FDINSERT ioctl can return EAGAIN since fd is marked as non-blocking,
so the ioctl jacket in fd.c should handle that in a way similar to
putmsg_timedwait_basic(). I_FDINSERT is described on the man page for
"streamio".
I'm tied up with another project right now, so I won't be able to actually
try this for a week or so. Maybe someone else would like to give it a whirl
before then.
- Steve Tether (tether@lns.mit.edu)