Release 970804
[wine] / misc / winsock_async.c
1 /*
2  * asynchronous winsock services
3  * 
4  * (C) 1996 Alex Korobka.
5  *
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>
17 #ifdef __EMX__
18 #include <sys/so_ioctl.h>
19 #include <sys/param.h>
20 #endif
21 #ifdef __svr4__
22 #include <sys/file.h>
23 #include <sys/filio.h>
24 #endif
25
26 extern int h_errno;
27
28 #include "windows.h"
29 #include "winsock.h"
30 #include "debug.h"
31
32 #ifndef FASYNC
33 #define FASYNC FIOASYNC
34 #endif
35
36 #define __WS_ASYNC_DEBUG        0
37
38 static int              __async_io_max_fd = 0;
39 static fd_set           __async_io_fdset;
40 static ws_async_op*     __async_op_list = NULL;
41
42 extern ws_async_ctl     async_ctl;
43 extern int              async_qid;
44
45 fd_set           fd_read, fd_write, fd_excp;
46
47 /* ----------------------------------- async/non-blocking I/O */
48
49 int WINSOCK_async_io(int fd, int async)
50 {
51     int fd_flags;
52
53 #ifndef __EMX__
54     fcntl(fd, F_SETOWN, getpid());
55 #endif
56
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;
60     return -1;
61 }
62
63 int WINSOCK_unblock_io(int fd, int noblock)
64 {
65     int fd_flags;
66
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;
70     return -1;
71 }
72
73 int WINSOCK_check_async_op(ws_async_op* p_aop)
74 {
75   ws_async_op*   p = __async_op_list;
76   while( p ) if( p == p_aop ) return 1;
77              else p = p->next;
78   return 0;
79 }
80
81 void WINSOCK_cancel_async_op(HTASK16 hTask)
82 {
83   ws_async_op*   p = __async_op_list;
84   while( p ) 
85      if(hTask == GetWindowTask16(p->hWnd)) 
86         p->flags = 0;
87 }
88
89 void WINSOCK_link_async_op(ws_async_op* p_aop)
90 {
91   if( __async_op_list ) __async_op_list->prev = p_aop;
92   else FD_ZERO(&__async_io_fdset);
93
94   p_aop->next = __async_op_list; 
95   p_aop->prev = NULL;
96   __async_op_list = p_aop;
97
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];
101 }
102
103 void WINSOCK_unlink_async_op(ws_async_op* p_aop)
104 {
105   if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
106   else
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 )
111                       __async_io_max_fd--;
112 }
113
114 /* ----------------------------------- SIGIO handler -
115  *
116  * link_async_op/unlink_async_op allow to install generic
117  * async IO handlers (provided that aop_control function is defined).
118  *
119  * Note: AsyncGetXbyY expilicitly raise it.
120  */
121
122 void WINSOCK_sigio(int signal)
123 {
124  struct timeval         timeout;
125  fd_set                 check_set;
126  ws_async_op*           p_aop;
127
128  check_set = __async_io_fdset;
129  memset(&timeout, 0, sizeof(timeout));
130
131  while( select(__async_io_max_fd + 1,
132               &check_set, NULL, NULL, &timeout) > 0)
133  {
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 )
138           {
139               if( p_aop->pid ) 
140               { 
141                 kill(p_aop->pid, SIGKILL);
142                 waitpid(p_aop->pid, NULL, WNOHANG);
143               }
144               WINSOCK_unlink_async_op( p_aop );
145           }
146    check_set = __async_io_fdset;
147   }
148 }
149
150 /* ----------------------------------- child process IPC */
151
152 static void _sigusr1_handler_child(int sig)
153 {
154    /* read message queue to decide which
155     * async_ctl parameters to update 
156     *
157     * Note: we don't want to have SA_RESTART on this signal
158     * handler, otherwise select() won't notice changed fd sets.
159     */
160
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 )
164    {
165        /* only ip.lParam is updated */
166 #if __WS_ASYNC_DEBUG
167        printf("handler - event %08x\n", async_ctl.ip.lParam );
168 #endif
169
170        switch( async_ctl.ip.lParam )
171        {
172           /* These are events we are notified of.
173            */
174
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);
178                                   break;
179
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);
183                                 break;
184           case   WS_FD_OOB:     async_ctl.lEvent |= WS_FD_OOB;
185                                 FD_SET(async_ctl.ws_sock->fd, &fd_excp);
186                                 break;
187           case   WS_FD_READ:    async_ctl.lEvent |= WS_FD_READ;
188                                 FD_SET(async_ctl.ws_sock->fd, &fd_read);
189                                 break;
190           case   WS_FD_WRITE:   async_ctl.lEvent |= WS_FD_WRITE;
191                                 FD_SET(async_ctl.ws_sock->fd, &fd_write);
192                                 break;
193           default:
194        }
195    }
196 }
197
198 static int notify_parent( unsigned flag )
199 {
200   if( flag & WSMSG_ASYNC_SELECT )
201   {
202      async_ctl.ip.mtype = MTYPE_CLIENT;
203      while( msgsnd(async_qid, (struct msgbuf*)&(async_ctl.ip),
204                                MTYPE_CLIENT_SIZE, 0) == -1 )
205      {
206        if( errno == EINTR ) continue;
207 #ifdef EIDRM
208        else if( errno == EIDRM ) _exit(0);
209 #endif
210        else 
211        { 
212          perror("AsyncSelect(child)"); 
213          return 0; 
214        }
215      }
216      kill(getppid(), SIGUSR1); 
217
218 #if __WS_ASYNC_DEBUG
219   printf("handler - notify [%08x]\n", async_ctl.ip.lParam);
220 #endif
221   }
222   else /* use half-duplex pipe to handle variable length packets */
223   {
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 );
226 #ifndef __EMX__
227      kill(getppid(), SIGIO);    /* simulate async I/O */
228 #endif
229 #if __WS_ASYNC_DEBUG
230   printf("handler - notify aop [%d, buf %d]\n", async_ctl.lLength, async_ctl.ws_aop->buflen);
231 #endif
232      pause();
233   }
234   return 1;
235 }
236
237 /* ----------------------------------- async select */
238
239 static void setup_fd_sets()
240 {
241    FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_ZERO(&fd_excp);
242
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);
250 }
251
252 static void setup_sig_sets(sigset_t* sig_block)
253 {
254    sigemptyset(sig_block);
255    sigaddset(sig_block, SIGUSR1);
256    sigprocmask( SIG_BLOCK, sig_block, NULL);
257    signal( SIGUSR1, _sigusr1_handler_child );
258 }
259
260 void WINSOCK_do_async_select()
261 {
262   sigset_t    sig_block;
263   int         sock_type, bytes;
264
265   getsockopt(async_ctl.ws_sock->fd, SOL_SOCKET, SO_TYPE, &sock_type, &bytes);
266   setup_sig_sets(&sig_block);
267   setup_fd_sets();
268
269   while(1)
270   {
271     int         val;
272
273     if( sock_type != SOCK_STREAM )
274         async_ctl.lEvent &= ~(WS_FD_ACCEPT | WS_FD_CONNECT);
275     sigprocmask( SIG_UNBLOCK, &sig_block, NULL); 
276
277 #if __WS_ASYNC_DEBUG
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));
282 #endif
283     if( (val = select(async_ctl.ws_sock->fd + 1, 
284                      &fd_read, &fd_write, &fd_excp, NULL)) == -1 )
285       if( errno == EINTR ) continue;
286 #if __WS_ASYNC_DEBUG
287     printf("got %i events\n", val);
288 #endif
289
290 #if __WS_ASYNC_DEBUG
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));
293 #endif
294
295     sigprocmask( SIG_BLOCK, &sig_block, NULL);
296     async_ctl.ip.lParam = 0;
297     if( async_ctl.ws_sock->flags & WS_FD_ACCEPT )
298     {
299         /* listening socket */
300         
301         FD_CLR(async_ctl.ws_sock->fd, &fd_read);
302         FD_CLR(async_ctl.ws_sock->fd, &fd_write);
303
304         async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_ACCEPT, 0 );
305         notify_parent( WSMSG_ASYNC_SELECT );
306         continue;
307     }
308     else /* I/O socket */
309     {
310         if( async_ctl.lEvent & WS_FD_CONNECT )
311         {
312           if( FD_ISSET(async_ctl.ws_sock->fd, &fd_write) ) 
313           {
314               /* success - reinit fd sets to start I/O */
315
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);
322
323               async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, 0 );
324               async_ctl.lEvent &= ~WS_FD_CONNECT; /* one-shot */
325           }
326           else if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
327           {
328               /* failure - do read() to get correct errno */
329
330               if( read(async_ctl.ws_sock->fd, &bytes, 4) == -1 )
331                   async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, wsaErrno() );
332               else continue;
333           } else continue; /* OOB?? */
334
335           notify_parent( WSMSG_ASYNC_SELECT );
336         }
337         else /* connected socket */
338         {
339
340           if( async_ctl.lEvent & WS_FD_OOB )
341             if( FD_ISSET(async_ctl.ws_sock->fd, &fd_excp) )
342             {
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 );
347             }
348             else FD_SET(async_ctl.ws_sock->fd, &fd_excp);
349
350           if( async_ctl.lEvent & WS_FD_WRITE )
351             if( FD_ISSET( async_ctl.ws_sock->fd, &fd_write ) )
352             {
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 );
357             }
358             else FD_SET(async_ctl.ws_sock->fd, &fd_write);
359
360           if( async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE) )
361             if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
362             {
363               int       ok = 0;
364
365               if( sock_type == SOCK_RAW ) ok = 1;
366               else if( ioctl( async_ctl.ws_sock->fd, FIONREAD, (char*)&bytes) == -1 )
367               {
368                   async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_READ, wsaErrno() );
369                   FD_CLR( async_ctl.ws_sock->fd, &fd_read );
370                   bytes = 0;
371               }
372
373               if( bytes || ok ) /* got data */
374               {
375 #if __WS_ASYNC_DEBUG
376                   if( ok ) printf("\traw/datagram read pending\n");
377                   else printf("\t%i bytes pending\n", bytes );
378 #endif
379                   if( async_ctl.lEvent & WS_FD_READ )
380                   {
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 );
385                   }
386                   else if( !(async_ctl.lEvent & (WS_FD_WRITE | WS_FD_OOB)) ) 
387                        {
388                           sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
389                           pause();
390                           sigprocmask( SIG_BLOCK, &sig_block, NULL);
391                        }
392                        else continue;
393               }
394               else              /* 0 bytes to read */
395               {
396                   val = read( async_ctl.ws_sock->fd, (char*)&bytes, 4);
397                   if( errno == EWOULDBLOCK || errno == EINTR ) 
398                   { 
399 #if __WS_ASYNC_DEBUG
400                     printf("\twould block..\n");
401 #endif
402                     continue;
403                   }
404                   switch( val )
405                   {
406                     case  0: errno = ENETDOWN;  /* ENETDOWN */
407                     case -1:                    /* ECONNRESET */
408                              async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() );
409                              break;
410                     default: continue;
411                   }
412                   async_ctl.lEvent &= ~(WS_FD_CLOSE | WS_FD_READ); /* one-shot */
413                   FD_ZERO(&fd_read); FD_ZERO(&fd_write); 
414               }
415
416               notify_parent( WSMSG_ASYNC_SELECT );
417           }
418           else FD_SET(async_ctl.ws_sock->fd, &fd_read);
419
420         } /* connected socket */
421     } /* I/O socket */
422   } /* while */
423 }
424
425
426 /* ----------------------------------- getXbyY requests */
427
428 static void _async_fail()
429 {
430      async_ctl.lLength =
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) );
434 #ifndef __EMX__
435      kill(getppid(), SIGIO);    /* simulate async I/O */
436 #endif
437      pause();
438 }
439
440 void dump_ws_hostent_offset(struct ws_hostent* wshe)
441 {
442   int           i;
443   char*         base = (char*)wshe;
444   unsigned*     ptr;
445
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++ )
451   {
452         printf("%i - %08x ", i + 1, ptr[i]);
453         printf(" [%s]\n", ((char*)base) + ptr[i]);
454   }
455   printf("h_length = %i\n", wshe->h_length);
456 }
457
458 void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
459 {  
460   int                   size = 0;
461   struct hostent*       p_he;
462
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 );
469   if( size )
470   {
471      async_ctl.buffer = pwsi->buffer;
472      async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
473      notify_parent( flag );
474   }
475   else _async_fail();
476 }
477
478 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
479 {
480   int                   size = 0;
481   struct protoent*      p_pe;
482
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 );
488   if( size )
489   {
490      async_ctl.buffer = pwsi->buffer;
491      async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
492      notify_parent( flag );
493   } 
494   else _async_fail();
495 }
496
497 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
498 {
499   int                   size = 0;
500   struct servent*       p_se;
501
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 );
507   if( size )
508   {
509      async_ctl.buffer = pwsi->buffer;
510      async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
511      notify_parent( flag );
512   }
513   else _async_fail();
514 }
515