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