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