1 /*
2 ** Copyright (C) 2006 Olivier DEMBOUR
3 ** $Id: select.c,v 1.1.2.4 2010/01/20 15:42:56 dembour Exp $
4 **
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with This program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include <stdio.h>
22 
23 #ifndef _WIN32
24 #include <sys/wait.h>
25 #include <sys/select.h>
26 #include <strings.h>
27 #else
28 #include "mywin32.h"
29 #endif
30 
31 #include "dns.h"
32 #include "list.h"
33 #include "myerror.h"
34 #include "client.h"
35 #include "debug.h"
36 #include "queue.h"
37 #include "socket.h"
38 
39 #ifdef _WIN32
add_event(WSAEVENT event,HANDLE * rfds,int max_fd)40 int		add_event(WSAEVENT event, HANDLE *rfds, int max_fd)
41 {
42   rfds[max_fd] = event;
43   return ((int) (max_fd+1));
44 }
45 #else
add_socket(socket_t socket,fd_set * rfds,socket_t max_fd)46 int		add_socket(socket_t socket, fd_set *rfds, socket_t max_fd)
47 {
48   FD_SET(socket, rfds);
49   return ((int)(MAX(max_fd, socket)));
50 }
51 #endif
52 
53 #ifdef _WIN32
win_prepare_select(t_conf * conf,WSAEVENT * rfds,struct timeval * tv)54 int		win_prepare_select(t_conf *conf, WSAEVENT *rfds, struct timeval *tv)
55 {
56   int		max_fd = 0;
57   t_simple_list	*client;
58 
59   max_fd = add_event(conf->event_udp, rfds, max_fd);
60 
61   for (client = conf->client; client; client = client->next)
62     {
63       if (socket_is_valid(client->fd_ro))
64 	{
65 	  queue_put_nop(conf, client);
66 	  if ((client->control.data_pending < MAX_DATA_SIZE)
67 	      && ((client->control.data_pending + client->control.nop_pending < WINDOW_SIZE)))
68 	    {
69 	      if (client->control.event && socket_is_valid(client->fd_ro))
70 		max_fd = add_event(client->control.event, rfds, max_fd);
71 	      else
72 		{
73 		  if (client->pid != (process_t)-1) {
74 		    // watch for pipe I/O completion
75 		    max_fd = add_event(client->control.aio.hEvent, rfds, max_fd);
76 		  }
77 		}
78 	    }
79 	  else
80 	    {
81 	      if (client->control.nop_pending == 0xffff)
82 		{
83 		  DPRINTF(1, "WTF !\n");
84 		  exit(0);
85 		}
86 	      SetEvent(conf->event_udp);
87 	    }
88 	  if (client->pid != (process_t)-1) {
89 	    // watch for process event (dead)
90 	    max_fd = add_event(client->pid, rfds, max_fd);
91 	  }
92 	}
93     }
94   /* select only if sd_tcp is alive */
95   if (socket_is_valid(conf->sd_tcp))
96     max_fd = add_event(conf->event_tcp, rfds, max_fd);
97   tv->tv_sec = SOCKET_TIMEOUT;
98   tv->tv_usec = 0;
99   return (max_fd);
100 }
101 
102 #else
103 
unix_prepare_select(t_conf * conf,fd_set * rfds,struct timeval * tv)104 int		unix_prepare_select(t_conf *conf, fd_set *rfds, struct timeval *tv)
105 {
106   int		max_fd = 0;
107   t_simple_list	*client;
108 
109   FD_ZERO(rfds);
110   for (client = conf->client; client; client = client->next)
111     {
112       if (socket_is_valid(client->fd_ro))
113 	{
114 	  queue_put_nop(conf, client);
115 	  if (!(client->control.data_pending >= MAX_DATA_SIZE)
116 	      && (!(client->control.data_pending + client->control.nop_pending >= WINDOW_SIZE)))
117 	    {
118 	      if (socket_is_valid(client->fd_ro))
119 		max_fd = add_socket(client->fd_ro, rfds, max_fd);
120 	    }
121 	}
122     }
123   max_fd = add_socket(conf->sd_udp, rfds, max_fd);
124   // fuck Windows, not queue debug
125   if ((!conf->use_stdin) && (debug > 1))
126     max_fd = add_socket(0, rfds, max_fd);
127 
128   /* select only if sd_tcp is alive */
129   if (socket_is_valid(conf->sd_tcp))
130     max_fd = add_socket(conf->sd_tcp, rfds, max_fd);
131   tv->tv_sec = SOCKET_TIMEOUT;
132   tv->tv_usec = 0;
133   return (max_fd);
134 }
135 #endif
136 
137 /**
138  * @brief prepare the fd_set for select or HANDLE for Windows
139  * @param[in] conf configuration
140  * @param[in] rfds the fd_set
141  * @param[in] tv timeval structure
142  * @retval last file descriptor
143  */
144 
prepare_select(t_conf * conf,fd_set * rfds,struct timeval * tv)145 int	prepare_select(t_conf *conf, fd_set *rfds, struct timeval *tv)
146 {
147 #ifndef _WIN32
148   return (unix_prepare_select(conf, rfds, tv));
149 #else
150   return (win_prepare_select(conf, (WSAEVENT *)rfds, tv));
151 #endif
152 }
153