Release 961208
[wine.git] / misc / winsock_async.c
blob6596b5fc322e332a283ffec690d30f4bd282d6ef
1 /*
2 * asynchronous winsock services
3 *
4 * (C) 1996 Alex Korobka.
6 * FIXME: telftp16 (ftp part) stalls on AsyncSelect with FD_ACCEPT.
7 */
8 #include <unistd.h>
9 #include <string.h>
10 #include <signal.h>
11 #include <sys/ioctl.h>
12 #include <sys/types.h>
13 #include <sys/ipc.h>
14 #include <sys/msg.h>
15 #include <sys/wait.h>
16 #include <errno.h>
18 #include "windows.h"
19 #include "winsock.h"
20 #include "debug.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;
29 extern int async_qid;
31 fd_set fd_read, fd_write, fd_excp;
33 /* ----------------------------------- async/non-blocking I/O */
35 int WINSOCK_async_io(int fd, int async)
37 int fd_flags;
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;
44 return -1;
47 int WINSOCK_unblock_io(int fd, int noblock)
49 int fd_flags;
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;
54 return -1;
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;
61 else p = p->next;
62 return 0;
65 void WINSOCK_cancel_async_op(HTASK16 hTask)
67 ws_async_op* p = __async_op_list;
68 while( p )
69 if(hTask == GetWindowTask16(p->hWnd))
70 p->flags = 0;
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;
79 p_aop->prev = NULL;
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;
90 else
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 )
95 _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;
109 fd_set check_set;
110 ws_async_op* p_aop;
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 )
123 if( p_aop->pid )
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 */
150 #if __WS_ASYNC_DEBUG
151 printf("handler - event %08x\n", async_ctl.ip.lParam );
152 #endif
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);
162 break;
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);
167 break;
168 case WS_FD_OOB: async_ctl.lEvent |= WS_FD_OOB;
169 FD_SET(async_ctl.ws_sock->fd, &fd_excp);
170 break;
171 case WS_FD_READ: async_ctl.lEvent |= WS_FD_READ;
172 FD_SET(async_ctl.ws_sock->fd, &fd_read);
173 break;
174 case WS_FD_WRITE: async_ctl.lEvent |= WS_FD_WRITE;
175 FD_SET(async_ctl.ws_sock->fd, &fd_write);
176 break;
177 default:
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);
192 else
194 perror("AsyncSelect(child)");
195 return 0;
198 kill(getppid(), SIGUSR1);
200 #if __WS_ASYNC_DEBUG
201 printf("handler - notify [%08x]\n", async_ctl.ip.lParam);
202 #endif
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 */
209 #if __WS_ASYNC_DEBUG
210 printf("handler - notify aop [%d, buf %d]\n", async_ctl.lLength, async_ctl.ws_aop->buflen);
211 #endif
212 pause();
214 return 1;
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()
242 sigset_t sig_block;
243 int bytes;
245 setup_sig_sets(&sig_block);
246 setup_fd_sets();
248 while(1)
250 int val;
252 sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
254 #if __WS_ASYNC_DEBUG
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));
259 #endif
260 if( (val = select(async_ctl.ws_sock->fd + 1,
261 &fd_read, &fd_write, &fd_excp, NULL)) == -1 )
262 if( errno == EINTR ) continue;
263 #if __WS_ASYNC_DEBUG
264 printf("got %i events\n", val);
265 #endif
267 #if __WS_ASYNC_DEBUG
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));
270 #endif
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 );
283 continue;
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() );
309 else continue;
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 */
344 #if __WS_ASYNC_DEBUG
345 printf("\t%i bytes pending\n", bytes );
346 #endif
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);
357 pause();
358 sigprocmask( SIG_BLOCK, &sig_block, NULL);
360 else continue;
362 else /* 0 bytes to read */
364 val = read( async_ctl.ws_sock->fd, (char*)&bytes, 4);
365 if( errno == EWOULDBLOCK || errno == EINTR )
367 #if __WS_ASYNC_DEBUG
368 printf("\twould block..\n");
369 #endif
370 continue;
372 switch( val )
374 case 0: errno = ENETDOWN; /* ENETDOWN */
375 case -1: /* ECONNRESET */
376 async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() );
377 break;
378 default: continue;
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 */
391 } /* I/O socket */
392 } /* while */
396 /* ----------------------------------- getXbyY requests */
398 static void _async_fail()
400 async_ctl.lLength =
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 */
405 pause();
408 void dump_ws_hostent_offset(struct ws_hostent* wshe)
410 int i;
411 char* base = (char*)wshe;
412 unsigned* ptr;
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 )
428 int size = 0;
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 );
437 if( size )
439 async_ctl.buffer = pwsi->buffer;
440 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
441 notify_parent( flag );
443 else _async_fail();
444 _exit(0);
447 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
449 int size = 0;
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 );
457 if( size )
459 async_ctl.buffer = pwsi->buffer;
460 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
461 notify_parent( flag );
463 else _async_fail();
464 _exit(0);
467 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
469 int size = 0;
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 );
477 if( size )
479 async_ctl.buffer = pwsi->buffer;
480 async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
481 notify_parent( flag );
483 else _async_fail();
484 _exit(0);