1
2 #include "gs-common.h"
3 #include <fcntl.h>
4 #include <gsocket/gsocket.h>
5 #include <gsocket/gs-select.h>
6 #include "gsocket-engine.h"
7 #include "gs-externs.h"
8
9
10 /********* FUNCTIONS ********************/
11
12 int
GS_SELECT_CTX_init(GS_SELECT_CTX * ctx,fd_set * rfd,fd_set * wfd,fd_set * r,fd_set * w,struct timeval * tv_now,int frequency)13 GS_SELECT_CTX_init(GS_SELECT_CTX *ctx, fd_set *rfd, fd_set *wfd, fd_set *r, fd_set *w, struct timeval *tv_now, int frequency)
14 {
15
16 memset(ctx, 0, sizeof *ctx);
17 ctx->rfd = rfd;
18 ctx->wfd = wfd;
19 ctx->r = r;
20 ctx->w = w;
21
22 ctx->tv_now = tv_now;
23
24 gettimeofday(ctx->tv_now, NULL);
25 GS_EVENT_MGR_init(&ctx->emgr);
26 GS_EVENT_add_by_ts(&ctx->emgr, &ctx->hb, 0, frequency, NULL, NULL, 0);
27
28 // ctx->hb_init = GS_TV_TO_USEC(ctx->tv_now);
29 // ctx->hb_freq = frequency;
30
31 int i;
32 for (i = 0; i < FD_SETSIZE; i++)
33 {
34 ctx->mgr_r[i].func = NULL;
35 ctx->mgr_w[i].func = NULL;
36 }
37
38 return 0;
39 }
40
41 void
gs_select_rw_save_state(GS_SELECT_CTX * ctx,int fd,char * idstr)42 gs_select_rw_save_state(GS_SELECT_CTX *ctx, int fd, char *idstr)
43 {
44 /* Save rfd/wfd state */
45 if (ctx->is_rw_state_saved[fd] == 1)
46 {
47 // DEBUGF_R("*** WARNING ***: RWFD already saved. SKIPPING (fd = %d, %s)\n", fd, idstr);
48 return;
49 }
50
51 DEBUGF_M("Saving state (fd = %d, %s):\n", fd, idstr);
52 gs_fds_out_fd(ctx->rfd, 'r', fd);
53 gs_fds_out_fd(ctx->wfd, 'w', fd);
54
55 ctx->saved_rw_state[fd] = 0;
56 ctx->is_rw_state_saved[fd] = 1;
57
58 if (FD_ISSET(fd, ctx->rfd))
59 ctx->saved_rw_state[fd] |= 0x01;
60 if (FD_ISSET(fd, ctx->wfd))
61 ctx->saved_rw_state[fd] |= 0x02;
62 }
63
64 void
gs_select_rw_restore_state(GS_SELECT_CTX * ctx,int fd,char * idstr)65 gs_select_rw_restore_state(GS_SELECT_CTX *ctx, int fd, char *idstr)
66 {
67 if (ctx->is_rw_state_saved[fd] == 0)
68 {
69 // DEBUGF("RWFD was not saved. Nothing to restore (fd = %d, %s).\n", fd, idstr);
70 return;
71 }
72
73 // DEBUGF_B("Restoring RWFD state (fd = %d, %s, %d)\n", fd, idstr, ctx->is_rw_state_saved[fd]);
74 /* This can happen when FD was half-closed (shutdown received):
75 * - We stopped reading (rfd not set)
76 * - Write() triggered would-block (wfd set) and then restored to 0.
77 */
78 if (ctx->saved_rw_state[fd] == 0)
79 DEBUGF_Y("*** NOTE ***: Restoring empty RW state (fd = %d, %s)\n", fd, idstr);
80 ctx->is_rw_state_saved[fd] = 0;
81
82 FD_CLR(fd, ctx->rfd);
83 FD_CLR(fd, ctx->wfd);
84 if (ctx->saved_rw_state[fd] & 0x01)
85 XFD_SET(fd, ctx->rfd);
86 if (ctx->saved_rw_state[fd] & 0x02)
87 XFD_SET(fd, ctx->wfd);
88 ctx->saved_rw_state[fd] = 0;
89
90 if (fd > 0)
91 {
92 DEBUGF_M("Restored state:\n");
93 gs_fds_out_fd(ctx->rfd, 'r', fd);
94 gs_fds_out_fd(ctx->wfd, 'w', fd);
95 }
96 }
97
98 void
gs_select_set_rdata_pending(GS_SELECT_CTX * ctx,int fd,int len)99 gs_select_set_rdata_pending(GS_SELECT_CTX *ctx, int fd, int len)
100 {
101 ctx->rdata_pending_count++;
102 ctx->rdata_pending[fd] = len;
103 }
104
105 static void
call_item(GS_SELECT_CTX * ctx,struct _gs_sel_item * item,int fd)106 call_item(GS_SELECT_CTX *ctx, struct _gs_sel_item *item, int fd)
107 {
108 // int ret;
109
110 (*item->func)(ctx, fd, item->cb_arg, item->cb_val);
111 // DEBUGF("cb-func ret = %d (fd %d)\n", ret, fd);
112 /* 1. Think carefully: STDIN (fd=0) may have succesfully
113 * 1024 bytes but GS_write (fd=3) failed (WANT-WRITE).
114 * - Do not set fd=0 to WANT-WRITE. Instead the GS_write()
115 * should set that flag on itself (fd=3).
116 *
117 * 2. Think carefully: Not all GS_read/GS_write functions
118 * are called by callbacks: Reading from STDIN calls
119 * GS_write() regardless if GS_write() would block or not.
120 */
121 }
122
123 /*
124 * Return 0 on timeout.
125 * Return -1 on fatal error. Errno is set.
126 */
127 int
GS_select(GS_SELECT_CTX * ctx)128 GS_select(GS_SELECT_CTX *ctx)
129 {
130 int n;
131 struct timeval tv;
132 // int ret;
133 int i;
134
135
136 while (1)
137 {
138 int max_fd = ctx->max_fd;
139
140 /* Before calling select() to check if there is new data on I/O:
141 * - Check if there is already data in the user-land (such as from
142 * SSL_pending() before checking I/O [kernel].
143 */
144 for (i = 0; i <= max_fd; i++)
145 {
146 if (ctx->rdata_pending_count <= 0)
147 break;
148 /* Continue if there is no pending data in the input read buffer */
149 if (ctx->rdata_pending[i] == 0)
150 continue;
151 /* Continue if the app does not want us to submit read data */
152 if (!FD_ISSET(i, ctx->rfd))
153 continue;
154 /* HERE: Call to GS_read() needed because there is still
155 * data in the input buffer (not i/o buffer).
156 */
157 DEBUGF_Y("fd=%d Pending data in SSL read input buffer (len=%d):>\n", i, ctx->rdata_pending[i]);
158 ctx->rdata_pending_count--;
159 call_item(ctx, &ctx->mgr_r[i], i);
160 }
161 /* Do it again if there are still items that
162 * have data in their input buffer...
163 */
164 if (ctx->rdata_pending_count > 0)
165 continue;
166
167 memcpy(ctx->r, ctx->rfd, sizeof *ctx->r);
168 memcpy(ctx->w, ctx->wfd, sizeof *ctx->w);
169
170 uint64_t wait;
171 wait = GS_EVENT_execute(&ctx->emgr);
172
173 gettimeofday(ctx->tv_now, NULL);
174 GS_USEC_TO_TV(&tv, wait);
175
176 gs_fds_out_rwfd(ctx); // BUG-2-MAX-FD
177 n = select(max_fd + 1, ctx->r, ctx->w, NULL, &tv);
178 // DEBUGF_B("max-fd = %d, *************** select = %d\n", max_fd, n);
179 if (n < 0)
180 {
181 if (errno == EINTR)
182 continue;
183 return -1;
184 }
185
186 gettimeofday(ctx->tv_now, NULL);
187
188 // gs_fds_out(ctx->r, max_fd, 'r');
189 // gs_fds_out(ctx->w, max_fd, 'w');
190 // int wants = 0;
191 for (i = 0; i <= max_fd; i++)
192 {
193 /* 'n' is not reliable as a listening gsocket might handle more than 1 fd
194 * if more than 1 are readable. Only 1 listen-callback will be called
195 * but the callback may serve more than 1 fd.
196 */
197 if (n <= 0)
198 break;
199 struct _gs_sel_item *item = NULL;
200 char c;
201 /* Must check r and rfd in case app deselected rfd to stop reading */
202 if (FD_ISSET(i, ctx->r) && FD_ISSET(i, ctx->rfd))
203 {
204 // DEBUGF_B("I/O == READ (fd = %d)\n", i);
205 /* GS_CALLREAD or GS_CALLDEFAULT */
206 /* Find out if read-i/o was required because GS_write() set
207 * WANT_READ.
208 */
209 item = &ctx->mgr_r[i];
210 c = 'r';
211 if (ctx->want_io_read[i])
212 {
213 if (ctx->blocking_func[i] & GS_CALLWRITE)
214 {
215 item = &ctx->mgr_w[i];
216 c = 'W';
217 }
218 }
219
220 // DEBUGF_B("CTX-R: %c fd=%d\n", c, i);
221 XASSERT(item->func != NULL, "%c fd = %d has no function to call\n", c, i);
222 call_item(ctx, item, i);
223 n--;
224 }
225
226 if (FD_ISSET(i, ctx->w) && FD_ISSET(i, ctx->wfd))
227 {
228 // DEBUGF_B("I/O == WRITE (fd = %d)\n", i);
229 item = &ctx->mgr_w[i];
230 c = 'w';
231 if (ctx->want_io_write[i])
232 {
233 if (ctx->blocking_func[i] & GS_CALLREAD)
234 {
235 item = &ctx->mgr_r[i];
236 c = 'R';
237 }
238 }
239
240 // DEBUGF_B("call_item: %c fd=%d\n", c, i);
241 XASSERT(item->func != NULL, "%c fd = %d has no function to call\n", c, i);
242 call_item(ctx, item, i);
243 n--;
244 } /* FD_ISSET(i, ctx->w) */
245 } /* for () */
246
247 /* Time to return control to caller? */
248 if (ctx->emgr.is_return_to_caller)
249 {
250 ctx->emgr.is_return_to_caller = 0;
251 return 0;
252 }
253 // if (((ctx->hb_freq > 0) && GS_TV_TO_USEC(ctx->tv_now) > ctx->hb_next))
254 // {
255 // return 0;
256 // }
257 } /* while (1) */
258
259 ERREXIT("NOT REACHED\n");
260 return -1;
261 }
262
263 void
GS_SELECT_del_cb(GS_SELECT_CTX * ctx,int fd)264 GS_SELECT_del_cb(GS_SELECT_CTX *ctx, int fd)
265 {
266 int new_max_fd = 0;
267
268 DEBUGF_B("Removing CB for fd = %d\n", fd);
269 ctx->mgr_r[fd].func = NULL;
270 ctx->mgr_w[fd].func = NULL;
271 ctx->mgr_r[fd].cb_arg = NULL;
272 ctx->mgr_w[fd].cb_arg = NULL;
273 ctx->mgr_w[fd].cb_val = 0;
274 ctx->mgr_r[fd].cb_val = 0;
275 FD_CLR(fd, ctx->rfd);
276 FD_CLR(fd, ctx->wfd);
277 FD_CLR(fd, ctx->r);
278 FD_CLR(fd, ctx->w);
279 /* Calcualte new max-fd */
280 int i;
281 #ifdef DEBUG
282 char buf[FD_SETSIZE + 1];
283 memset(buf, '-', sizeof buf);
284 buf[ctx->max_fd + 1] = '\0';
285 int c;
286 int tracking = 0;
287 #endif
288
289 for (i = 0; i <= ctx->max_fd; i++)
290 {
291
292 if ((ctx->mgr_r[i].func == NULL) && (ctx->mgr_w[i].func == NULL))
293 {
294 continue;
295 }
296 #ifdef DEBUG
297 tracking += 1;
298 c = 0;
299 if (ctx->mgr_r[i].func != NULL)
300 c = 1;
301 if (ctx->mgr_w[i].func != NULL)
302 c += 2;
303 if (c == 1)
304 buf[i] = 'r'; // should not happen
305 if (c == 2)
306 buf[i] = 'w'; // should not happen.
307 if (c == 3)
308 buf[i] = 'X'; // both callback functions set (normal case).
309 #endif
310 new_max_fd = i;
311 }
312 #ifdef DEBUG
313 buf[fd] = '*'; // This one being removed
314 // BUG-2-MAX-FD
315 // xfprintf(gs_errfp, "%s (CB funcs, tracking=%d, max=%d)\n", buf, tracking, ctx->max_fd);
316 #endif
317
318 DEBUGF("Setting MAX-FD to %d\n", new_max_fd);
319 ctx->max_fd = new_max_fd;
320 }
321
322 void
GS_SELECT_add_cb_r(GS_SELECT_CTX * ctx,gselect_cb_t func,int fd,void * arg,int val)323 GS_SELECT_add_cb_r(GS_SELECT_CTX *ctx, gselect_cb_t func, int fd, void *arg, int val)
324 {
325 DEBUGF_B("Adding CB-r for fd = %d\n", fd);
326 ctx->mgr_r[fd].func = (void *)func;
327 ctx->mgr_r[fd].cb_arg = arg;
328 ctx->mgr_r[fd].cb_val = val;
329 ctx->max_fd = MAX(ctx->max_fd, fd);
330 }
331
332 void
GS_SELECT_add_cb_w(GS_SELECT_CTX * ctx,gselect_cb_t func,int fd,void * arg,int val)333 GS_SELECT_add_cb_w(GS_SELECT_CTX *ctx, gselect_cb_t func, int fd, void *arg, int val)
334 {
335 DEBUGF_B("Adding CB-w for fd = %d\n", fd);
336 ctx->mgr_w[fd].func = (void *)func;
337 ctx->mgr_w[fd].cb_arg = arg;
338 ctx->mgr_w[fd].cb_val = val;
339 ctx->max_fd = MAX(ctx->max_fd, fd);
340 }
341
342 void
GS_SELECT_add_cb(GS_SELECT_CTX * ctx,gselect_cb_t func_r,gselect_cb_t func_w,int fd,void * arg,int val)343 GS_SELECT_add_cb(GS_SELECT_CTX *ctx, gselect_cb_t func_r, gselect_cb_t func_w, int fd, void *arg, int val)
344 {
345 GS_SELECT_add_cb_r(ctx, func_r, fd, arg, val);
346 GS_SELECT_add_cb_w(ctx, func_w, fd, arg, val);
347 }
348
349
350
351