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>
22 #define __WS_ASYNC_DEBUG 0
24 static int _async_io_max_fd
= 0;
25 static fd_set __async_io_fdset
;
26 static ws_async_op
* __async_op_list
= NULL
;
28 extern ws_async_ctl async_ctl
;
31 fd_set fd_read
, fd_write
, fd_excp
;
33 /* ----------------------------------- async/non-blocking I/O */
35 int WINSOCK_async_io(int fd
, int async
)
39 fcntl(fd
, F_SETOWN
, getpid());
41 fd_flags
= fcntl(fd
, F_GETFL
, 0);
42 if (fcntl(fd
, F_SETFL
, (async
)? fd_flags
| FASYNC
43 : fd_flags
& ~FASYNC
) != -1) return 0;
47 int WINSOCK_unblock_io(int fd
, int noblock
)
51 fd_flags
= fcntl(fd
, F_GETFL
, 0);
52 if (fcntl(fd
, F_SETFL
, (noblock
)? fd_flags
| O_NONBLOCK
53 : fd_flags
& ~O_NONBLOCK
) != -1) return 0;
57 int WINSOCK_check_async_op(ws_async_op
* p_aop
)
59 ws_async_op
* p
= __async_op_list
;
60 while( p
) if( p
== p_aop
) return 1;
65 void WINSOCK_cancel_async_op(HTASK16 hTask
)
67 ws_async_op
* p
= __async_op_list
;
69 if(hTask
== GetWindowTask16(p
->hWnd
))
73 void WINSOCK_link_async_op(ws_async_op
* p_aop
)
75 if( __async_op_list
) __async_op_list
->prev
= p_aop
;
76 else FD_ZERO(&__async_io_fdset
);
78 p_aop
->next
= __async_op_list
;
80 __async_op_list
= p_aop
;
82 FD_SET(p_aop
->fd
[0], &__async_io_fdset
);
83 if( p_aop
->fd
[0] > _async_io_max_fd
)
84 _async_io_max_fd
= p_aop
->fd
[0];
87 void WINSOCK_unlink_async_op(ws_async_op
* p_aop
)
89 if( p_aop
== __async_op_list
) __async_op_list
= p_aop
->next
;
91 { p_aop
->prev
->next
= p_aop
->next
;
92 if( p_aop
->next
) p_aop
->next
->prev
= p_aop
->prev
; }
93 FD_CLR(p_aop
->fd
[0], &__async_io_fdset
);
94 if( p_aop
->fd
[0] == _async_io_max_fd
)
98 /* ----------------------------------- SIGIO handler -
100 * link_async_op/unlink_async_op allow to install generic
101 * async IO handlers (provided that aop_control function is defined).
103 * Note: AsyncGetXbyY expilicitly raise it.
106 void WINSOCK_sigio(int signal
)
108 struct timeval timeout
;
112 check_set
= __async_io_fdset
;
113 bzero(&timeout
,sizeof(timeout
));
115 while( select(_async_io_max_fd
+ 1,
116 &check_set
, NULL
, NULL
, &timeout
) > 0)
118 for( p_aop
= __async_op_list
;
119 p_aop
; p_aop
= p_aop
->next
)
120 if( FD_ISSET(p_aop
->fd
[0], &check_set
) )
121 if( p_aop
->aop_control(p_aop
, AOP_IO
) == AOP_CONTROL_REMOVE
)
125 kill(p_aop
->pid
, SIGKILL
);
126 waitpid(p_aop
->pid
, NULL
, 0);
128 WINSOCK_unlink_async_op( p_aop
);
130 check_set
= __async_io_fdset
;
134 /* ----------------------------------- child process IPC */
136 static void _sigusr1_handler_child(int sig
)
138 /* read message queue to decide which
139 * async_ctl parameters to update
141 * Note: we don't want to have SA_RESTART on this signal
142 * handler, otherwise select() won't notice changed fd sets.
145 signal( SIGUSR1
, _sigusr1_handler_child
);
146 while( msgrcv(async_qid
, (struct msgbuf
*)&async_ctl
.ip
,
147 MTYPE_PARENT_SIZE
, MTYPE_PARENT
, IPC_NOWAIT
) != -1 )
149 /* only ip.lParam is updated */
151 printf("handler - event %08x\n", async_ctl
.ip
.lParam
);
154 switch( async_ctl
.ip
.lParam
)
156 /* These are events we are notified of.
159 case WS_FD_CONNECTED
: async_ctl
.lEvent
&= ~WS_FD_CONNECT
;
160 FD_SET(async_ctl
.ws_sock
->fd
, &fd_read
);
161 FD_SET(async_ctl
.ws_sock
->fd
, &fd_write
);
164 case WS_FD_ACCEPT
: async_ctl
.ws_sock
->flags
|= WS_FD_ACCEPT
;
165 FD_SET(async_ctl
.ws_sock
->fd
, &fd_read
);
166 FD_SET(async_ctl
.ws_sock
->fd
, &fd_write
);
168 case WS_FD_OOB
: async_ctl
.lEvent
|= WS_FD_OOB
;
169 FD_SET(async_ctl
.ws_sock
->fd
, &fd_excp
);
171 case WS_FD_READ
: async_ctl
.lEvent
|= WS_FD_READ
;
172 FD_SET(async_ctl
.ws_sock
->fd
, &fd_read
);
174 case WS_FD_WRITE
: async_ctl
.lEvent
|= WS_FD_WRITE
;
175 FD_SET(async_ctl
.ws_sock
->fd
, &fd_write
);
182 static int notify_parent( unsigned flag
)
184 if( flag
& WSMSG_ASYNC_SELECT
)
186 async_ctl
.ip
.mtype
= MTYPE_CLIENT
;
187 while( msgsnd(async_qid
, (struct msgbuf
*)&(async_ctl
.ip
),
188 MTYPE_CLIENT_SIZE
, 0) == -1 )
190 if( errno
== EINTR
) continue;
191 else if( errno
== EIDRM
) _exit(0);
194 perror("AsyncSelect(child)");
198 kill(getppid(), SIGUSR1
);
201 printf("handler - notify [%08x]\n", async_ctl
.ip
.lParam
);
204 else /* use half-duplex pipe to handle variable length packets */
206 write(async_ctl
.ws_aop
->fd
[1], &async_ctl
.lLength
, sizeof(unsigned) );
207 write(async_ctl
.ws_aop
->fd
[1], async_ctl
.buffer
, async_ctl
.lLength
);
208 kill(getppid(), SIGIO
); /* simulate async I/O */
210 printf("handler - notify aop [%d, buf %d]\n", async_ctl
.lLength
, async_ctl
.ws_aop
->buflen
);
217 /* ----------------------------------- async select */
219 static void setup_fd_sets()
221 FD_ZERO(&fd_read
); FD_ZERO(&fd_write
); FD_ZERO(&fd_excp
);
223 if( async_ctl
.lEvent
& WS_FD_OOB
)
224 FD_SET(async_ctl
.ws_sock
->fd
, &fd_excp
);
225 if( async_ctl
.lEvent
& (WS_FD_ACCEPT
| WS_FD_READ
|
226 WS_FD_CONNECT
| WS_FD_CLOSE
) )
227 FD_SET(async_ctl
.ws_sock
->fd
, &fd_read
);
228 if( async_ctl
.lEvent
& (WS_FD_WRITE
| WS_FD_CONNECT
) )
229 FD_SET(async_ctl
.ws_sock
->fd
, &fd_write
);
232 static void setup_sig_sets(sigset_t
* sig_block
)
234 sigemptyset(sig_block
);
235 sigaddset(sig_block
, SIGUSR1
);
236 sigprocmask( SIG_BLOCK
, sig_block
, NULL
);
237 signal( SIGUSR1
, _sigusr1_handler_child
);
240 void WINSOCK_do_async_select()
245 setup_sig_sets(&sig_block
);
252 sigprocmask( SIG_UNBLOCK
, &sig_block
, NULL
);
255 printf("select(2)[%i,%i,%i]... ",
256 FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_read
),
257 FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_write
),
258 FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_excp
));
260 if( (val
= select(async_ctl
.ws_sock
->fd
+ 1,
261 &fd_read
, &fd_write
, &fd_excp
, NULL
)) == -1 )
262 if( errno
== EINTR
) continue;
264 printf("got %i events\n", val
);
268 if( FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_read
) )
269 printf("handler - read is READY! [%08x]\n", async_ctl
.lEvent
& (WS_FD_READ
| WS_FD_CLOSE
));
272 sigprocmask( SIG_BLOCK
, &sig_block
, NULL
);
273 async_ctl
.ip
.lParam
= 0;
274 if( async_ctl
.ws_sock
->flags
& WS_FD_ACCEPT
)
276 /* listening socket */
278 FD_CLR(async_ctl
.ws_sock
->fd
, &fd_read
);
279 FD_CLR(async_ctl
.ws_sock
->fd
, &fd_write
);
281 async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_ACCEPT
, 0 );
282 notify_parent( WSMSG_ASYNC_SELECT
);
285 else /* I/O socket */
287 if( async_ctl
.lEvent
& WS_FD_CONNECT
)
289 if( FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_write
) )
291 /* success - reinit fd sets to start I/O */
293 if( async_ctl
.lEvent
& (WS_FD_READ
| WS_FD_CLOSE
))
294 FD_SET(async_ctl
.ws_sock
->fd
, &fd_read
);
295 else FD_CLR(async_ctl
.ws_sock
->fd
, &fd_read
);
296 if( async_ctl
.lEvent
& WS_FD_WRITE
)
297 FD_SET(async_ctl
.ws_sock
->fd
, &fd_write
);
298 else FD_CLR(async_ctl
.ws_sock
->fd
, &fd_write
);
300 async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_CONNECT
, 0 );
301 async_ctl
.lEvent
&= ~WS_FD_CONNECT
; /* one-shot */
303 else if( FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_read
) )
305 /* failure - do read() to get correct errno */
307 if( read(async_ctl
.ws_sock
->fd
, &bytes
, 4) == -1 )
308 async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_CONNECT
, wsaErrno() );
310 } else continue; /* OOB?? */
312 notify_parent( WSMSG_ASYNC_SELECT
);
314 else /* connected socket */
317 if( async_ctl
.lEvent
& WS_FD_OOB
)
318 if( FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_excp
) )
320 async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_OOB
, 0 );
321 async_ctl
.lEvent
&= ~WS_FD_OOB
;
322 FD_CLR(async_ctl
.ws_sock
->fd
, &fd_excp
);
323 notify_parent( WSMSG_ASYNC_SELECT
);
325 else FD_SET(async_ctl
.ws_sock
->fd
, &fd_excp
);
327 if( async_ctl
.lEvent
& WS_FD_WRITE
)
328 if( FD_ISSET( async_ctl
.ws_sock
->fd
, &fd_write
) )
330 async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_WRITE
, 0 );
331 async_ctl
.lEvent
&= ~WS_FD_WRITE
;
332 FD_CLR(async_ctl
.ws_sock
->fd
, &fd_write
);
333 notify_parent( WSMSG_ASYNC_SELECT
);
335 else FD_SET(async_ctl
.ws_sock
->fd
, &fd_write
);
337 if( async_ctl
.lEvent
& (WS_FD_READ
| WS_FD_CLOSE
) )
338 if( FD_ISSET(async_ctl
.ws_sock
->fd
, &fd_read
) )
340 if( ioctl( async_ctl
.ws_sock
->fd
, FIONREAD
, (char*)&bytes
) != -1 )
342 if( bytes
) /* got data */
345 printf("\t%i bytes pending\n", bytes
);
347 if( async_ctl
.lEvent
& WS_FD_READ
)
349 async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_READ
, 0 );
350 async_ctl
.lEvent
&= ~WS_FD_READ
;
351 if( !(async_ctl
.lEvent
& WS_FD_CLOSE
) )
352 FD_CLR( async_ctl
.ws_sock
->fd
, &fd_read
);
354 else if( !(async_ctl
.lEvent
& (WS_FD_WRITE
| WS_FD_OOB
)) )
356 sigprocmask( SIG_UNBLOCK
, &sig_block
, NULL
);
358 sigprocmask( SIG_BLOCK
, &sig_block
, NULL
);
362 else /* 0 bytes to read */
364 val
= read( async_ctl
.ws_sock
->fd
, (char*)&bytes
, 4);
365 if( errno
== EWOULDBLOCK
|| errno
== EINTR
)
368 printf("\twould block..\n");
374 case 0: errno
= ENETDOWN
; /* ENETDOWN */
375 case -1: /* ECONNRESET */
376 async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_CLOSE
, wsaErrno() );
380 async_ctl
.lEvent
&= ~(WS_FD_CLOSE
| WS_FD_READ
); /* one-shot */
381 FD_ZERO(&fd_read
); FD_ZERO(&fd_write
);
384 else async_ctl
.ip
.lParam
= WSAMAKESELECTREPLY( WS_FD_READ
, wsaErrno() );
386 notify_parent( WSMSG_ASYNC_SELECT
);
388 else FD_SET(async_ctl
.ws_sock
->fd
, &fd_read
);
390 } /* connected socket */
396 /* ----------------------------------- getXbyY requests */
398 static void _async_fail()
401 (h_errno
< 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
402 : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
403 write(async_ctl
.ws_aop
->fd
[1], &async_ctl
.lLength
, sizeof(unsigned) );
404 kill(getppid(), SIGIO
); /* simulate async I/O */
408 void dump_ws_hostent_offset(struct ws_hostent
* wshe
)
411 char* base
= (char*)wshe
;
414 printf("h_name = %08x\t[%s]\n", (unsigned)wshe
->h_name
, base
+ (unsigned)wshe
->h_name
);
415 printf("h_aliases = %08x\t[%08x]\n", (unsigned)wshe
->h_aliases
,
416 (unsigned)(base
+ (unsigned)wshe
->h_aliases
));
417 ptr
= (unsigned*)(base
+ (unsigned)wshe
->h_aliases
);
418 for(i
= 0; ptr
[i
]; i
++ )
420 printf("%i - %08x ", i
+ 1, ptr
[i
]);
421 printf(" [%s]\n", ((char*)base
) + ptr
[i
]);
423 printf("h_length = %i\n", wshe
->h_length
);
426 void WS_do_async_gethost(LPWSINFO pwsi
, unsigned flag
)
429 struct hostent
* p_he
;
431 close(async_ctl
.ws_aop
->fd
[0]);
432 p_he
= (flag
& WSMSG_ASYNC_HOSTBYNAME
)
433 ? gethostbyname(async_ctl
.ws_aop
->init
)
434 : gethostbyaddr(async_ctl
.ws_aop
->init
,
435 async_ctl
.lLength
, async_ctl
.lEvent
);
436 if( p_he
) size
= WS_dup_he(pwsi
, p_he
, WS_DUP_SEGPTR
| WS_DUP_OFFSET
);
439 async_ctl
.buffer
= pwsi
->buffer
;
440 async_ctl
.lLength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
441 notify_parent( flag
);
447 void WS_do_async_getproto(LPWSINFO pwsi
, unsigned flag
)
450 struct protoent
* p_pe
;
452 close(async_ctl
.ws_aop
->fd
[0]);
453 p_pe
= (flag
& WSMSG_ASYNC_PROTOBYNAME
)
454 ? getprotobyname(async_ctl
.ws_aop
->init
)
455 : getprotobynumber(async_ctl
.lEvent
);
456 if( p_pe
) size
= WS_dup_pe(pwsi
, p_pe
, WS_DUP_SEGPTR
| WS_DUP_OFFSET
);
459 async_ctl
.buffer
= pwsi
->buffer
;
460 async_ctl
.lLength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
461 notify_parent( flag
);
467 void WS_do_async_getserv(LPWSINFO pwsi
, unsigned flag
)
470 struct servent
* p_se
;
472 close(async_ctl
.ws_aop
->fd
[0]);
473 p_se
= (flag
& WSMSG_ASYNC_SERVBYNAME
)
474 ? getservbyname(async_ctl
.ws_aop
->init
, async_ctl
.buffer
)
475 : getservbyport(async_ctl
.lEvent
, async_ctl
.ws_aop
->init
);
476 if( p_se
) size
= WS_dup_se(pwsi
, p_se
, WS_DUP_SEGPTR
| WS_DUP_OFFSET
);
479 async_ctl
.buffer
= pwsi
->buffer
;
480 async_ctl
.lLength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
481 notify_parent( flag
);