changed sockets and pipes used in httped to work in non-blocking mode
This commit is contained in:
		| @ -92,7 +92,14 @@ enum qse_pio_flag_t | |||||||
| 	/** return immediately from qse_pio_wait() if a child has not exited */ | 	/** return immediately from qse_pio_wait() if a child has not exited */ | ||||||
| 	QSE_PIO_WAITNOBLOCK   = (1 << 23), | 	QSE_PIO_WAITNOBLOCK   = (1 << 23), | ||||||
| 	/** do not wait again if waitpid has been interrupted */ | 	/** do not wait again if waitpid has been interrupted */ | ||||||
| 	QSE_PIO_WAITNORETRY   = (1 << 24) | 	QSE_PIO_WAITNORETRY   = (1 << 24), | ||||||
|  |  | ||||||
|  | 	/** put stdin to non-blocking mode (only on supported platforms) */ | ||||||
|  | 	QSE_PIO_INNOBLOCK   = (1 << 25), | ||||||
|  | 	/** put stdout to non-blocking mode (only on supported platforms)*/ | ||||||
|  | 	QSE_PIO_OUTNOBLOCK  = (1 << 26), | ||||||
|  | 	/** put stderr to non-blocking mode (only on supported platforms) */ | ||||||
|  | 	QSE_PIO_ERRNOBLOCK  = (1 << 27) | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -438,6 +438,26 @@ qse_mux_errnum_t qse_mux_geterrnum (qse_mux_t* mux) | |||||||
|  |  | ||||||
| int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt) | int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt) | ||||||
| { | { | ||||||
|  | #if defined(USE_SELECT) | ||||||
|  | 	/* nothing */ | ||||||
|  | #elif defined(USE_KQUEUE) | ||||||
|  | 	struct kevent chlist[2]; | ||||||
|  | 	int count = 0; | ||||||
|  | #elif defined(USE_EPOLL) | ||||||
|  | 	struct epoll_event ev; | ||||||
|  | #elif defined(__OS2__) | ||||||
|  | 	/* nothing */ | ||||||
|  | #else | ||||||
|  | 	/* nothing */ | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	/* sanity check */ | ||||||
|  | 	if (!(evt->mask & (QSE_MUX_IN | QSE_MUX_OUT)) || evt->hnd < 0)  | ||||||
|  | 	{ | ||||||
|  | 		mux->errnum = QSE_MUX_EINVAL; | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| #if defined(USE_SELECT) | #if defined(USE_SELECT) | ||||||
|  |  | ||||||
| 	/* TODO: windows seems to return a pretty high file descriptors | 	/* TODO: windows seems to return a pretty high file descriptors | ||||||
| @ -482,9 +502,6 @@ int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt) | |||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| #elif defined(USE_KQUEUE) | #elif defined(USE_KQUEUE) | ||||||
| 	struct kevent chlist[2]; |  | ||||||
| 	int count = 0; |  | ||||||
|  |  | ||||||
| 	/* TODO: study if it is better to put 'evt' to the udata  | 	/* TODO: study if it is better to put 'evt' to the udata  | ||||||
| 	 *       field of chlist? */ | 	 *       field of chlist? */ | ||||||
|  |  | ||||||
| @ -502,11 +519,7 @@ int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt) | |||||||
| 		count++; | 		count++; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (count == 0 || evt->hnd < 0) | 	QSE_ASSERT (count > 0); | ||||||
| 	{ |  | ||||||
| 		mux->errnum = QSE_MUX_EINVAL; |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (evt->hnd >= mux->me.ubound) | 	if (evt->hnd >= mux->me.ubound) | ||||||
| 	{ | 	{ | ||||||
| @ -550,17 +563,12 @@ int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt) | |||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| #elif defined(USE_EPOLL) | #elif defined(USE_EPOLL) | ||||||
| 	struct epoll_event ev; |  | ||||||
|  |  | ||||||
| 	QSE_MEMSET (&ev, 0, QSE_SIZEOF(ev)); | 	QSE_MEMSET (&ev, 0, QSE_SIZEOF(ev)); | ||||||
| 	if (evt->mask & QSE_MUX_IN) ev.events |= EPOLLIN; | 	if (evt->mask & QSE_MUX_IN) ev.events |= EPOLLIN; | ||||||
| 	if (evt->mask & QSE_MUX_OUT) ev.events |= EPOLLOUT; | 	if (evt->mask & QSE_MUX_OUT) ev.events |= EPOLLOUT; | ||||||
|  |  | ||||||
| 	if (ev.events == 0 || evt->hnd < 0) | 	QSE_ASSERT (ev.events != 0); | ||||||
| 	{ |  | ||||||
| 		mux->errnum = QSE_MUX_EINVAL; |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (evt->hnd >= mux->me.ubound) | 	if (evt->hnd >= mux->me.ubound) | ||||||
| 	{ | 	{ | ||||||
| @ -937,13 +945,13 @@ int qse_mux_poll (qse_mux_t* mux, const qse_ntime_t* tmout) | |||||||
| 		if (mux->ee.ptr[i].events & EPOLLIN) xevt.mask |= QSE_MUX_IN; | 		if (mux->ee.ptr[i].events & EPOLLIN) xevt.mask |= QSE_MUX_IN; | ||||||
| 		if (mux->ee.ptr[i].events & EPOLLOUT) xevt.mask |= QSE_MUX_OUT; | 		if (mux->ee.ptr[i].events & EPOLLOUT) xevt.mask |= QSE_MUX_OUT; | ||||||
|  |  | ||||||
| 		if (mux->ee.ptr[i].events & EPOLLHUP) | 		if (mux->ee.ptr[i].events & (EPOLLHUP | EPOLLERR)) | ||||||
| 		{ | 		{ | ||||||
| 			if (evt->mask & QSE_MUX_IN) xevt.mask |= QSE_MUX_IN; | 			if (evt->mask & QSE_MUX_IN) xevt.mask |= QSE_MUX_IN; | ||||||
| 			if (evt->mask & QSE_MUX_OUT) xevt.mask |= QSE_MUX_OUT; | 			if (evt->mask & QSE_MUX_OUT) xevt.mask |= QSE_MUX_OUT; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		mux->evtfun (mux, &xevt); | 		if (xevt.mask > 0) mux->evtfun (mux, &xevt); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nfds; | 	return nfds; | ||||||
|  | |||||||
| @ -429,6 +429,22 @@ static int get_highest_fd (void) | |||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | static int set_pipe_nonblock (qse_pio_t* pio, qse_pio_hnd_t fd, int enabled) | ||||||
|  | { | ||||||
|  | #if defined(O_NONBLOCK) | ||||||
|  |  | ||||||
|  | 	int flag = QSE_FCNTL (fd, F_GETFL, 0); | ||||||
|  | 	if (flag >= 0) flag = QSE_FCNTL (fd, F_SETFL, (enabled? (flag | O_NONBLOCK): (flag & ~O_NONBLOCK))); | ||||||
|  | 	if (flag <= -1) pio->errnum = syserr_to_errnum (errno); | ||||||
|  | 	return flag; | ||||||
|  |  | ||||||
|  | #else | ||||||
|  | 	pio->errnum = QSE_PIO_ENOIMPL; | ||||||
|  | 	return -1; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| int qse_pio_init ( | int qse_pio_init ( | ||||||
| 	qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd,  | 	qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd,  | ||||||
| 	qse_env_t* env, int flags) | 	qse_env_t* env, int flags) | ||||||
| @ -1785,6 +1801,13 @@ create_process: | |||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	if (((flags & QSE_PIO_INNOBLOCK) && set_pipe_nonblock(pio, handle[1], 1) <= -1) || | ||||||
|  | 	    ((flags & QSE_PIO_OUTNOBLOCK) && set_pipe_nonblock(pio, handle[2], 1) <= -1) || | ||||||
|  | 	    ((flags & QSE_PIO_ERRNOBLOCK) && set_pipe_nobnlock(pio, handle[4], 1) <= -1)) | ||||||
|  | 	{ | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/* store back references */ | 	/* store back references */ | ||||||
| 	pio->pin[QSE_PIO_IN].self = pio; | 	pio->pin[QSE_PIO_IN].self = pio; | ||||||
| 	pio->pin[QSE_PIO_OUT].self = pio; | 	pio->pin[QSE_PIO_OUT].self = pio; | ||||||
| @ -1795,6 +1818,7 @@ create_process: | |||||||
| 	pio->pin[QSE_PIO_OUT].handle = handle[2]; | 	pio->pin[QSE_PIO_OUT].handle = handle[2]; | ||||||
| 	pio->pin[QSE_PIO_ERR].handle = handle[4]; | 	pio->pin[QSE_PIO_ERR].handle = handle[4]; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	if (flags & QSE_PIO_TEXT) | 	if (flags & QSE_PIO_TEXT) | ||||||
| 	{ | 	{ | ||||||
| 		int topt = 0; | 		int topt = 0; | ||||||
|  | |||||||
| @ -25,6 +25,16 @@ | |||||||
| #include <qse/cmn/fmt.h> | #include <qse/cmn/fmt.h> | ||||||
| #include <qse/cmn/path.h> | #include <qse/cmn/path.h> | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	/* nothing */ | ||||||
|  | #elif defined(__OS2__) | ||||||
|  | 	/* nothing */ | ||||||
|  | #elif defined(__DOS__) | ||||||
|  | 	/* nothing */ | ||||||
|  | #else | ||||||
|  | #	include "../cmn/syscall.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #include <stdio.h> /* TODO: remove this */ | #include <stdio.h> /* TODO: remove this */ | ||||||
| #if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) | #if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) | ||||||
| #	define snprintf _snprintf  | #	define snprintf _snprintf  | ||||||
| @ -104,6 +114,8 @@ struct cgi_client_req_hdr_ctx_t | |||||||
| 	qse_env_t* env; | 	qse_env_t* env; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int cgi_capture_client_header ( | static int cgi_capture_client_header ( | ||||||
| 	qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx) | 	qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx) | ||||||
| { | { | ||||||
| @ -637,33 +649,14 @@ static void cgi_forward_client_input_to_script ( | |||||||
| 			/* normal forwarding */ | 			/* normal forwarding */ | ||||||
| 			qse_ssize_t n; | 			qse_ssize_t n; | ||||||
|  |  | ||||||
| 			if (writable) goto forward; |  | ||||||
|  |  | ||||||
| 			n = httpd->opt.scb.mux.writable ( |  | ||||||
| 				httpd, qse_pio_gethandleasubi (&cgi->pio, QSE_PIO_IN), 0); |  | ||||||
| 			if (n >= 1) |  | ||||||
| 			{ |  | ||||||
| 			forward: |  | ||||||
| 				/* writable */ |  | ||||||
| 			n = qse_pio_write ( | 			n = qse_pio_write ( | ||||||
| 				&cgi->pio, QSE_PIO_IN, | 				&cgi->pio, QSE_PIO_IN, | ||||||
| 				QSE_MBS_PTR(cgi->reqfwdbuf), | 				QSE_MBS_PTR(cgi->reqfwdbuf), | ||||||
| 				QSE_MBS_LEN(cgi->reqfwdbuf) | 				QSE_MBS_LEN(cgi->reqfwdbuf) | ||||||
| 			); | 			); | ||||||
| 				if (n > 0)  |  | ||||||
| 				{ |  | ||||||
| /* TODO: improve performance.. instead of copying the remaing part  |  | ||||||
| to the head all the time..  grow the buffer to a certain limit. */ |  | ||||||
| 					qse_mbs_del (cgi->reqfwdbuf, 0, n); |  | ||||||
| 					if (QSE_MBS_LEN(cgi->reqfwdbuf) <= 0) |  | ||||||
| 					{ |  | ||||||
| 						if (cgi->reqflags & CGI_REQ_GOTALL) goto done; |  | ||||||
| 						else task->trigger.v[1].mask = 0; /* pipe output to child */ |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (n <= -1) | 			if (n <= -1) | ||||||
|  | 			{ | ||||||
|  | 				if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN) | ||||||
| 				{ | 				{ | ||||||
| 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 						log_cgi_script_error (cgi, QSE_MT("cgi pio write error - ")); | 						log_cgi_script_error (cgi, QSE_MT("cgi pio write error - ")); | ||||||
| @ -690,6 +683,18 @@ to the head all the time..  grow the buffer to a certain limit. */ | |||||||
| 					task->trigger.v[1].mask = 0; /* pipe output to child */ | 					task->trigger.v[1].mask = 0; /* pipe output to child */ | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 			else if (n > 0)  | ||||||
|  | 			{ | ||||||
|  | /* TODO: improve performance.. instead of copying the remaing part  | ||||||
|  | to the head all the time..  grow the buffer to a certain limit. */ | ||||||
|  | 				qse_mbs_del (cgi->reqfwdbuf, 0, n); | ||||||
|  | 				if (QSE_MBS_LEN(cgi->reqfwdbuf) <= 0) | ||||||
|  | 				{ | ||||||
|  | 					if (cgi->reqflags & CGI_REQ_GOTALL) goto done; | ||||||
|  | 					else task->trigger.v[1].mask = 0; /* pipe output to child */ | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	else if (cgi->reqflags & CGI_REQ_GOTALL) | 	else if (cgi->reqflags & CGI_REQ_GOTALL) | ||||||
| 	{ | 	{ | ||||||
| @ -953,10 +958,18 @@ static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer ( | |||||||
| 		&cgi->buf[cgi->buflen],  | 		&cgi->buf[cgi->buflen],  | ||||||
| 		QSE_SIZEOF(cgi->buf) - cgi->buflen | 		QSE_SIZEOF(cgi->buf) - cgi->buflen | ||||||
| 	); | 	); | ||||||
| 	if (n > 0) cgi->buflen += n; | 	if (n <= -1) | ||||||
|  | 	{ | ||||||
| 	if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | 		if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN) | ||||||
|  | 		{ | ||||||
|  | 			if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 				log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | 				log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		n = -999; | ||||||
|  | 	} | ||||||
|  | 	else if (n > 0) cgi->buflen += n; | ||||||
|  |  | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
| @ -966,16 +979,25 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client ( | |||||||
| { | { | ||||||
| 	qse_ssize_t n; | 	qse_ssize_t n; | ||||||
|  |  | ||||||
|  | 	QSE_ASSERT (cgi->buflen > 0); | ||||||
|  |  | ||||||
|  | 	httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 	n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen); | 	n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen); | ||||||
| 	if (n > 0) | 	if (n <= -1) | ||||||
|  | 	{ | ||||||
|  | 		if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
|  | 		{ | ||||||
|  | 			if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 				log_cgi_script_error (cgi, QSE_MT("cgi write error to client - ")); | ||||||
|  | 		} | ||||||
|  | 		else n = 0; | ||||||
|  | 	} | ||||||
|  | 	else if (n > 0) | ||||||
| 	{ | 	{ | ||||||
| 		QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); | 		QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); | ||||||
| 		cgi->buflen -= n; | 		cgi->buflen -= n; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  |  | ||||||
| 		log_cgi_script_error (cgi, QSE_MT("cgi write error to client - ")); |  | ||||||
|  |  | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -998,10 +1020,7 @@ static int task_main_cgi_5 ( | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ | 	if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ cgi->buflen > 0) | ||||||
| 	    (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) |  | ||||||
| 	{ |  | ||||||
| 		if (cgi->buflen > 0) |  | ||||||
| 	{ | 	{ | ||||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | ||||||
| 		{ | 		{ | ||||||
| @ -1009,7 +1028,6 @@ static int task_main_cgi_5 ( | |||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* if forwarding didn't finish, something is not really right...  | 	/* if forwarding didn't finish, something is not really right...  | ||||||
| 	 * so long as the output from CGI is finished, no more forwarding | 	 * so long as the output from CGI is finished, no more forwarding | ||||||
| @ -1042,9 +1060,21 @@ static int task_main_cgi_4_nph ( | |||||||
| 	{ | 	{ | ||||||
| 		if (cgi->buflen < QSE_SIZEOF(cgi->buf)) | 		if (cgi->buflen < QSE_SIZEOF(cgi->buf)) | ||||||
| 		{ | 		{ | ||||||
| 			n = cgi_read_script_output_to_buffer (httpd, client, cgi); | 			n = qse_pio_read ( | ||||||
| 			if (n <= -1) return -1; /* TODO: logging */ | 				&cgi->pio, QSE_PIO_OUT, | ||||||
| 			if (n == 0)  | 				&cgi->buf[cgi->buflen],  | ||||||
|  | 				QSE_SIZEOF(cgi->buf) - cgi->buflen | ||||||
|  | 			); | ||||||
|  | 			if (n <= -1) | ||||||
|  | 			{ | ||||||
|  | 				if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN) | ||||||
|  | 				{ | ||||||
|  | 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 						log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
|  | 					return -1; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else if (n == 0) | ||||||
| 			{ | 			{ | ||||||
| 				/* switch to the next phase */ | 				/* switch to the next phase */ | ||||||
| 				task->main = task_main_cgi_5; | 				task->main = task_main_cgi_5; | ||||||
| @ -1052,10 +1082,10 @@ static int task_main_cgi_4_nph ( | |||||||
| 				task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | 				task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
| 				return 1; | 				return 1; | ||||||
| 			} | 			} | ||||||
|  | 			else cgi->buflen += n; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		QSE_ASSERT (cgi->buflen > 0); | 		if (cgi->buflen > 0 && cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; | ||||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 1; | 	return 1; | ||||||
| @ -1109,12 +1139,15 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 					count - extra | 					count - extra | ||||||
| 				); | 				); | ||||||
| 				if (n <= -1) | 				if (n <= -1) | ||||||
|  | 				{ | ||||||
|  | 					if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN) | ||||||
| 					{ | 					{ | ||||||
| 						if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | 						if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 							log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | 							log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
| 						return -1; | 						return -1; | ||||||
| 					} | 					} | ||||||
| 				if (n == 0)  | 				} | ||||||
|  | 				else if (n == 0)  | ||||||
| 				{ | 				{ | ||||||
| 					/* the cgi script closed the output */ | 					/* the cgi script closed the output */ | ||||||
| 					cgi->buf[cgi->buflen++] = QSE_MT('0'); | 					cgi->buf[cgi->buflen++] = QSE_MT('0'); | ||||||
| @ -1128,7 +1161,8 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 					task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | 					task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
| 					return 1; | 					return 1; | ||||||
| 				} | 				} | ||||||
| 	 | 				else | ||||||
|  | 				{ | ||||||
| 					/* set the chunk length. if the length string is less  | 					/* set the chunk length. if the length string is less  | ||||||
| 					 * than 4 digits, the right side of the string is filled | 					 * than 4 digits, the right side of the string is filled | ||||||
| 					 * with space letters. for example, the chunk length line | 					 * with space letters. for example, the chunk length line | ||||||
| @ -1159,13 +1193,26 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			if (cgi->buflen < QSE_SIZEOF(cgi->buf)) | 			if (cgi->buflen < QSE_SIZEOF(cgi->buf)) | ||||||
| 			{ | 			{ | ||||||
| 				n = cgi_read_script_output_to_buffer (httpd, client, cgi); | 				n = qse_pio_read ( | ||||||
| 				if (n <= -1) return -1; /* TODO: logging */ | 					&cgi->pio, QSE_PIO_OUT, | ||||||
| 				if (n == 0)  | 					&cgi->buf[cgi->buflen],  | ||||||
|  | 					QSE_SIZEOF(cgi->buf) - cgi->buflen | ||||||
|  | 				); | ||||||
|  | 				if (n <= -1) | ||||||
|  | 				{ | ||||||
|  | 					if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN) | ||||||
|  | 					{ | ||||||
|  | 						if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 							log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
|  | 						return -1; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				else if (n == 0)  | ||||||
| 				{ | 				{ | ||||||
| 					/* switch to the next phase */ | 					/* switch to the next phase */ | ||||||
| 					task->main = task_main_cgi_5; | 					task->main = task_main_cgi_5; | ||||||
| @ -1173,7 +1220,8 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 					task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | 					task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
| 					return 1; | 					return 1; | ||||||
| 				} | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
| 					cgi->script_output_received += n; | 					cgi->script_output_received += n; | ||||||
| 					if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | 					if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | ||||||
| 						cgi->script_output_received > cgi->script_output_length) | 						cgi->script_output_received > cgi->script_output_length) | ||||||
| @ -1185,12 +1233,12 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 	 | 	 | ||||||
| 		/* the main loop invokes the task function only if the client  | 		/* the main loop invokes the task function only if the client  | ||||||
| 		 * side is writable. it should be safe to write whenever | 		 * side is writable. it should be safe to write whenever | ||||||
| 		 * this task function is called. */ | 		 * this task function is called. */ | ||||||
| 		QSE_ASSERT (cgi->buflen > 0); | 		if (cgi->buflen > 0 && cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; | ||||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 1; | 	return 1; | ||||||
| @ -1226,25 +1274,26 @@ printf ("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
|  |  | ||||||
| 	/* send the partial reponse received with the initial line and headers | 	/* send the partial reponse received with the initial line and headers | ||||||
| 	 * so long as the client-side handle is writable... */ | 	 * so long as the client-side handle is writable... */ | ||||||
| 	if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ | 	if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ cgi->res_left > 0) | ||||||
| 	    (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) |  | ||||||
| 	{ | 	{ | ||||||
| 		count = MAX_SEND_SIZE; | 		count = cgi->res_left; | ||||||
| 		if (count >= cgi->res_left) count = cgi->res_left; | 		if (count >= MAX_SEND_SIZE) count = MAX_SEND_SIZE; | ||||||
|  |  | ||||||
| 		if (count > 0) | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		{ |  | ||||||
| 		n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count); | 		n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count); | ||||||
| 		if (n <= -1)  | 		if (n <= -1)  | ||||||
|  | 		{ | ||||||
|  | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_cgi_script_error (cgi, QSE_MT("cgi initial write error to client - ")); | 					log_cgi_script_error (cgi, QSE_MT("cgi initial write error to client - ")); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  | 		else if (n > 0) | ||||||
|  | 		{ | ||||||
| 			cgi->res_ptr += n; | 			cgi->res_ptr += n; | ||||||
| 			cgi->res_left -= n; | 			cgi->res_left -= n; | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 			if (cgi->res_left <= 0)  | 			if (cgi->res_left <= 0)  | ||||||
| 			{ | 			{ | ||||||
| @ -1270,7 +1319,7 @@ printf ("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 				} | 				} | ||||||
| 				return 1; | 				return 1; | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 1; /* more work to do */ | 	return 1; /* more work to do */ | ||||||
| @ -1319,13 +1368,16 @@ printf ("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 			QSE_SIZEOF(cgi->buf) - cgi->buflen | 			QSE_SIZEOF(cgi->buf) - cgi->buflen | ||||||
| 		); | 		); | ||||||
| 		if (n <= -1) | 		if (n <= -1) | ||||||
|  | 		{ | ||||||
|  | 			if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				/* can't return internal server error any more... */ | 				/* can't return internal server error any more... */ | ||||||
| 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | 					log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 		if (n == 0)  | 		} | ||||||
|  | 		else if (n == 0)  | ||||||
| 		{ | 		{ | ||||||
| 			/* end of output from cgi before it has seen a header. | 			/* end of output from cgi before it has seen a header. | ||||||
| 			 * the cgi script must be crooked. */ | 			 * the cgi script must be crooked. */ | ||||||
| @ -1333,8 +1385,13 @@ printf ("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 				log_cgi_script_error (cgi, QSE_MT("cgi premature eof - ")); | 				log_cgi_script_error (cgi, QSE_MT("cgi premature eof - ")); | ||||||
| 			goto oops; | 			goto oops; | ||||||
| 		} | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
| 			cgi->buflen += n; | 			cgi->buflen += n; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (cgi->buflen > 0) | ||||||
|  | 		{ | ||||||
| 			if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1) | 			if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1) | ||||||
| 			{ | 			{ | ||||||
| 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| @ -1343,6 +1400,7 @@ printf ("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			cgi->buflen = 0; | 			cgi->buflen = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (QSE_MBS_LEN(cgi->res) > 0) | 		if (QSE_MBS_LEN(cgi->res) > 0) | ||||||
| 		{ | 		{ | ||||||
| @ -1410,7 +1468,11 @@ static int task_main_cgi ( | |||||||
| 		if (cgi->res == QSE_NULL) goto oops; | 		if (cgi->res == QSE_NULL) goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	pio_options = QSE_PIO_READOUT | QSE_PIO_WRITEIN | QSE_PIO_MBSCMD; | 	/* <<WARNING>> | ||||||
|  | 	 *  QSE_PIO_INNOBLOCK and QSE_PIO_OUTNONBLOCK are not supported | ||||||
|  | 	 *   on non-unix/linux platforms. so the CGI task can only be | ||||||
|  | 	 *   used on unix/linux platforms */ | ||||||
|  | 	pio_options = QSE_PIO_READOUT | QSE_PIO_WRITEIN | QSE_PIO_MBSCMD | QSE_PIO_INNOBLOCK | QSE_PIO_OUTNOBLOCK; | ||||||
| 	if (httpd->opt.trait & QSE_HTTPD_CGIERRTONUL) | 	if (httpd->opt.trait & QSE_HTTPD_CGIERRTONUL) | ||||||
| 		pio_options |= QSE_PIO_ERRTONUL; | 		pio_options |= QSE_PIO_ERRTONUL; | ||||||
| 	else | 	else | ||||||
| @ -1446,6 +1508,7 @@ static int task_main_cgi ( | |||||||
|  |  | ||||||
| 		goto oops; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cgi->pio_inited = 1; | 	cgi->pio_inited = 1; | ||||||
|  |  | ||||||
| 	/* set the trigger that the main loop can use this | 	/* set the trigger that the main loop can use this | ||||||
|  | |||||||
| @ -93,12 +93,19 @@ static int task_main_getfseg ( | |||||||
| 	count = MAX_SEND_SIZE; | 	count = MAX_SEND_SIZE; | ||||||
| 	if (count >= ctx->left) count = ctx->left; | 	if (count >= ctx->left) count = ctx->left; | ||||||
|  |  | ||||||
|  | 	httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 	n = httpd->opt.scb.client.sendfile ( | 	n = httpd->opt.scb.client.sendfile ( | ||||||
| 		httpd, client, ctx->handle, &ctx->offset, count); | 		httpd, client, ctx->handle, &ctx->offset, count); | ||||||
| 	if (n <= -1)  | 	if (n <= -1)  | ||||||
| 	{ | 	{ | ||||||
| /* HANDLE EGAIN specially??? */ | /* HANDLE EGAIN specially??? */ | ||||||
| 		return -1; /* TODO: any logging */ | 		if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
|  | 		{ | ||||||
|  | 			/* TODO: logging */ | ||||||
|  | 			return -1;  | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		goto more_work; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (n == 0 && count > 0) | 	if (n == 0 && count > 0) | ||||||
| @ -114,6 +121,7 @@ static int task_main_getfseg ( | |||||||
| 	ctx->left -= n; | 	ctx->left -= n; | ||||||
| 	if (ctx->left <= 0) return 0; | 	if (ctx->left <= 0) return 0; | ||||||
|  |  | ||||||
|  | more_work: | ||||||
| 	return 1; /* more work to do */ | 	return 1; /* more work to do */ | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -658,8 +658,7 @@ static qse_htrd_recbs_t proxy_peer_htrd_cbs = | |||||||
| 	proxy_htrd_handle_peer_output | 	proxy_htrd_handle_peer_output | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void proxy_forward_client_input_to_peer ( | static void proxy_forward_client_input_to_peer (qse_httpd_t* httpd, qse_httpd_task_t* task) | ||||||
| 	qse_httpd_t* httpd, qse_httpd_task_t* task, int writable) |  | ||||||
| { | { | ||||||
| 	task_proxy_t* proxy = (task_proxy_t*)task->ctx; | 	task_proxy_t* proxy = (task_proxy_t*)task->ctx; | ||||||
|  |  | ||||||
| @ -680,41 +679,21 @@ static void proxy_forward_client_input_to_peer ( | |||||||
| 			/* normal forwarding */ | 			/* normal forwarding */ | ||||||
| 			qse_ssize_t n; | 			qse_ssize_t n; | ||||||
|  |  | ||||||
| 			if (writable) goto forward; |  | ||||||
|  |  | ||||||
| 			n = httpd->opt.scb.mux.writable (httpd, proxy->peer.handle, 0); |  | ||||||
| #if 0 |  | ||||||
| if (n == 0) qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@NOT WRITABLE\n")); |  | ||||||
| #endif |  | ||||||
| 			if (n >= 1) |  | ||||||
| 			{ |  | ||||||
| 			forward: |  | ||||||
| 				/* writable */ |  | ||||||
| #if 0 | #if 0 | ||||||
| qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), | qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), | ||||||
| 	(int)QSE_MBS_LEN(proxy->reqfwdbuf), | 	(int)QSE_MBS_LEN(proxy->reqfwdbuf), | ||||||
| 	QSE_MBS_PTR(proxy->reqfwdbuf)); | 	QSE_MBS_PTR(proxy->reqfwdbuf)); | ||||||
| #endif | #endif | ||||||
|  | 			httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 			n = httpd->opt.scb.peer.send ( | 			n = httpd->opt.scb.peer.send ( | ||||||
| 				httpd, &proxy->peer, | 				httpd, &proxy->peer, | ||||||
| 				QSE_MBS_PTR(proxy->reqfwdbuf), | 				QSE_MBS_PTR(proxy->reqfwdbuf), | ||||||
| 				QSE_MBS_LEN(proxy->reqfwdbuf) | 				QSE_MBS_LEN(proxy->reqfwdbuf) | ||||||
| 			); | 			); | ||||||
|  |  | ||||||
| /* TODO: improve performance.. instead of copying the remaing part  |  | ||||||
| to the head all the time..  grow the buffer to a certain limit. */ |  | ||||||
| 				if (n > 0)  |  | ||||||
| 				{ |  | ||||||
| 					qse_mbs_del (proxy->reqfwdbuf, 0, n); |  | ||||||
| 					if (QSE_MBS_LEN(proxy->reqfwdbuf) <= 0) |  | ||||||
| 					{ |  | ||||||
| 						if (proxy->req == QSE_NULL) goto done; |  | ||||||
| 						else task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (n <= -1) | 			if (n <= -1) | ||||||
|  | 			{ | ||||||
|  | 				if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 				{ | 				{ | ||||||
| 					if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 					if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 						log_proxy_error (proxy, "proxy send-to-peer error - "); | 						log_proxy_error (proxy, "proxy send-to-peer error - "); | ||||||
| @ -732,6 +711,18 @@ to the head all the time..  grow the buffer to a certain limit. */ | |||||||
| 					task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; /* peer */ | 					task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; /* peer */ | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 			else if (n > 0)  | ||||||
|  | 			{ | ||||||
|  | /* TODO: improve performance.. instead of copying the remaing part  | ||||||
|  | to the head all the time..  grow the buffer to a certain limit. */ | ||||||
|  | 				qse_mbs_del (proxy->reqfwdbuf, 0, n); | ||||||
|  | 				if (QSE_MBS_LEN(proxy->reqfwdbuf) <= 0) | ||||||
|  | 				{ | ||||||
|  | 					if (proxy->req == QSE_NULL) goto done; | ||||||
|  | 					else task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	else if (proxy->req == QSE_NULL) | 	else if (proxy->req == QSE_NULL) | ||||||
| 	{ | 	{ | ||||||
| @ -1038,6 +1029,7 @@ printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| 		/* if the client side is readable */ | 		/* if the client side is readable */ | ||||||
| @ -1048,23 +1040,30 @@ printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 		/* if the peer side is writable while the client side is not readable*/ | 		/* if the peer side is writable while the client side is not readable*/ | ||||||
| 		proxy_forward_client_input_to_peer (httpd, task, 1); | 		proxy_forward_client_input_to_peer (httpd, task, 1); | ||||||
| 	} | 	} | ||||||
|  | #endif | ||||||
|  | 	proxy_forward_client_input_to_peer (httpd, task); | ||||||
|  |  | ||||||
| 	if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ | 	if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ proxy->buflen > 0) | ||||||
| 	    (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) |  | ||||||
| 	{ |  | ||||||
| 		if (proxy->buflen > 0) |  | ||||||
| 	{ | 	{ | ||||||
|  | 		/* wrote to the client socket as long as there's something to | ||||||
|  | 		 * write. it's safe to do so as the socket is non-blocking.  | ||||||
|  | 		 * i commented out the check in the 'if' condition above */ | ||||||
|  |  | ||||||
| 		/* TODO: check if proxy outputs more than content-length if it is set... */ | 		/* TODO: check if proxy outputs more than content-length if it is set... */ | ||||||
|  | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); | 		n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); | ||||||
| 		if (n <= -1) | 		if (n <= -1) | ||||||
|  | 		{ | ||||||
|  | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				/* can't return internal server error any more... */ | 				/* can't return internal server error any more... */ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); | 					log_proxy_error (proxy, "proxy send-to-client error - "); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  | 		else if (n > 0) | ||||||
|  | 		{ | ||||||
| 			QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); | 			QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); | ||||||
| 			proxy->buflen -= n; | 			proxy->buflen -= n; | ||||||
| 		} | 		} | ||||||
| @ -1087,6 +1086,8 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	proxy_forward_client_input_to_peer (httpd, task); | ||||||
|  | /* | ||||||
| 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| 		proxy_forward_client_input_to_peer (httpd, task, 0); | 		proxy_forward_client_input_to_peer (httpd, task, 0); | ||||||
| @ -1095,15 +1096,14 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 	{ | 	{ | ||||||
| 		proxy_forward_client_input_to_peer (httpd, task, 1); | 		proxy_forward_client_input_to_peer (httpd, task, 1); | ||||||
| 	} | 	} | ||||||
|  | */ | ||||||
|  |  | ||||||
| 	if (task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if ((task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) && | ||||||
|  | 	    proxy->buflen < QSE_SIZEOF(proxy->buf)) | ||||||
| 	{ | 	{ | ||||||
| 		qse_ssize_t n; | 		qse_ssize_t n; | ||||||
|  |  | ||||||
| 		if (proxy->buflen < QSE_SIZEOF(proxy->buf)) |  | ||||||
| 		{ |  | ||||||
| 		/* reading from the peer */ | 		/* reading from the peer */ | ||||||
|  |  | ||||||
| 		httpd->errnum = QSE_HTTPD_ENOERR; | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.peer.recv ( | 		n = httpd->opt.scb.peer.recv ( | ||||||
| 			httpd, &proxy->peer, | 			httpd, &proxy->peer, | ||||||
| @ -1113,11 +1113,16 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 		if (n <= -1) | 		if (n <= -1) | ||||||
| 		{ | 		{ | ||||||
| 			/* can't return internal server error any more... */ | 			/* can't return internal server error any more... */ | ||||||
|  | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
|  | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_proxy_error (proxy, "proxy recv-from-peer error - "); | 					log_proxy_error (proxy, "proxy recv-from-peer error - "); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 			if (n == 0) |  | ||||||
|  | 			/* carry on as if recv was't called at all */ | ||||||
|  | 		} | ||||||
|  | 		else if (n == 0) | ||||||
| 		{ | 		{ | ||||||
| 			/* peer closed connection */ | 			/* peer closed connection */ | ||||||
| 			if (proxy->resflags & PROXY_RES_PEER_LENGTH)  | 			if (proxy->resflags & PROXY_RES_PEER_LENGTH)  | ||||||
| @ -1152,7 +1157,8 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
|  |  | ||||||
| 			return 1; | 			return 1; | ||||||
| 		} | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
| 			proxy->buflen += n; | 			proxy->buflen += n; | ||||||
| 			proxy->peer_output_received += n; | 			proxy->peer_output_received += n; | ||||||
| 	 | 	 | ||||||
| @ -1177,22 +1183,34 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (proxy->buflen) | ||||||
|  | 	{ | ||||||
| 		/* the main loop invokes the task function only if the client  | 		/* the main loop invokes the task function only if the client  | ||||||
| 		 * side is writable. it should be safe to write whenever | 		 * side is writable. it should be safe to write whenever | ||||||
| 		 * this task function is called. */ | 		 * this task function is called. even if it's not writable, | ||||||
|  | 		 * it should still be ok as the client socket is non-blocking. */ | ||||||
|  | 		qse_ssize_t n; | ||||||
|  |  | ||||||
|  | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); | 		n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); | ||||||
| 		if (n <= -1) | 		if (n <= -1) | ||||||
|  | 		{ | ||||||
|  | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				/* can't return internal server error any more... */ | 				/* can't return internal server error any more... */ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT) | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); | 					log_proxy_error (proxy, "proxy send-to-client error - "); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 	 | 		} | ||||||
|  | 		else if (n > 0) | ||||||
|  | 		{ | ||||||
| 			QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); | 			QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); | ||||||
| 			proxy->buflen -= n; | 			proxy->buflen -= n; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| @ -1212,6 +1230,8 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg | |||||||
| 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	proxy_forward_client_input_to_peer (httpd, task); | ||||||
|  | /* | ||||||
| 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| 		proxy_forward_client_input_to_peer (httpd, task, 0); | 		proxy_forward_client_input_to_peer (httpd, task, 0); | ||||||
| @ -1220,34 +1240,41 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg | |||||||
| 	{ | 	{ | ||||||
| 		proxy_forward_client_input_to_peer (httpd, task, 1); | 		proxy_forward_client_input_to_peer (httpd, task, 1); | ||||||
| 	} | 	} | ||||||
|  | */ | ||||||
|  |  | ||||||
| 	if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ | 	if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) &&*/ proxy->res_pending > 0) | ||||||
| 	    (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) |  | ||||||
| 	{ | 	{ | ||||||
|  | 		/* the client socket is non-blocking. so attempt to send | ||||||
|  | 		 * so long as there's something to send regardless of writability  | ||||||
|  | 		 * of the client socket. see the check commented out in the 'if' | ||||||
|  | 		 * condition above.*/ | ||||||
|  |  | ||||||
| 		qse_ssize_t n; | 		qse_ssize_t n; | ||||||
| 		qse_size_t count; | 		qse_size_t count; | ||||||
|  |  | ||||||
| 		count = proxy->res_pending; | 		count = proxy->res_pending; | ||||||
| 		if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; | 		if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; | ||||||
|  |  | ||||||
| 		if (count > 0) | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		{ |  | ||||||
| 		n = httpd->opt.scb.client.send ( | 		n = httpd->opt.scb.client.send ( | ||||||
| 			httpd, client,  | 			httpd, client,  | ||||||
| 			&QSE_MBS_CHAR(proxy->res,proxy->res_consumed),  | 			&QSE_MBS_CHAR(proxy->res,proxy->res_consumed),  | ||||||
| 			count | 			count | ||||||
| 		); | 		); | ||||||
| 		if (n <= -1)  | 		if (n <= -1)  | ||||||
|  | 		{ | ||||||
|  | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); | 					log_proxy_error (proxy, "proxy send-to-client error - "); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  | 		else if (n > 0) | ||||||
|  | 		{ | ||||||
| 			proxy->resflags |= PROXY_RES_EVER_SENTBACK; | 			proxy->resflags |= PROXY_RES_EVER_SENTBACK; | ||||||
| 			proxy->res_consumed += n; | 			proxy->res_consumed += n; | ||||||
| 			proxy->res_pending -= n; | 			proxy->res_pending -= n; | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 			if (proxy->res_pending <= 0) | 			if (proxy->res_pending <= 0) | ||||||
| 			{ | 			{ | ||||||
| @ -1276,6 +1303,7 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg | |||||||
| 				return 1; | 				return 1; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return 1; /* more work to do */ | 	return 1; /* more work to do */ | ||||||
| } | } | ||||||
| @ -1291,6 +1319,8 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | 	task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	proxy_forward_client_input_to_peer (httpd, task); | ||||||
|  | #if 0 | ||||||
| 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| 		/* client is readable */ | 		/* client is readable */ | ||||||
| @ -1301,19 +1331,19 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 		/* client is not readable but peer is writable */ | 		/* client is not readable but peer is writable */ | ||||||
| 		proxy_forward_client_input_to_peer (httpd, task, 1); | 		proxy_forward_client_input_to_peer (httpd, task, 1); | ||||||
| 	} | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ | 	if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ proxy->res_pending > 0) | ||||||
| 	    (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) |  | ||||||
| 	{ |  | ||||||
| 		if (proxy->res_pending > 0) |  | ||||||
| 	{ | 	{ | ||||||
| 		/* the 'if' condition becomes true only if '100 Continue' | 		/* the 'if' condition becomes true only if '100 Continue' | ||||||
| 		 * is received without an actual reply in a previous call to  | 		 * is received without an actual reply in a previous call to  | ||||||
| 			 * qse_htrd_feed() below. Since the actual reply is not | 		 * qse_htrd_feed() far below. Since the actual reply is not | ||||||
| 			 * received yet, i just want to read more while realying  | 		 * received yet, i just want to read more while relaying  | ||||||
| 			 * '100 Continue' to the client. this task handler is called | 		 * '100 Continue' to the client.  | ||||||
| 			 * only if the client side handle is writable. i can safely | 		 * | ||||||
| 			 * write to the client without a check. */ | 		 * attempt to write to the client regardless of writability of | ||||||
|  | 		 * the cleint socket as it is non-blocking. see the check commented | ||||||
|  | 		 * in the 'if' condition above. */ | ||||||
|  |  | ||||||
| 		qse_ssize_t n; | 		qse_ssize_t n; | ||||||
| 		qse_size_t count; | 		qse_size_t count; | ||||||
| @ -1324,18 +1354,23 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 		count = proxy->res_pending; | 		count = proxy->res_pending; | ||||||
| 		if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; | 		if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; | ||||||
|  |  | ||||||
|  | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.client.send ( | 		n = httpd->opt.scb.client.send ( | ||||||
| 			httpd, client,  | 			httpd, client,  | ||||||
| 			QSE_MBS_CPTR(proxy->res,proxy->res_consumed),  | 			QSE_MBS_CPTR(proxy->res,proxy->res_consumed),  | ||||||
| 			count | 			count | ||||||
| 		); | 		); | ||||||
| 		if (n <= -1)  | 		if (n <= -1)  | ||||||
|  | 		{ | ||||||
|  | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); | 					log_proxy_error (proxy, "proxy send-to-client error - "); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  | 		else if (n > 0) | ||||||
|  | 		{ | ||||||
| 			proxy->resflags |= PROXY_RES_EVER_SENTBACK; | 			proxy->resflags |= PROXY_RES_EVER_SENTBACK; | ||||||
| 			proxy->res_consumed += n; | 			proxy->res_consumed += n; | ||||||
| 			proxy->res_pending -= n; | 			proxy->res_pending -= n; | ||||||
| @ -1366,17 +1401,20 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 			QSE_SIZEOF(proxy->buf) - proxy->buflen | 			QSE_SIZEOF(proxy->buf) - proxy->buflen | ||||||
| 		); | 		); | ||||||
| 		if (n <= -1) | 		if (n <= -1) | ||||||
|  | 		{ | ||||||
|  | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_proxy_error (proxy, "proxy recv-from-peer error - "); | 					log_proxy_error (proxy, "proxy recv-from-peer error - "); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 		if (n == 0)  | 		} | ||||||
|  | 		else if (n == 0)  | ||||||
| 		{ | 		{ | ||||||
| 			if (!(proxy->resflags & PROXY_RES_RECEIVED_RESHDR)) | 			if (!(proxy->resflags & PROXY_RES_RECEIVED_RESHDR)) | ||||||
| 			{ | 			{ | ||||||
| 				/* end of output from peer before it has seen a header. | 				/* end of output from peer before it has seen a header. | ||||||
| 				 * the proxy peer must be crooked. */ | 				 * the proxy peer must be bad. */ | ||||||
|  |  | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 					log_proxy_error (proxy, "proxy premature eof - "); | 					log_proxy_error (proxy, "proxy premature eof - "); | ||||||
| @ -1405,8 +1443,10 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", | |||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		else  | ||||||
|  | 		{ | ||||||
| 			proxy->buflen += n; | 			proxy->buflen += n; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| #if 0 | #if 0 | ||||||
| qse_printf (QSE_T("#####PROXY FEEDING %d [\n"), (int)proxy->buflen); | qse_printf (QSE_T("#####PROXY FEEDING %d [\n"), (int)proxy->buflen); | ||||||
| @ -1416,7 +1456,8 @@ for (i = 0; i < proxy->buflen; i++) qse_printf (QSE_T("%hc"), proxy->buf[i]); | |||||||
| } | } | ||||||
| qse_printf (QSE_T("]\n")); | qse_printf (QSE_T("]\n")); | ||||||
| #endif | #endif | ||||||
|  | 		if (proxy->buflen > 0) | ||||||
|  | 		{ | ||||||
| 			if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1) | 			if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| @ -1425,6 +1466,7 @@ qse_printf (QSE_T("]\n")); | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			proxy->buflen = 0; | 			proxy->buflen = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (QSE_MBS_LEN(proxy->res) > 0) | 		if (QSE_MBS_LEN(proxy->res) > 0) | ||||||
| 		{ | 		{ | ||||||
| @ -1530,7 +1572,7 @@ static int task_main_proxy_1 ( | |||||||
| 			if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | 			if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | ||||||
| 			{ | 			{ | ||||||
| 				/* forward the initial part of the input to the peer */ | 				/* forward the initial part of the input to the peer */ | ||||||
| 				proxy_forward_client_input_to_peer (httpd, task, 0); | 				proxy_forward_client_input_to_peer (httpd, task); | ||||||
| 				if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | 				if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | ||||||
| 				{ | 				{ | ||||||
| 					/* there are still more to forward in the buffer | 					/* there are still more to forward in the buffer | ||||||
| @ -1697,7 +1739,7 @@ static int task_main_proxy ( | |||||||
|  |  | ||||||
| 		if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | 		if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | ||||||
| 		{ | 		{ | ||||||
| 			proxy_forward_client_input_to_peer (httpd, task, 0); | 			proxy_forward_client_input_to_peer (httpd, task); | ||||||
| 			if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | 			if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) | ||||||
| 			{ | 			{ | ||||||
| 				task->trigger.v[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | 				task->trigger.v[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
|  | |||||||
| @ -135,6 +135,9 @@ static qse_httpd_errnum_t skerr_to_errnum (DWORD e) | |||||||
| 		case WSAEINTR: | 		case WSAEINTR: | ||||||
| 			return QSE_HTTPD_EINTR; | 			return QSE_HTTPD_EINTR; | ||||||
|  |  | ||||||
|  | 		case WASEWOULDBLOCK: | ||||||
|  | 			return QSE_HTTPD_EAGAIN; | ||||||
|  |  | ||||||
| 		case WSAECONNREFUSED: | 		case WSAECONNREFUSED: | ||||||
| 		case WSAENETUNREACH: | 		case WSAENETUNREACH: | ||||||
| 		case WSAEHOSTUNREACH: | 		case WSAEHOSTUNREACH: | ||||||
| @ -180,6 +183,9 @@ static qse_httpd_errnum_t skerr_to_errnum (int e) | |||||||
| 		case SOCEPIPE: | 		case SOCEPIPE: | ||||||
| 			return QSE_HTTPD_EPIPE; | 			return QSE_HTTPD_EPIPE; | ||||||
|  |  | ||||||
|  | 		case SOCEAGAIN: | ||||||
|  | 			return QSE_HTTPD_EAGAIN; | ||||||
|  |  | ||||||
| 		case SOCECONNREFUSED: | 		case SOCECONNREFUSED: | ||||||
| 		case SOCENETUNREACH: | 		case SOCENETUNREACH: | ||||||
| 		case SOCEHOSTUNREACH: | 		case SOCEHOSTUNREACH: | ||||||
| @ -229,6 +235,9 @@ static qse_httpd_errnum_t skerr_to_errnum (int e) | |||||||
| 			return QSE_HTTPD_EPIPE; | 			return QSE_HTTPD_EPIPE; | ||||||
|  |  | ||||||
| 		case EAGAIN: | 		case EAGAIN: | ||||||
|  | #if defined(EWEOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN | ||||||
|  | 		case EWOULDBLOCK: | ||||||
|  | #endif | ||||||
| 			return QSE_HTTPD_EAGAIN; | 			return QSE_HTTPD_EAGAIN; | ||||||
|  |  | ||||||
| #if defined(ECONNREFUSED) || defined(ENETUNREACH) || defined(EHOSTUNREACH) || defined(EHOSTDOWN) | #if defined(ECONNREFUSED) || defined(ENETUNREACH) || defined(EHOSTUNREACH) || defined(EHOSTDOWN) | ||||||
| @ -640,13 +649,86 @@ void* qse_httpd_getxtnstd (qse_httpd_t* httpd) | |||||||
|  |  | ||||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	typedef SOCKET sock_t; | ||||||
|  | #	define SOCK_INIT INVALID_SOCKET | ||||||
|  | #else | ||||||
|  | 	typedef int sock_t; | ||||||
|  | #	define SOCK_INIT -1 | ||||||
|  | #endif | ||||||
|  | #if !defined(HAVE_SOCKLEN_T) | ||||||
|  | 	typedef int socklen_t; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static QSE_INLINE int is_valid_socket (sock_t fd) | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	return fd != INVALID_SOCKET; | ||||||
|  | #else | ||||||
|  | 	return fd >= 0; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static QSE_INLINE void close_socket (sock_t fd) | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	closesocket (fd); | ||||||
|  | #elif defined(__OS2__) | ||||||
|  | 	soclose (fd); | ||||||
|  | #elif defined(__DOS__) | ||||||
|  | 	/* TODO: */ | ||||||
|  | #else | ||||||
|  | 	QSE_CLOSE (fd); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int set_socket_nonblock (qse_httpd_t* httpd, sock_t fd, int enabled) | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	if (ioctlsocket (fd, FIONBIO, &enabled) == SOCKET_ERROR)  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | #elif defined(__OS2__) | ||||||
|  |  | ||||||
|  | 	if (ioctl (fd, FIONBIO, (char*)&enabled, sizeof(enabled)) <= -1)  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | #elif defined(O_NONBLOCK) | ||||||
|  |  | ||||||
|  | 	int flag = fcntl (fd, F_GETFL); | ||||||
|  | 	if (flag >= 0) flag = fcntl (fd, F_SETFL, (enabled? (flag | O_NONBLOCK): (flag & ~O_NONBLOCK))); | ||||||
|  | 	if (flag <= -1) | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 	return -1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
| static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) | static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
| { | { | ||||||
| #if defined(__DOS__) | #if defined(__DOS__) | ||||||
| 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
| 	return -1; | 	return -1; | ||||||
| #else | #else | ||||||
| 	int fd = -1, flag; | 	sock_t fd = SOCK_INIT, flag; | ||||||
| 	qse_skad_t addr; | 	qse_skad_t addr; | ||||||
| 	int addrsize; | 	int addrsize; | ||||||
|  |  | ||||||
| @ -658,7 +740,11 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	fd = socket (qse_skadfamily(&addr), SOCK_STREAM, IPPROTO_TCP); | 	fd = socket (qse_skadfamily(&addr), SOCK_STREAM, IPPROTO_TCP); | ||||||
| 	if (fd <= -1) goto oops; | 	if (!is_valid_socket(fd))  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	#if defined(FD_CLOEXEC) | 	#if defined(FD_CLOEXEC) | ||||||
| 	flag = fcntl (fd, F_GETFD); | 	flag = fcntl (fd, F_GETFD); | ||||||
| @ -720,6 +806,7 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 		if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1) | 		if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1) | ||||||
| 		{ | 		{ | ||||||
| 			/* TODO: logging ... */ | 			/* TODO: logging ... */ | ||||||
|  | 			qse_httpd_seterrnum (httpd, ((len <= 0)? QSE_HTTPD_EINVAL: SKERR_TO_ERRNUM())); | ||||||
| 			goto oops; | 			goto oops; | ||||||
| 		} | 		} | ||||||
| 	#endif | 	#endif | ||||||
| @ -735,50 +822,44 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 		{ | 		{ | ||||||
| 			int on = 1; | 			int on = 1; | ||||||
| 			setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); | 			setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); | ||||||
| 			if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1)  goto oops; | 			if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1)   | ||||||
|  | 			{ | ||||||
|  | 				qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else  | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 			goto oops; | ||||||
| 		} | 		} | ||||||
| 		else goto oops; |  | ||||||
| 	#else | 	#else | ||||||
|  |  | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
| 		goto oops; | 		goto oops; | ||||||
| 	#endif | 	#endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (listen (fd, 10) <= -1) goto oops; | 	if (listen (fd, 10) <= -1)  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	#if defined(O_NONBLOCK) | 	if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; | ||||||
| 	flag = fcntl (fd, F_GETFL); |  | ||||||
| 	if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK); |  | ||||||
| 	#endif |  | ||||||
|  |  | ||||||
| 	server->handle.i = fd; | 	server->handle.i = fd; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 	if (is_valid_socket(fd)) close_socket (fd); | ||||||
| 	#if defined(_WIN32) |  | ||||||
| 	if (fd != INVALID_SOCKET) closesocket (fd); |  | ||||||
| 	#elif defined(__OS2__) |  | ||||||
| 	if (fd >= 0) soclose (fd); |  | ||||||
| 	#elif defined(__DOS__) |  | ||||||
| 		/* TODO: */ |  | ||||||
| 	#else |  | ||||||
| 	if (fd >= 0) QSE_CLOSE (fd); |  | ||||||
| 	#endif |  | ||||||
| 	return -1; | 	return -1; | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server) | static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
| { | { | ||||||
| #if defined(_WIN32) | 	close_socket (server->handle.i); | ||||||
| 	closesocket (server->handle.i); |  | ||||||
| #elif defined(__OS2__) |  | ||||||
| 	soclose (server->handle.i); |  | ||||||
| #elif defined(__DOS__) |  | ||||||
| 	/* TODO: */ |  | ||||||
| #else |  | ||||||
| 	QSE_CLOSE (server->handle.i); |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int server_accept ( | static int server_accept ( | ||||||
| @ -790,29 +871,25 @@ static int server_accept ( | |||||||
|  |  | ||||||
| #else | #else | ||||||
| 	qse_skad_t addr; | 	qse_skad_t addr; | ||||||
|  |  | ||||||
| 	#if defined(HAVE_SOCKLEN_T) |  | ||||||
| 	socklen_t addrlen; | 	socklen_t addrlen; | ||||||
| 	#else | 	sock_t fd = SOCK_INIT; | ||||||
| 	int addrlen; | 	int flag; | ||||||
| 	#endif |  | ||||||
| 	int fd, flag; |  | ||||||
|  |  | ||||||
| 	addrlen = QSE_SIZEOF(addr); | 	addrlen = QSE_SIZEOF(addr); | ||||||
| 	fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen); | 	fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen); | ||||||
| 	if (fd <= -1) | 	if (!is_valid_socket(fd))  | ||||||
| 	{ | 	{ | ||||||
| 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
| 		return -1; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	#if 0 | 	#if 0 | ||||||
|  | /* TODO: implement maximum number of client per server??? */ | ||||||
| 	if (fd >= FD_SETSIZE) | 	if (fd >= FD_SETSIZE) | ||||||
| 	{ | 	{ | ||||||
| qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); | qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); | ||||||
| 		/*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/ | 		/*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/ | ||||||
| 		QSE_CLOSE (fd); | 		goto oops; | ||||||
| 		return -1; |  | ||||||
| 	} | 	} | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| @ -821,10 +898,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); | |||||||
| 	if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); | 	if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| 	#if defined(O_NONBLOCK) | 	if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; | ||||||
| 	flag = fcntl (fd, F_GETFL); |  | ||||||
| 	if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK); |  | ||||||
| 	#endif |  | ||||||
|  |  | ||||||
| 	if (qse_skadtonwad (&addr, &client->remote_addr) <= -1) | 	if (qse_skadtonwad (&addr, &client->remote_addr) <= -1) | ||||||
| 	{ | 	{ | ||||||
| @ -867,6 +941,10 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); | |||||||
|  |  | ||||||
| 	client->handle.i = fd; | 	client->handle.i = fd; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | oops: | ||||||
|  | 	if (is_valid_socket(fd)) close_socket (fd); | ||||||
|  | 	return -1; | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -885,17 +963,14 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
| 	qse_skad_t connaddr, bindaddr; | 	qse_skad_t connaddr, bindaddr; | ||||||
| 	int connaddrsize, bindaddrsize; | 	int connaddrsize, bindaddrsize; | ||||||
| 	int connected = 1; | 	int connected = 1; | ||||||
|  | 	sock_t fd = SOCK_INIT; | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| 	SOCKET fd = -1;  |  | ||||||
| 	unsigned long cmd; | 	unsigned long cmd; | ||||||
| #elif defined(__OS2__) | #elif defined(__OS2__) | ||||||
| 	int fd = -1;  |  | ||||||
| 	int cmd; | 	int cmd; | ||||||
| #elif defined(__DOS__) | #elif defined(__DOS__) | ||||||
| 	int fd = -1;  |  | ||||||
| 	int flag; | 	int flag; | ||||||
| #else | #else | ||||||
| 	int fd = -1;  |  | ||||||
| 	int flag; | 	int flag; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @ -908,7 +983,11 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	fd = socket (qse_skadfamily(&connaddr), SOCK_STREAM, IPPROTO_TCP); | 	fd = socket (qse_skadfamily(&connaddr), SOCK_STREAM, IPPROTO_TCP); | ||||||
| 	if (fd <= -1) goto oops; | 	if (!is_valid_socket(fd))  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	#if defined(IP_TRANSPARENT) | 	#if defined(IP_TRANSPARENT) | ||||||
| 	flag = 1; | 	flag = 1; | ||||||
| @ -921,72 +1000,58 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
| 		/* TODO: some logging for this failure though */ | 		/* TODO: some logging for this failure though */ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #if defined(_WIN32) |  | ||||||
| 	cmd = 1; |  | ||||||
| 	if (ioctlsocket(fd, FIONBIO, &cmd) == SOCKET_ERROR) goto oops; |  | ||||||
|  |  | ||||||
| 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) |  | ||||||
| 	{ |  | ||||||
| 		if (WSAGetLastError() != WSAEWOULDBLOCK) goto oops; |  | ||||||
| 		connected = 0; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cmd = 0; |  | ||||||
| 	if (ioctlsocket(fd, FIONBIO, &cmd) == SOCKET_ERROR) goto oops; |  | ||||||
|  |  | ||||||
| #elif defined(__OS2__) |  | ||||||
|  |  | ||||||
| 	cmd = 1; |  | ||||||
| 	if (ioctl(fd, FIONBIO, (char*)&cmd, QSE_SIZEOF(cmd)) == -1) goto oops; |  | ||||||
|  |  | ||||||
| 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) == -1) |  | ||||||
| 	{ |  | ||||||
| 		if (sock_errno() != SOCEINPROGRESS) goto oops; |  | ||||||
| 		connected = 0; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cmd = 0; |  | ||||||
| 	if (ioctl(fd, FIONBIO, (char*)&cmd, QSE_SIZEOF(cmd)) == -1) goto oops; |  | ||||||
|  |  | ||||||
| #elif defined(__DOS__) |  | ||||||
|  |  | ||||||
| 	/* TODO: */ |  | ||||||
|  |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| 	#if defined(FD_CLOEXEC) | 	#if defined(FD_CLOEXEC) | ||||||
| 	flag = fcntl (fd, F_GETFD); | 	flag = fcntl (fd, F_GETFD); | ||||||
| 	if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); | 	if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| 	flag = fcntl (fd, F_GETFL); | 	if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; | ||||||
| 	if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK); |  | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) | ||||||
| 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) | 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) | ||||||
| 	{ | 	{ | ||||||
| 		if (errno != EINPROGRESS) goto oops; | 		if (WSAGetLastError() != WSAEWOULDBLOCK)  | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
| 		connected = 0; | 		connected = 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* restore flags */ | #elif defined(__OS2__) | ||||||
| 	if (fcntl (fd, F_SETFL, flag) <= -1) goto oops; | 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) == -1) | ||||||
|  | 	{ | ||||||
|  | 		if (sock_errno() != SOCEINPROGRESS)  | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
|  | 		connected = 0; | ||||||
|  | 	} | ||||||
|  | #elif defined(__DOS__) | ||||||
|  |  | ||||||
|  | 	/* TODO: */ | ||||||
|  |  | ||||||
|  | #else | ||||||
|  | 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) | ||||||
|  | 	{ | ||||||
|  | 		if (errno != EINPROGRESS)  | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
|  | 		connected = 0; | ||||||
|  | 	} | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	/*if (set_socket_nonblock (httpd, fd, 0) <= -1) goto oops;*/ | ||||||
|  |  | ||||||
| 	peer->handle.i = fd; | 	peer->handle.i = fd; | ||||||
| 	return connected; | 	return connected; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 	qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
| #if defined(_WIN32) | 	if (is_valid_socket(fd)) close_socket (fd); | ||||||
| 	if (fd != INVALID_SOCKET) closesocket (fd); |  | ||||||
| #elif defined(__OS2__) |  | ||||||
| 	if (fd >= 0) soclose (fd); |  | ||||||
| #elif defined(__DOS__) |  | ||||||
| 	/* TODO: */ |  | ||||||
| #else |  | ||||||
| 	if (fd >= 0) QSE_CLOSE (fd); |  | ||||||
| #endif |  | ||||||
| 	return -1; | 	return -1; | ||||||
|  |  | ||||||
| 	/* -------------------------------------------------------------------- */ | 	/* -------------------------------------------------------------------- */ | ||||||
| @ -995,15 +1060,7 @@ oops: | |||||||
|  |  | ||||||
| static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | ||||||
| { | { | ||||||
| #if defined(_WIN32) | 	close_socket (peer->handle.i); | ||||||
| 	closesocket (peer->handle.i); |  | ||||||
| #elif defined(__OS2__) |  | ||||||
| 	soclose (peer->handle.i); |  | ||||||
| #elif defined(__DOS__) |  | ||||||
| 	/* TODO: */ |  | ||||||
| #else |  | ||||||
| 	QSE_CLOSE (peer->handle.i); |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | ||||||
| @ -1057,11 +1114,7 @@ static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| 	#if defined(HAVE_SOCKLEN_T) |  | ||||||
| 	socklen_t len; | 	socklen_t len; | ||||||
| 	#else |  | ||||||
| 	int len; |  | ||||||
| 	#endif |  | ||||||
| 	int ret; | 	int ret; | ||||||
|  |  | ||||||
| 	len = QSE_SIZEOF(ret); | 	len = QSE_SIZEOF(ret); | ||||||
| @ -1747,26 +1800,22 @@ static int dir_read (qse_httpd_t* httpd, qse_ubi_t handle, qse_httpd_dirent_t* d | |||||||
| #	define SHUT_RDWR 2 | #	define SHUT_RDWR 2 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| static void client_close ( | static void client_close (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { | { | ||||||
|  |  | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| 	shutdown (client->handle.i, SHUT_RDWR); | 	shutdown (client->handle.i, SHUT_RDWR); | ||||||
| 	closesocket (client->handle.i); |  | ||||||
| #elif defined(__OS2__) | #elif defined(__OS2__) | ||||||
| 	shutdown (client->handle.i, SHUT_RDWR); | 	shutdown (client->handle.i, SHUT_RDWR); | ||||||
| 	soclose (client->handle.i); |  | ||||||
| #elif defined(__DOS__) | #elif defined(__DOS__) | ||||||
| 	/* TODO: */ | 	/* TODO: */ | ||||||
| #else | #else | ||||||
| 	shutdown (client->handle.i, SHUT_RDWR); | 	shutdown (client->handle.i, SHUT_RDWR); | ||||||
| 	QSE_CLOSE (client->handle.i); |  | ||||||
| #endif | #endif | ||||||
|  | 	close_socket (client->handle.i); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void client_shutdown ( | static void client_shutdown (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { | { | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| 	shutdown (client->handle.i, SHUT_RDWR); | 	shutdown (client->handle.i, SHUT_RDWR); | ||||||
| @ -2201,7 +2250,8 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | |||||||
| 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
| 	return -1; | 	return -1; | ||||||
| #else | #else | ||||||
| 	int fd = -1, flag; | 	sock_t fd = SOCK_INIT;  | ||||||
|  | 	int flag; | ||||||
| 	qse_nwad_t nwad; | 	qse_nwad_t nwad; | ||||||
| 	dns_ctx_t* dc; | 	dns_ctx_t* dc; | ||||||
| 	httpd_xtn_t* httpd_xtn; | 	httpd_xtn_t* httpd_xtn; | ||||||
| @ -2276,7 +2326,11 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	fd = socket (qse_skadfamily(&dc->skad), SOCK_DGRAM, IPPROTO_UDP); | 	fd = socket (qse_skadfamily(&dc->skad), SOCK_DGRAM, IPPROTO_UDP); | ||||||
| 	if (fd <= -1) goto oops; | 	if (!is_valid_socket(fd))  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	#if defined(FD_CLOEXEC) | 	#if defined(FD_CLOEXEC) | ||||||
| 	flag = fcntl (fd, F_GETFD); | 	flag = fcntl (fd, F_GETFD); | ||||||
| @ -2293,22 +2347,14 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | |||||||
| 	setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void*)&flag, QSE_SIZEOF(flag)); | 	setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void*)&flag, QSE_SIZEOF(flag)); | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
|  | 	if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; | ||||||
|  | 	 | ||||||
| 	dns->handle.i = fd; | 	dns->handle.i = fd; | ||||||
| 	dns->ctx = dc; | 	dns->ctx = dc; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	if (fd >= 0)  | 	if (is_valid_socket(fd)) close_socket (fd); | ||||||
| 	{ |  | ||||||
| 	#if defined(_WIN32) |  | ||||||
| 		closesocket (fd); |  | ||||||
| 	#elif defined(__OS2__) |  | ||||||
| 		soclose (fd); |  | ||||||
| 	#else |  | ||||||
| 		QSE_CLOSE (fd); |  | ||||||
| 	#endif |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (dc) qse_httpd_freemem (httpd, dc); | 	if (dc) qse_httpd_freemem (httpd, dc); | ||||||
| 	return -1; | 	return -1; | ||||||
|  |  | ||||||
| @ -2447,7 +2493,7 @@ static int dns_recv (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | |||||||
| 	dns_ctx_t* dc = (dns_ctx_t*)dns->ctx; | 	dns_ctx_t* dc = (dns_ctx_t*)dns->ctx; | ||||||
|  |  | ||||||
| 	qse_skad_t fromaddr; | 	qse_skad_t fromaddr; | ||||||
| 	socklen_t fromlen; /* TODO: change type */ | 	socklen_t fromlen; | ||||||
|  |  | ||||||
| 	qse_uint8_t buf[DNS_MAX_MSG_LEN]; | 	qse_uint8_t buf[DNS_MAX_MSG_LEN]; | ||||||
| 	qse_ssize_t len; | 	qse_ssize_t len; | ||||||
| @ -2614,16 +2660,13 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t | |||||||
| 	qse_size_t name_len; | 	qse_size_t name_len; | ||||||
| 	dns_ans_t* ans; | 	dns_ans_t* ans; | ||||||
|  |  | ||||||
| printf ("finding answer in cache...\n"); |  | ||||||
| 	ans = dns_get_answer_from_cache (dc, name); | 	ans = dns_get_answer_from_cache (dc, name); | ||||||
| 	if (ans) | 	if (ans) | ||||||
| 	{ | 	{ | ||||||
| printf ("found answer in cache...\n"); |  | ||||||
| 		resol (httpd, name, ((ans->nwad.type == QSE_NWAD_NX)? QSE_NULL: &ans->nwad), ctx); | 		resol (httpd, name, ((ans->nwad.type == QSE_NWAD_NX)? QSE_NULL: &ans->nwad), ctx); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| printf ("found XXXXX in cache...\n"); |  | ||||||
| 	seq = dc->seq; | 	seq = dc->seq; | ||||||
| 	seq = (seq + 1) % QSE_COUNTOF(dc->reqs); | 	seq = (seq + 1) % QSE_COUNTOF(dc->reqs); | ||||||
| 	dc->seq = seq; | 	dc->seq = seq; | ||||||
|  | |||||||
| @ -90,13 +90,19 @@ static int task_main_format ( | |||||||
| 	count = MAX_SEND_SIZE; | 	count = MAX_SEND_SIZE; | ||||||
| 	if (count >= ctx->left) count = ctx->left; | 	if (count >= ctx->left) count = ctx->left; | ||||||
|  |  | ||||||
|  | 	httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 	n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count); | 	n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count); | ||||||
| 	if (n <= -1) return -1; | 	if (n <= -1)  | ||||||
|  | 	{ | ||||||
|  | 		if (httpd->errnum != QSE_HTTPD_EAGAIN) return -1; | ||||||
|  | 	} | ||||||
|  | 	else if (n > 0) | ||||||
|  | 	{ | ||||||
| 		ctx->left -= n; | 		ctx->left -= n; | ||||||
| 		if (ctx->left <= 0) return 0; | 		if (ctx->left <= 0) return 0; | ||||||
|  |  | ||||||
| 		ctx->ptr += n; | 		ctx->ptr += n; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return 1; /* more work to do */ | 	return 1; /* more work to do */ | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -53,13 +53,18 @@ static int task_main_text ( | |||||||
| 	if (count >= ctx->left) count = ctx->left; | 	if (count >= ctx->left) count = ctx->left; | ||||||
|  |  | ||||||
| /* TODO: do i need to add code to skip this send if count is 0? */ | /* TODO: do i need to add code to skip this send if count is 0? */ | ||||||
|  | 	httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 	n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count); | 	n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count); | ||||||
| 	if (n <= -1) return -1; | 	if (n <= -1)  | ||||||
|  | 	{ | ||||||
|  | 		if (httpd->errnum != QSE_HTTPD_EAGAIN) return -1; | ||||||
|  | 	} | ||||||
|  | 	else if (n > 0) | ||||||
|  | 	{ | ||||||
| 		ctx->left -= n; | 		ctx->left -= n; | ||||||
| 		if (ctx->left <= 0) return 0; | 		if (ctx->left <= 0) return 0; | ||||||
|  |  | ||||||
| 		ctx->ptr += n; | 		ctx->ptr += n; | ||||||
|  | 	} | ||||||
| 	return 1; /* more work to do */ | 	return 1; /* more work to do */ | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -921,7 +921,7 @@ static int update_mux_for_current_task (qse_httpd_t* httpd, qse_httpd_client_t* | |||||||
| 			{ | 			{ | ||||||
| 				/* active to inactive */ | 				/* active to inactive */ | ||||||
|  |  | ||||||
| printf ("ACTIVE TO INACTIVE....\n"); | /*printf ("ACTIVE TO INACTIVE....\n");*/ | ||||||
| 				for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++) | 				for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++) | ||||||
| 				{ | 				{ | ||||||
| 					if (client->status & CLIENT_TASK_TRIGGER_RW_IN_MUX(i)) | 					if (client->status & CLIENT_TASK_TRIGGER_RW_IN_MUX(i)) | ||||||
| @ -942,21 +942,21 @@ printf ("ACTIVE TO INACTIVE....\n"); | |||||||
| 				return 0; | 				return 0; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| printf ("INACTIVE TO ACTIVE....\n"); | /*printf ("INACTIVE TO ACTIVE....\n");*/ | ||||||
| 			/* inactive to active . go on*/ | 			/* inactive to active . go on*/ | ||||||
| 		} | 		} | ||||||
| 		else  | 		else  | ||||||
| 		{ | 		{ | ||||||
| 			if (task->trigger.flags & QSE_HTTPD_TASK_TRIGGER_INACTIVE) | 			if (task->trigger.flags & QSE_HTTPD_TASK_TRIGGER_INACTIVE) | ||||||
| 			{ | 			{ | ||||||
| printf ("INACTIVE TO INACTIVE....\n"); | /*printf ("INACTIVE TO INACTIVE....\n");*/ | ||||||
| 				/* inactive to inactive. | 				/* inactive to inactive. | ||||||
| 				 * save the trigger as the trigger handle and masks could change */ | 				 * save the trigger as the trigger handle and masks could change */ | ||||||
| 				client->trigger = task->trigger; | 				client->trigger = task->trigger; | ||||||
| 				return 0; | 				return 0; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| printf ("ACTIVE TO ACTIVE....\n"); | /*printf ("ACTIVE TO ACTIVE....\n");*/ | ||||||
| 			/* active to active. go on */ | 			/* active to active. go on */ | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -1183,13 +1183,23 @@ static int invoke_client_task ( | |||||||
| 			{ | 			{ | ||||||
| 				if (mask & QSE_HTTPD_MUX_READ) | 				if (mask & QSE_HTTPD_MUX_READ) | ||||||
| 				{ | 				{ | ||||||
| 					QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_READ); | 					/*QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_READ);*/ | ||||||
|  | 					/* the assertion above may be false if a task for the same  | ||||||
|  | 					 * trigger set was called earlier by a qse_mux_poll() call. | ||||||
|  | 					 * and the task has changed some masks. | ||||||
|  | 					 * | ||||||
|  | 					 * for instance, you put handle A and B in to a trigger. | ||||||
|  | 					 * if the task is triggered for A but the task may change | ||||||
|  | 					 * the mask for B. the task may get executed for B by  | ||||||
|  | 					 * the same qse_mux_poll() call.  | ||||||
|  | 					 */ | ||||||
|  |  | ||||||
| 					task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_READABLE; | 					task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_READABLE; | ||||||
| 					trigger_fired = 1; | 					trigger_fired = 1; | ||||||
| 				} | 				} | ||||||
| 				if (mask & QSE_HTTPD_MUX_WRITE) | 				if (mask & QSE_HTTPD_MUX_WRITE) | ||||||
| 				{ | 				{ | ||||||
| 					QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE); | 					/*QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE);*/ | ||||||
| 					task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE; | 					task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE; | ||||||
| 					trigger_fired = 1; | 					trigger_fired = 1; | ||||||
| 				} | 				} | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user