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>
22 #define FASYNC FIOASYNC
26 #include <sys/filio.h>
35 #define __WS_ASYNC_DEBUG 0
37 static int __async_io_max_fd = 0;
38 static fd_set __async_io_fdset;
39 static ws_async_op* __async_op_list = NULL;
41 extern ws_async_ctl async_ctl;
44 fd_set fd_read, fd_write, fd_excp;
46 /* ----------------------------------- async/non-blocking I/O */
48 int WINSOCK_async_io(int fd, int async)
53 fcntl(fd, F_SETOWN, getpid());
56 fd_flags = fcntl(fd, F_GETFL, 0);
57 if (fcntl(fd, F_SETFL, (async)? fd_flags | FASYNC
58 : fd_flags & ~FASYNC ) != -1) return 0;
62 int WINSOCK_unblock_io(int fd, int noblock)
66 fd_flags = fcntl(fd, F_GETFL, 0);
67 if (fcntl(fd, F_SETFL, (noblock)? fd_flags | O_NONBLOCK
68 : fd_flags & ~O_NONBLOCK ) != -1) return 0;
72 int WINSOCK_check_async_op(ws_async_op* p_aop)
74 ws_async_op* p = __async_op_list;
75 while( p ) if( p == p_aop ) return 1;
80 void WINSOCK_cancel_async_op(HTASK16 hTask)
82 ws_async_op* p = __async_op_list;
84 if(hTask == GetWindowTask16(p->hWnd))
88 void WINSOCK_link_async_op(ws_async_op* p_aop)
90 if( __async_op_list ) __async_op_list->prev = p_aop;
91 else FD_ZERO(&__async_io_fdset);
93 p_aop->next = __async_op_list;
95 __async_op_list = p_aop;
97 FD_SET(p_aop->fd[0], &__async_io_fdset);
98 if( p_aop->fd[0] > __async_io_max_fd )
99 __async_io_max_fd = p_aop->fd[0];
102 void WINSOCK_unlink_async_op(ws_async_op* p_aop)
104 if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
106 { p_aop->prev->next = p_aop->next;
107 if( p_aop->next ) p_aop->next->prev = p_aop->prev; }
108 FD_CLR(p_aop->fd[0], &__async_io_fdset);
109 if( p_aop->fd[0] == __async_io_max_fd )
113 /* ----------------------------------- SIGIO handler -
115 * link_async_op/unlink_async_op allow to install generic
116 * async IO handlers (provided that aop_control function is defined).
118 * Note: AsyncGetXbyY expilicitly raise it.
121 void WINSOCK_sigio(int signal)
123 struct timeval timeout;
127 check_set = __async_io_fdset;
128 memset(&timeout, 0, sizeof(timeout));
130 while( select(__async_io_max_fd + 1,
131 &check_set, NULL, NULL, &timeout) > 0)
133 for( p_aop = __async_op_list;
134 p_aop ; p_aop = p_aop->next )
135 if( FD_ISSET(p_aop->fd[0], &check_set) )
136 if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE )
140 kill(p_aop->pid, SIGKILL);
141 waitpid(p_aop->pid, NULL, WNOHANG);
143 WINSOCK_unlink_async_op( p_aop );
145 check_set = __async_io_fdset;
149 /* ----------------------------------- child process IPC */
151 static void _sigusr1_handler_child(int sig)
153 /* read message queue to decide which
154 * async_ctl parameters to update
156 * Note: we don't want to have SA_RESTART on this signal
157 * handler, otherwise select() won't notice changed fd sets.
160 signal( SIGUSR1, _sigusr1_handler_child );
161 while( msgrcv(async_qid, (struct msgbuf*)&async_ctl.ip,
162 MTYPE_PARENT_SIZE, MTYPE_PARENT, IPC_NOWAIT) != -1 )
164 /* only ip.lParam is updated */
166 printf("handler - event %08x\n", async_ctl.ip.lParam );
169 switch( async_ctl.ip.lParam )
171 /* These are events we are notified of.
174 case WS_FD_CONNECTED: async_ctl.lEvent &= ~WS_FD_CONNECT;
175 FD_SET(async_ctl.ws_sock->fd, &fd_read);
176 FD_SET(async_ctl.ws_sock->fd, &fd_write);
179 case WS_FD_ACCEPT: async_ctl.ws_sock->flags |= WS_FD_ACCEPT;
180 FD_SET(async_ctl.ws_sock->fd, &fd_read);
181 FD_SET(async_ctl.ws_sock->fd, &fd_write);
183 case WS_FD_OOB: async_ctl.lEvent |= WS_FD_OOB;
184 FD_SET(async_ctl.ws_sock->fd, &fd_excp);
186 case WS_FD_READ: async_ctl.lEvent |= WS_FD_READ;
187 FD_SET(async_ctl.ws_sock->fd, &fd_read);
189 case WS_FD_WRITE: async_ctl.lEvent |= WS_FD_WRITE;
190 FD_SET(async_ctl.ws_sock->fd, &fd_write);
197 static int notify_parent( unsigned flag )
199 if( flag & WSMSG_ASYNC_SELECT )
201 async_ctl.ip.mtype = MTYPE_CLIENT;
202 while( msgsnd(async_qid, (struct msgbuf*)&(async_ctl.ip),
203 MTYPE_CLIENT_SIZE, 0) == -1 )
205 if( errno == EINTR ) continue;
207 else if( errno == EIDRM ) _exit(0);
211 perror("AsyncSelect(child)");
215 kill(getppid(), SIGUSR1);
218 printf("handler - notify [%08x]\n", async_ctl.ip.lParam);
221 else /* use half-duplex pipe to handle variable length packets */
223 write(async_ctl.ws_aop->fd[1], &async_ctl.lLength, sizeof(unsigned) );
224 write(async_ctl.ws_aop->fd[1], async_ctl.buffer, async_ctl.lLength );
226 kill(getppid(), SIGIO); /* simulate async I/O */
229 printf("handler - notify aop [%d, buf %d]\n", async_ctl.lLength, async_ctl.ws_aop->buflen);
236 /* ----------------------------------- async select */
238 static void setup_fd_sets()
240 FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_ZERO(&fd_excp);
242 if( async_ctl.lEvent & WS_FD_OOB)
243 FD_SET(async_ctl.ws_sock->fd, &fd_excp);
244 if( async_ctl.lEvent & (WS_FD_ACCEPT | WS_FD_READ |
245 WS_FD_CONNECT | WS_FD_CLOSE) )
246 FD_SET(async_ctl.ws_sock->fd, &fd_read);
247 if( async_ctl.lEvent & (WS_FD_WRITE | WS_FD_CONNECT) )
248 FD_SET(async_ctl.ws_sock->fd, &fd_write);
251 static void setup_sig_sets(sigset_t* sig_block)
253 sigemptyset(sig_block);
254 sigaddset(sig_block, SIGUSR1);
255 sigprocmask( SIG_BLOCK, sig_block, NULL);
256 signal( SIGUSR1, _sigusr1_handler_child );
259 void WINSOCK_do_async_select()
262 int sock_type, bytes;
264 getsockopt(async_ctl.ws_sock->fd, SOL_SOCKET, SO_TYPE, &sock_type, &bytes);
265 setup_sig_sets(&sig_block);
272 if( sock_type != SOCK_STREAM )
273 async_ctl.lEvent &= ~(WS_FD_ACCEPT | WS_FD_CONNECT);
274 sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
277 printf("select(2)[%i,%i,%i]... ",
278 FD_ISSET(async_ctl.ws_sock->fd, &fd_read),
279 FD_ISSET(async_ctl.ws_sock->fd, &fd_write),
280 FD_ISSET(async_ctl.ws_sock->fd, &fd_excp));
282 if( (val = select(async_ctl.ws_sock->fd + 1,
283 &fd_read, &fd_write, &fd_excp, NULL)) == -1 )
284 if( errno == EINTR ) continue;
286 printf("got %i events\n", val);
290 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
291 printf("handler - read is READY! [%08x]\n", async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE));
294 sigprocmask( SIG_BLOCK, &sig_block, NULL);
295 async_ctl.ip.lParam = 0;
296 if( async_ctl.ws_sock->flags & WS_FD_ACCEPT )
298 /* listening socket */
300 FD_CLR(async_ctl.ws_sock->fd, &fd_read);
301 FD_CLR(async_ctl.ws_sock->fd, &fd_write);
303 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_ACCEPT, 0 );
304 notify_parent( WSMSG_ASYNC_SELECT );
307 else /* I/O socket */
309 if( async_ctl.lEvent & WS_FD_CONNECT )
311 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_write) )
313 /* success - reinit fd sets to start I/O */
315 if( async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE))
316 FD_SET(async_ctl.ws_sock->fd, &fd_read);
317 else FD_CLR(async_ctl.ws_sock->fd, &fd_read);
318 if( async_ctl.lEvent & WS_FD_WRITE )
319 FD_SET(async_ctl.ws_sock->fd, &fd_write);
320 else FD_CLR(async_ctl.ws_sock->fd, &fd_write);
322 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, 0 );
323 async_ctl.lEvent &= ~WS_FD_CONNECT; /* one-shot */
325 else if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
327 /* failure - do read() to get correct errno */
329 if( read(async_ctl.ws_sock->fd, &bytes, 4) == -1 )
330 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, wsaErrno() );
332 } else continue; /* OOB?? */
334 notify_parent( WSMSG_ASYNC_SELECT );
336 else /* connected socket */
339 if( async_ctl.lEvent & WS_FD_OOB )
340 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_excp) )
342 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_OOB, 0 );
343 async_ctl.lEvent &= ~WS_FD_OOB;
344 FD_CLR(async_ctl.ws_sock->fd, &fd_excp);
345 notify_parent( WSMSG_ASYNC_SELECT );
347 else FD_SET(async_ctl.ws_sock->fd, &fd_excp);
349 if( async_ctl.lEvent & WS_FD_WRITE )
350 if( FD_ISSET( async_ctl.ws_sock->fd, &fd_write ) )
352 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_WRITE, 0 );
353 async_ctl.lEvent &= ~WS_FD_WRITE;
354 FD_CLR(async_ctl.ws_sock->fd, &fd_write);
355 notify_parent( WSMSG_ASYNC_SELECT );
357 else FD_SET(async_ctl.ws_sock->fd, &fd_write);
359 if( async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE) )
360 if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
364 if( sock_type == SOCK_RAW ) ok = 1;
365 else if( ioctl( async_ctl.ws_sock->fd, FIONREAD, (char*)&bytes) == -1 )
367 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_READ, wsaErrno() );
368 FD_CLR( async_ctl.ws_sock->fd, &fd_read );
372 if( bytes || ok ) /* got data */
375 if( ok ) printf("\traw/datagram read pending\n");
376 else printf("\t%i bytes pending\n", bytes );
378 if( async_ctl.lEvent & WS_FD_READ )
380 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_READ, 0 );
381 async_ctl.lEvent &= ~WS_FD_READ;
382 if( !(async_ctl.lEvent & WS_FD_CLOSE) )
383 FD_CLR( async_ctl.ws_sock->fd, &fd_read );
385 else if( !(async_ctl.lEvent & (WS_FD_WRITE | WS_FD_OOB)) )
387 sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
389 sigprocmask( SIG_BLOCK, &sig_block, NULL);
393 else /* 0 bytes to read */
395 val = read( async_ctl.ws_sock->fd, (char*)&bytes, 4);
396 if( errno == EWOULDBLOCK || errno == EINTR )
399 printf("\twould block..\n");
405 case 0: errno = ENETDOWN; /* ENETDOWN */
406 case -1: /* ECONNRESET */
407 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() );
411 async_ctl.lEvent &= ~(WS_FD_CLOSE | WS_FD_READ); /* one-shot */
412 FD_ZERO(&fd_read); FD_ZERO(&fd_write);
415 notify_parent( WSMSG_ASYNC_SELECT );
417 else FD_SET(async_ctl.ws_sock->fd, &fd_read);
419 } /* connected socket */
425 /* ----------------------------------- getXbyY requests */
427 static void _async_fail()
430 (h_errno < 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
431 : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
432 write(async_ctl.ws_aop->fd[1], &async_ctl.lLength, sizeof(unsigned) );
434 kill(getppid(), SIGIO); /* simulate async I/O */
439 void dump_ws_hostent_offset(struct ws_hostent* wshe)
442 char* base = (char*)wshe;
445 printf("h_name = %08x\t[%s]\n", (unsigned)wshe->h_name, base + (unsigned)wshe->h_name);
446 printf("h_aliases = %08x\t[%08x]\n", (unsigned)wshe->h_aliases,
447 (unsigned)(base + (unsigned)wshe->h_aliases));
448 ptr = (unsigned*)(base + (unsigned)wshe->h_aliases);
449 for(i = 0; ptr[i]; i++ )
451 printf("%i - %08x ", i + 1, ptr[i]);
452 printf(" [%s]\n", ((char*)base) + ptr[i]);
454 printf("h_length = %i\n", wshe->h_length);
457 void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
460 struct hostent* p_he;
462 close(async_ctl.ws_aop->fd[0]);
463 p_he = (flag & WSMSG_ASYNC_HOSTBYNAME)
464 ? gethostbyname(async_ctl.init)
465 : gethostbyaddr(async_ctl.init,
466 async_ctl.lLength, async_ctl.lEvent);
467 if( p_he ) size = WS_dup_he(pwsi, p_he, WS_DUP_SEGPTR | WS_DUP_OFFSET );
470 async_ctl.buffer = pwsi->buffer;
471 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
472 notify_parent( flag );
477 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
480 struct protoent* p_pe;
482 close(async_ctl.ws_aop->fd[0]);
483 p_pe = (flag & WSMSG_ASYNC_PROTOBYNAME)
484 ? getprotobyname(async_ctl.init)
485 : getprotobynumber(async_ctl.lEvent);
486 if( p_pe ) size = WS_dup_pe(pwsi, p_pe, WS_DUP_SEGPTR | WS_DUP_OFFSET );
489 async_ctl.buffer = pwsi->buffer;
490 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
491 notify_parent( flag );
496 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
499 struct servent* p_se;
501 close(async_ctl.ws_aop->fd[0]);
502 p_se = (flag & WSMSG_ASYNC_SERVBYNAME)
503 ? getservbyname(async_ctl.init, async_ctl.buffer)
504 : getservbyport(async_ctl.lEvent, async_ctl.init);
505 if( p_se ) size = WS_dup_se(pwsi, p_se, WS_DUP_SEGPTR | WS_DUP_OFFSET );
508 async_ctl.buffer = pwsi->buffer;
509 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
510 notify_parent( flag );