2 * asynchronous winsock services
4 * (C) 1996 Alex Korobka.
6 * FIXME: telftp16 (ftp part) stalls on AsyncSelect with FD_ACCEPT.
11 #include <sys/ioctl.h>
12 #include <sys/types.h>
18 #include <sys/so_ioctl.h>
19 #include <sys/param.h>
23 #include <sys/filio.h>
33 #define FASYNC FIOASYNC
36 #define __WS_ASYNC_DEBUG 0
38 static int __async_io_max_fd = 0;
39 static fd_set __async_io_fdset;
40 static ws_async_op* __async_op_list = NULL;
42 extern ws_async_ctl async_ctl;
45 fd_set fd_read, fd_write, fd_excp;
47 /* ----------------------------------- async/non-blocking I/O */
49 int WINSOCK_async_io(int fd, int async)
54 fcntl(fd, F_SETOWN, getpid());
57 fd_flags = fcntl(fd, F_GETFL, 0);
58 if (fcntl(fd, F_SETFL, (async)? fd_flags | FASYNC
59 : fd_flags & ~FASYNC ) != -1) return 0;
63 int WINSOCK_unblock_io(int fd, int noblock)
67 fd_flags = fcntl(fd, F_GETFL, 0);
68 if (fcntl(fd, F_SETFL, (noblock)? fd_flags | O_NONBLOCK
69 : fd_flags & ~O_NONBLOCK ) != -1) return 0;
73 int WINSOCK_check_async_op(ws_async_op* p_aop)
75 ws_async_op* p = __async_op_list;
76 while( p ) if( p == p_aop ) return 1;
81 void WINSOCK_cancel_async_op(HTASK16 hTask)
83 ws_async_op* p = __async_op_list;
85 if(hTask == GetWindowTask16(p->hWnd))
89 void WINSOCK_link_async_op(ws_async_op* p_aop)
91 if( __async_op_list ) __async_op_list->prev = p_aop;
92 else FD_ZERO(&__async_io_fdset);
94 p_aop->next = __async_op_list;
96 __async_op_list = p_aop;
98 FD_SET(p_aop->fd[0], &__async_io_fdset);
99 if( p_aop->fd[0] > __async_io_max_fd )
100 __async_io_max_fd = p_aop->fd[0];
103 void WINSOCK_unlink_async_op(ws_async_op* p_aop)
105 if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
107 { p_aop->prev->next = p_aop->next;
108 if( p_aop->next ) p_aop->next->prev = p_aop->prev; }
109 FD_CLR(p_aop->fd[0], &__async_io_fdset);
110 if( p_aop->fd[0] == __async_io_max_fd )
114 /* ----------------------------------- SIGIO handler -
116 * link_async_op/unlink_async_op allow to install generic
117 * async IO handlers (provided that aop_control function is defined).
119 * Note: AsyncGetXbyY expilicitly raise it.
122 void WINSOCK_sigio(int signal)
124 struct timeval timeout;
128 check_set = __async_io_fdset;
129 memset(&timeout, 0, sizeof(timeout));
131 while( select(__async_io_max_fd + 1,
132 &check_set, NULL, NULL, &timeout) > 0)
134 for( p_aop = __async_op_list;
135 p_aop ; p_aop = p_aop->next )
136 if( FD_ISSET(p_aop->fd[0], &check_set) )
137 if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE )
141 kill(p_aop->pid, SIGKILL);
142 waitpid(p_aop->pid, NULL, WNOHANG);
144 WINSOCK_unlink_async_op( p_aop );
146 check_set = __async_io_fdset;
150 /* ----------------------------------- child process IPC */
152 static void _sigusr1_handler_child(int sig)
154 /* read message queue to decide which
155 * async_ctl parameters to update
157 * Note: we don't want to have SA_RESTART on this signal
158 * handler, otherwise select() won't notice changed fd sets.
161 signal( SIGUSR1, _sigusr1_handler_child );
162 while( msgrcv(async_qid, (struct msgbuf*)&async_ctl.ip,
163 MTYPE_PARENT_SIZE, MTYPE_PARENT, IPC_NOWAIT) != -1 )
165 /* only ip.lParam is updated */
167 printf("handler - event %08x\n", async_ctl.ip.lParam );
170 switch( async_ctl.ip.lParam )
172 /* These are events we are notified of.
175 case WS_FD_CONNECTED: async_ctl.lEvent &= ~WS_FD_CONNECT;
176 FD_SET(async_ctl.ws_sock->fd, &fd_read);
177 FD_SET(async_ctl.ws_sock->fd, &fd_write);
180 case WS_FD_ACCEPT: async_ctl.ws_sock->flags |= WS_FD_ACCEPT;
181 FD_SET(async_ctl.ws_sock->fd, &fd_read);
182 FD_SET(async_ctl.ws_sock->fd, &fd_write);
184 case WS_FD_OOB: async_ctl.lEvent |= WS_FD_OOB;
185 FD_SET(async_ctl.ws_sock->fd, &fd_excp);
187 case WS_FD_READ: async_ctl.lEvent |= WS_FD_READ;
188 FD_SET(async_ctl.ws_sock->fd, &fd_read);
190 case WS_FD_WRITE: async_ctl.lEvent |= WS_FD_WRITE;
191 FD_SET(async_ctl.ws_sock->fd, &fd_write);
198 static int notify_parent( unsigned flag )
200 if( flag & WSMSG_ASYNC_SELECT )
202 async_ctl.ip.mtype = MTYPE_CLIENT;
203 while( msgsnd(async_qid, (struct msgbuf*)&(async_ctl.ip),
204 MTYPE_CLIENT_SIZE, 0) == -1 )
206 if( errno == EINTR ) continue;
208 else if( errno == EIDRM ) _exit(0);
212 perror("AsyncSelect(child)");
216 kill(getppid(), SIGUSR1);
219 printf("handler - notify [%08x]\n", async_ctl.ip.lParam);
222 else /* use half-duplex pipe to handle variable length packets */
224 write(async_ctl.ws_aop->fd[1], &async_ctl.lLength, sizeof(unsigned) );
225 write(async_ctl.ws_aop->fd[1], async_ctl.buffer, async_ctl.lLength );
227 kill(getppid(), SIGIO); /* simulate async I/O */
230 printf("handler - notify aop [%d, buf %d]\n", async_ctl.lLength, async_ctl.ws_aop->buflen);
237 /* ----------------------------------- async select */
239 static void setup_fd_sets()
241 FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_ZERO(&fd_excp);
243 if( async_ctl.lEvent & WS_FD_OOB)
244 FD_SET(async_ctl.ws_sock->fd, &fd_excp);
245 if( async_ctl.lEvent & (WS_FD_ACCEPT | WS_FD_READ |
246 WS_FD_CONNECT | WS_FD_CLOSE) )
247 FD_SET(async_ctl.ws_sock->fd, &fd_read);
248 if( async_ctl.lEvent & (WS_FD_WRITE | WS_FD_CONNECT) )
249 FD_SET(async_ctl.ws_sock->fd, &fd_write);
252 static void setup_sig_sets(sigset_t* sig_block)
254 sigemptyset(sig_block);
255 sigaddset(sig_block, SIGUSR1);
256 sigprocmask( SIG_BLOCK, sig_block, NULL);
257 signal( SIGUSR1, _sigusr1_handler_child );
260 void WINSOCK_do_async_select()
263 int sock_type, bytes;
265 getsockopt(async_ctl.ws_sock->fd, SOL_SOCKET, SO_TYPE, &sock_type, &bytes);
266 setup_sig_sets(&sig_block);
273 if( sock_type != SOCK_STREAM )
274 async_ctl.lEvent &= ~(WS_FD_ACCEPT | WS_FD_CONNECT);
275 sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
278 printf("select(2)[%i,%i,%i]... ",
279 FD_ISSET(async_ctl.ws_sock->fd, &fd_read),
280 FD_ISSET(async_ctl.ws_sock->fd, &fd_write),
281 FD_ISSET(async_ctl.ws_sock->fd, &fd_excp));
283 if( (val = select(async_ctl.ws_sock->fd + 1,
284 &fd_read, &fd_write, &fd_excp, NULL)) == -1 )
285 if( errno == EINTR ) continue;
287 printf("got %i events\n", val);
291 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
292 printf("handler - read is READY! [%08x]\n", async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE));
295 sigprocmask( SIG_BLOCK, &sig_block, NULL);
296 async_ctl.ip.lParam = 0;
297 if( async_ctl.ws_sock->flags & WS_FD_ACCEPT )
299 /* listening socket */
301 FD_CLR(async_ctl.ws_sock->fd, &fd_read);
302 FD_CLR(async_ctl.ws_sock->fd, &fd_write);
304 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_ACCEPT, 0 );
305 notify_parent( WSMSG_ASYNC_SELECT );
308 else /* I/O socket */
310 if( async_ctl.lEvent & WS_FD_CONNECT )
312 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_write) )
314 /* success - reinit fd sets to start I/O */
316 if( async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE))
317 FD_SET(async_ctl.ws_sock->fd, &fd_read);
318 else FD_CLR(async_ctl.ws_sock->fd, &fd_read);
319 if( async_ctl.lEvent & WS_FD_WRITE )
320 FD_SET(async_ctl.ws_sock->fd, &fd_write);
321 else FD_CLR(async_ctl.ws_sock->fd, &fd_write);
323 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, 0 );
324 async_ctl.lEvent &= ~WS_FD_CONNECT; /* one-shot */
326 else if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
328 /* failure - do read() to get correct errno */
330 if( read(async_ctl.ws_sock->fd, &bytes, 4) == -1 )
331 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, wsaErrno() );
333 } else continue; /* OOB?? */
335 notify_parent( WSMSG_ASYNC_SELECT );
337 else /* connected socket */
340 if( async_ctl.lEvent & WS_FD_OOB )
341 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_excp) )
343 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_OOB, 0 );
344 async_ctl.lEvent &= ~WS_FD_OOB;
345 FD_CLR(async_ctl.ws_sock->fd, &fd_excp);
346 notify_parent( WSMSG_ASYNC_SELECT );
348 else FD_SET(async_ctl.ws_sock->fd, &fd_excp);
350 if( async_ctl.lEvent & WS_FD_WRITE )
351 if( FD_ISSET( async_ctl.ws_sock->fd, &fd_write ) )
353 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_WRITE, 0 );
354 async_ctl.lEvent &= ~WS_FD_WRITE;
355 FD_CLR(async_ctl.ws_sock->fd, &fd_write);
356 notify_parent( WSMSG_ASYNC_SELECT );
358 else FD_SET(async_ctl.ws_sock->fd, &fd_write);
360 if( async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE) )
361 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
365 if( sock_type == SOCK_RAW ) ok = 1;
366 else if( ioctl( async_ctl.ws_sock->fd, FIONREAD, (char*)&bytes) == -1 )
368 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_READ, wsaErrno() );
369 FD_CLR( async_ctl.ws_sock->fd, &fd_read );
373 if( bytes || ok ) /* got data */
376 if( ok ) printf("\traw/datagram read pending\n");
377 else printf("\t%i bytes pending\n", bytes );
379 if( async_ctl.lEvent & WS_FD_READ )
381 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_READ, 0 );
382 async_ctl.lEvent &= ~WS_FD_READ;
383 if( !(async_ctl.lEvent & WS_FD_CLOSE) )
384 FD_CLR( async_ctl.ws_sock->fd, &fd_read );
386 else if( !(async_ctl.lEvent & (WS_FD_WRITE | WS_FD_OOB)) )
388 sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
390 sigprocmask( SIG_BLOCK, &sig_block, NULL);
394 else /* 0 bytes to read */
396 val = read( async_ctl.ws_sock->fd, (char*)&bytes, 4);
397 if( errno == EWOULDBLOCK || errno == EINTR )
400 printf("\twould block..\n");
406 case 0: errno = ENETDOWN; /* ENETDOWN */
407 case -1: /* ECONNRESET */
408 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() );
412 async_ctl.lEvent &= ~(WS_FD_CLOSE | WS_FD_READ); /* one-shot */
413 FD_ZERO(&fd_read); FD_ZERO(&fd_write);
416 notify_parent( WSMSG_ASYNC_SELECT );
418 else FD_SET(async_ctl.ws_sock->fd, &fd_read);
420 } /* connected socket */
426 /* ----------------------------------- getXbyY requests */
428 static void _async_fail()
431 (h_errno < 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
432 : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
433 write(async_ctl.ws_aop->fd[1], &async_ctl.lLength, sizeof(unsigned) );
435 kill(getppid(), SIGIO); /* simulate async I/O */
440 void dump_ws_hostent_offset(struct ws_hostent* wshe)
443 char* base = (char*)wshe;
446 printf("h_name = %08x\t[%s]\n", (unsigned)wshe->h_name, base + (unsigned)wshe->h_name);
447 printf("h_aliases = %08x\t[%08x]\n", (unsigned)wshe->h_aliases,
448 (unsigned)(base + (unsigned)wshe->h_aliases));
449 ptr = (unsigned*)(base + (unsigned)wshe->h_aliases);
450 for(i = 0; ptr[i]; i++ )
452 printf("%i - %08x ", i + 1, ptr[i]);
453 printf(" [%s]\n", ((char*)base) + ptr[i]);
455 printf("h_length = %i\n", wshe->h_length);
458 void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
461 struct hostent* p_he;
463 close(async_ctl.ws_aop->fd[0]);
464 p_he = (flag & WSMSG_ASYNC_HOSTBYNAME)
465 ? gethostbyname(async_ctl.init)
466 : gethostbyaddr(async_ctl.init,
467 async_ctl.lLength, async_ctl.lEvent);
468 if( p_he ) size = WS_dup_he(pwsi, p_he, WS_DUP_SEGPTR | WS_DUP_OFFSET );
471 async_ctl.buffer = pwsi->buffer;
472 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
473 notify_parent( flag );
478 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
481 struct protoent* p_pe;
483 close(async_ctl.ws_aop->fd[0]);
484 p_pe = (flag & WSMSG_ASYNC_PROTOBYNAME)
485 ? getprotobyname(async_ctl.init)
486 : getprotobynumber(async_ctl.lEvent);
487 if( p_pe ) size = WS_dup_pe(pwsi, p_pe, WS_DUP_SEGPTR | WS_DUP_OFFSET );
490 async_ctl.buffer = pwsi->buffer;
491 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
492 notify_parent( flag );
497 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
500 struct servent* p_se;
502 close(async_ctl.ws_aop->fd[0]);
503 p_se = (flag & WSMSG_ASYNC_SERVBYNAME)
504 ? getservbyname(async_ctl.init, async_ctl.buffer)
505 : getservbyport(async_ctl.lEvent, async_ctl.init);
506 if( p_se ) size = WS_dup_se(pwsi, p_se, WS_DUP_SEGPTR | WS_DUP_OFFSET );
509 async_ctl.buffer = pwsi->buffer;
510 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
511 notify_parent( flag );