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
);