added mio_sys_getrealtime()
writing http server
This commit is contained in:
		@ -1236,6 +1236,7 @@ static int fmt_outv (mio_fmtout_t* fmtout, va_list ap)
 | 
			
		||||
				PUT_OOCH (fmtout, padc, width);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			
 | 
			
		||||
			while (*nbufp) PUT_OOCH (fmtout, *nbufp--, 1); /* output actual digits */
 | 
			
		||||
 | 
			
		||||
			if ((flagc & FLAGC_LEFTADJ) && width > 0 && (width -= tmp) > 0)
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,13 @@ void mio_htre_fini (mio_htre_t* re)
 | 
			
		||||
	mio_htb_fini (&re->trailers);
 | 
			
		||||
	mio_htb_fini (&re->hdrtab);
 | 
			
		||||
 | 
			
		||||
	if (re->orgqpath.buf) mio_freemem (re->mio, re->orgqpath.buf);
 | 
			
		||||
	if (re->orgqpath.buf) 
 | 
			
		||||
	{
 | 
			
		||||
		mio_freemem (re->mio, re->orgqpath.buf);
 | 
			
		||||
		re->orgqpath.buf = MIO_NULL;
 | 
			
		||||
		re->orgqpath.len = 0;
 | 
			
		||||
		re->orgqpath.capa = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mio_htre_clear (mio_htre_t* re)
 | 
			
		||||
@ -103,8 +109,13 @@ void mio_htre_clear (mio_htre_t* re)
 | 
			
		||||
	re->state = 0;
 | 
			
		||||
	re->flags = 0;
 | 
			
		||||
 | 
			
		||||
	re->orgqpath.ptr = MIO_NULL;
 | 
			
		||||
	re->orgqpath.len = 0;
 | 
			
		||||
	if (re->orgqpath.buf) 
 | 
			
		||||
	{
 | 
			
		||||
		mio_freemem (re->mio, re->orgqpath.buf);
 | 
			
		||||
		re->orgqpath.buf = MIO_NULL;
 | 
			
		||||
		re->orgqpath.len = 0;
 | 
			
		||||
		re->orgqpath.capa = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MIO_MEMSET (&re->version, 0, MIO_SIZEOF(re->version));
 | 
			
		||||
	MIO_MEMSET (&re->attr, 0, MIO_SIZEOF(re->attr));
 | 
			
		||||
@ -282,6 +293,7 @@ int mio_htre_perdecqpath (mio_htre_t* re)
 | 
			
		||||
			if (re->orgqpath.buf)
 | 
			
		||||
			{
 | 
			
		||||
				mio_freemem (re->mio, re->orgqpath.buf);
 | 
			
		||||
				re->orgqpath.len = 0;
 | 
			
		||||
				re->orgqpath.capa = 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -298,7 +310,7 @@ int mio_htre_perdecqpath (mio_htre_t* re)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	re->u.q.path.len = mio_perdechttpstr (re->u.q.path.ptr, re->u.q.path.ptr, &dec_count);
 | 
			
		||||
	re->u.q.path.len = mio_perdec_http_bcstr(re->u.q.path.ptr, re->u.q.path.ptr, &dec_count);
 | 
			
		||||
	if (dec_count > 0) 
 | 
			
		||||
	{
 | 
			
		||||
		/* this assertion is to ensure that mio_is_perenced_http_bstr() 
 | 
			
		||||
 | 
			
		||||
@ -14,10 +14,22 @@ struct mio_svc_httc_t
 | 
			
		||||
	MIO_SVC_HEADER;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct mio_htts_client_t
 | 
			
		||||
{
 | 
			
		||||
	mio_skad_t remote_addr;
 | 
			
		||||
	mio_skad_t local_addr;
 | 
			
		||||
	mio_skad_t orgdst_addr;
 | 
			
		||||
	mio_htrd_t* htrd;
 | 
			
		||||
	mio_becs_t* sbuf; /* temporary buffer for status line formatting */
 | 
			
		||||
};
 | 
			
		||||
typedef struct mio_htts_client_t mio_htts_client_t;
 | 
			
		||||
 | 
			
		||||
struct sck_xtn_t
 | 
			
		||||
{
 | 
			
		||||
	mio_svc_htts_t* htts;
 | 
			
		||||
	mio_htrd_t* htrd; /* used by clients only */
 | 
			
		||||
 | 
			
		||||
	mio_htts_client_t c;
 | 
			
		||||
};
 | 
			
		||||
typedef struct sck_xtn_t sck_xtn_t;
 | 
			
		||||
 | 
			
		||||
@ -28,6 +40,282 @@ struct htrd_xtn_t
 | 
			
		||||
typedef struct htrd_xtn_t htrd_xtn_t;
 | 
			
		||||
/* ------------------------------------------------------------------------ */
 | 
			
		||||
 | 
			
		||||
static int process_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, int peek)
 | 
			
		||||
{
 | 
			
		||||
	//server_xtn_t* server_xtn = GET_SERVER_XTN(htts, client->server);
 | 
			
		||||
	//mio_htts_task_t* task;
 | 
			
		||||
	sck_xtn_t* csckxtn = mio_dev_sck_getxtn(csck);
 | 
			
		||||
	mio_http_method_t mth;
 | 
			
		||||
	//mio_htts_rsrc_t rsrc;
 | 
			
		||||
 | 
			
		||||
	/* percent-decode the query path to the original buffer
 | 
			
		||||
	 * since i'm not going to need it in the original form
 | 
			
		||||
	 * any more. once it's decoded in the peek mode,
 | 
			
		||||
	 * the decoded query path is made available in the
 | 
			
		||||
	 * non-peek mode as well */
 | 
			
		||||
	if (peek) 
 | 
			
		||||
	{
 | 
			
		||||
		mio_htre_perdecqpath(req);
 | 
			
		||||
 | 
			
		||||
		/* TODO: proper request logging */
 | 
			
		||||
 | 
			
		||||
		MIO_DEBUG2 (htts->mio, "%s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req));
 | 
			
		||||
	}
 | 
			
		||||
else
 | 
			
		||||
{
 | 
			
		||||
	MIO_DEBUG2 (htts->mio, "[NOPEEK] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
mio_printf (MIO_T("================================\n"));
 | 
			
		||||
mio_printf (MIO_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"),
 | 
			
		||||
	(unsigned long)time(NULL),
 | 
			
		||||
	(peek? MIO_MT("PEEK"): MIO_MT("HANDLE")),
 | 
			
		||||
	mio_htre_getqpath(req),
 | 
			
		||||
	mio_htre_getmajorversion(req),
 | 
			
		||||
	mio_htre_getminorversion(req),
 | 
			
		||||
	mio_htre_getverstr(req),
 | 
			
		||||
	mio_htre_getqmethodname(req)
 | 
			
		||||
);
 | 
			
		||||
if (mio_htre_getqparam(req))
 | 
			
		||||
	mio_printf (MIO_T("PARAMS ==> [%hs]\n"), mio_htre_getqparam(req));
 | 
			
		||||
 | 
			
		||||
mio_htb_walk (&req->hdrtab, walk, MIO_NULL);
 | 
			
		||||
if (mio_htre_getcontentlen(req) > 0)
 | 
			
		||||
{
 | 
			
		||||
	mio_printf (MIO_T("CONTENT [%.*S]\n"), (int)mio_htre_getcontentlen(req), mio_htre_getcontentptr(req));
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	mth = mio_htre_getqmethodtype(req);
 | 
			
		||||
	if (peek)
 | 
			
		||||
	{
 | 
			
		||||
		/* determine what to do once the header fields are all received.
 | 
			
		||||
		 * i don't want to delay this until the contents are received.
 | 
			
		||||
		 * if you don't like this behavior, you must implement your own
 | 
			
		||||
		 * callback function for request handling. */
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
		/* TODO support X-HTTP-Method-Override */
 | 
			
		||||
		if (data.method == MIO_HTTP_POST)
 | 
			
		||||
		{
 | 
			
		||||
			tmp = mio_htre_getheaderval(req, MIO_MT("X-HTTP-Method-Override"));
 | 
			
		||||
			if (tmp)
 | 
			
		||||
			{
 | 
			
		||||
				/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
 | 
			
		||||
				data.method = mio_mbstohttpmethod (tmp->ptr);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (mth == MIO_HTTP_CONNECT)
 | 
			
		||||
		{
 | 
			
		||||
			/* CONNECT method must not have content set. 
 | 
			
		||||
			 * however, arrange to discard it if so. 
 | 
			
		||||
			 *
 | 
			
		||||
			 * NOTE: CONNECT is implemented to ignore many headers like
 | 
			
		||||
			 *       'Expect: 100-continue' and 'Connection: keep-alive'. */
 | 
			
		||||
			mio_htre_discardcontent (req);
 | 
			
		||||
		}
 | 
			
		||||
		else 
 | 
			
		||||
		{
 | 
			
		||||
#if 0
 | 
			
		||||
			if (mth == MIO_HTTP_POST &&
 | 
			
		||||
			    !(req->flags & MIO_HTRE_ATTR_LENGTH) &&
 | 
			
		||||
			    !(req->flags & MIO_HTRE_ATTR_CHUNKED))
 | 
			
		||||
			{
 | 
			
		||||
				/* POST without Content-Length nor not chunked */
 | 
			
		||||
				req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE;
 | 
			
		||||
				mio_htre_discardcontent (req);
 | 
			
		||||
				task = mio_htts_entaskerror(htts, client, MIO_NULL, 411, req);
 | 
			
		||||
				if (task) 
 | 
			
		||||
				{
 | 
			
		||||
					/* 411 Length Required - can't keep alive. Force disconnect */
 | 
			
		||||
					task = mio_htts_entaskdisconnect (htts, client, MIO_NULL);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	const qse_http_version_t* version = qse_htre_getversion(req);
 | 
			
		||||
	return qse_httpd_entaskformat (
 | 
			
		||||
		httpd, client, pred,
 | 
			
		||||
		QSE_MT("HTTP/%d.%d 100 Continue\r\n\r\n"),
 | 
			
		||||
		version->major, version->minor);
 | 
			
		||||
*/
 | 
			
		||||
				mio_dev_sck_write (csck, data, len, XXXX, MIO_NULL);
 | 
			
		||||
			}
 | 
			
		||||
			else if (server_xtn->makersrc(htts, client, req, &rsrc) <= -1)
 | 
			
		||||
			{
 | 
			
		||||
				/* failed to make a resource. just send the internal server error.
 | 
			
		||||
				 * the makersrc handler can return a negative number to return 
 | 
			
		||||
				 * '500 Internal Server Error'. If it wants to return a specific
 | 
			
		||||
				 * error code, it should return 0 with the MIO_HTTPD_RSRC_ERROR
 | 
			
		||||
				 * resource. */
 | 
			
		||||
				mio_htts_discardcontent (req);
 | 
			
		||||
				task = mio_htts_entaskerror(htts, client, MIO_NULL, 500, req);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
 | 
			
		||||
				task = MIO_NULL;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				if ((rsrc.flags & MIO_HTTPD_RSRC_100_CONTINUE) &&
 | 
			
		||||
				    (task = mio_htts_entaskcontinue(htts, client, task, req)) == MIO_NULL) 
 | 
			
		||||
				{
 | 
			
		||||
					/* inject '100 continue' first if it is needed */
 | 
			
		||||
					goto oops;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* arrange the actual resource to be returned */
 | 
			
		||||
				task = mio_htts_entaskrsrc(htts, client, task, &rsrc, req);
 | 
			
		||||
				server_xtn->freersrc (htts, client, req, &rsrc);
 | 
			
		||||
 | 
			
		||||
				/* if the resource is indicating to return an error,
 | 
			
		||||
				 * discard the contents since i won't return them */
 | 
			
		||||
				if (rsrc.type == MIO_HTTPD_RSRC_ERROR) 
 | 
			
		||||
				{ 
 | 
			
		||||
					mio_htre_discardcontent (req); 
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (task == MIO_NULL) goto oops;
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* contents are all received */
 | 
			
		||||
mio_svc_htts_sendstatus (htts, csck, 500, mth, mio_htre_getversion(req), (req->flags & MIO_HTRE_ATTR_KEEPALIVE), MIO_NULL);
 | 
			
		||||
return 0;
 | 
			
		||||
 | 
			
		||||
		if (mth == MIO_HTTP_CONNECT)
 | 
			
		||||
		{
 | 
			
		||||
			MIO_DEBUG1 (htts->mio, "Switching HTRD to DUMMY for [%hs]\n", mio_htre_getqpath(req));
 | 
			
		||||
 | 
			
		||||
			/* Switch the http read to a dummy mode so that the subsqeuent
 | 
			
		||||
			 * input(request) is just treated as data to the request just 
 | 
			
		||||
			 * completed */
 | 
			
		||||
			mio_htrd_dummify (csckxtn->c.htrd);
 | 
			
		||||
 | 
			
		||||
////////
 | 
			
		||||
#if 0
 | 
			
		||||
			if (server_xtn->makersrc(htts, client, req, &rsrc) <= -1)
 | 
			
		||||
			{
 | 
			
		||||
				MIO_DEBUG1 (htts->mio, "Cannot make resource for [%hs]\n", mio_htre_getqpath(req));
 | 
			
		||||
 | 
			
		||||
				/* failed to make a resource. just send the internal server error.
 | 
			
		||||
				 * the makersrc handler can return a negative number to return 
 | 
			
		||||
				 * '500 Internal Server Error'. If it wants to return a specific
 | 
			
		||||
				 * error code, it should return 0 with the MIO_HTTPD_RSRC_ERROR
 | 
			
		||||
				 * resource. */
 | 
			
		||||
				task = mio_htts_entaskerror(htts, client, MIO_NULL, 500, req);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				/* arrange the actual resource to be returned */
 | 
			
		||||
				task = mio_htts_entaskrsrc (htts, client, MIO_NULL, &rsrc, req);
 | 
			
		||||
				server_xtn->freersrc (htts, client, req, &rsrc);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (task == MIO_NULL) goto oops;
 | 
			
		||||
#endif
 | 
			
		||||
////////
 | 
			
		||||
		}
 | 
			
		||||
		else if (req->flags & MIO_HTRE_ATTR_PROXIED)
 | 
			
		||||
		{
 | 
			
		||||
			/* the contents should be proxied. 
 | 
			
		||||
			 * do nothing locally */
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/* when the request is handled locally, 
 | 
			
		||||
			 * there's nothing special to do here */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(req->flags & MIO_HTRE_ATTR_KEEPALIVE) || mth == MIO_HTTP_CONNECT)
 | 
			
		||||
	{
 | 
			
		||||
		if (!peek)
 | 
			
		||||
		{
 | 
			
		||||
////			task = mio_htts_entaskdisconnect(htts, client, MIO_NULL);
 | 
			
		||||
////			if (MIO_UNLIKELY(!task)) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	/*mio_htts_markbadclient (htts, client);*/
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int client_htrd_peek_request (mio_htrd_t* htrd, mio_htre_t* req)
 | 
			
		||||
{
 | 
			
		||||
	htrd_xtn_t* htrdxtn = (htrd_xtn_t*)mio_htrd_getxtn(htrd);
 | 
			
		||||
	sck_xtn_t* sckxtn = (sck_xtn_t*)mio_dev_sck_getxtn(htrdxtn->sck);
 | 
			
		||||
	return process_request(sckxtn->htts, htrdxtn->sck, req, 1);
 | 
			
		||||
//	return xtn->htts->opt.rcb.peekreq(xtn->htts, xtn->client, req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int client_htrd_poke_request (mio_htrd_t* htrd, mio_htre_t* req)
 | 
			
		||||
{
 | 
			
		||||
	htrd_xtn_t* htrdxtn = (htrd_xtn_t*)mio_htrd_getxtn(htrd);
 | 
			
		||||
	sck_xtn_t* sckxtn = (sck_xtn_t*)mio_dev_sck_getxtn(htrdxtn->sck);
 | 
			
		||||
	return process_request(sckxtn->htts, htrdxtn->sck, req, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static mio_htrd_recbs_t client_htrd_recbs =
 | 
			
		||||
{
 | 
			
		||||
	client_htrd_peek_request,
 | 
			
		||||
	client_htrd_poke_request
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int init_client (mio_t* mio, mio_htts_client_t* c, mio_dev_sck_t* sck)
 | 
			
		||||
{
 | 
			
		||||
	htrd_xtn_t* htrdxtn;
 | 
			
		||||
 | 
			
		||||
	c->htrd = mio_htrd_open(mio, MIO_SIZEOF(*htrdxtn));
 | 
			
		||||
	if (MIO_UNLIKELY(!c->htrd)) goto oops;
 | 
			
		||||
 | 
			
		||||
	c->sbuf = mio_becs_open(mio, 0, 2048);
 | 
			
		||||
	if (MIO_UNLIKELY(!c->sbuf)) goto oops;
 | 
			
		||||
	htrdxtn = mio_htrd_getxtn(c->htrd);
 | 
			
		||||
	htrdxtn->sck = sck;
 | 
			
		||||
 | 
			
		||||
	mio_htrd_setrecbs (c->htrd, &client_htrd_recbs);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	if (c->sbuf) 
 | 
			
		||||
	{
 | 
			
		||||
		mio_becs_close(c->sbuf);
 | 
			
		||||
		c->sbuf = MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
	if (c->htrd)
 | 
			
		||||
	{
 | 
			
		||||
		mio_htrd_close (c->htrd);
 | 
			
		||||
		c->htrd = MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fini_client (mio_t* mio, mio_htts_client_t* c)
 | 
			
		||||
{
 | 
			
		||||
	if (c->sbuf) 
 | 
			
		||||
	{
 | 
			
		||||
		mio_becs_close(c->sbuf);
 | 
			
		||||
		c->sbuf = MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
	if (c->htrd)
 | 
			
		||||
	{
 | 
			
		||||
		mio_htrd_close (c->htrd);
 | 
			
		||||
		c->htrd = MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------------ */
 | 
			
		||||
 | 
			
		||||
static int client_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr)
 | 
			
		||||
{
 | 
			
		||||
	sck_xtn_t* sckxtn = mio_dev_sck_getxtn(sck);
 | 
			
		||||
@ -36,7 +324,7 @@ printf ("** HTTS - client read   %p  %d -> htts:%p\n", sck, (int)len, sckxtn->ht
 | 
			
		||||
	{
 | 
			
		||||
		mio_dev_sck_halt (sck);
 | 
			
		||||
	}
 | 
			
		||||
	else if (mio_htrd_feed(sckxtn->htrd, buf, len) <= -1)
 | 
			
		||||
	else if (mio_htrd_feed(sckxtn->c.htrd, buf, len) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		mio_dev_sck_halt (sck);
 | 
			
		||||
	}
 | 
			
		||||
@ -49,12 +337,15 @@ static int client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrctx,
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int client_on_disconnect (mio_dev_sck_t* sck)
 | 
			
		||||
static void client_on_disconnect (mio_dev_sck_t* sck)
 | 
			
		||||
{
 | 
			
		||||
	sck_xtn_t* sckxtn = mio_dev_sck_getxtn(sck);
 | 
			
		||||
printf ("** HTTS - client disconnect  %p\n", sck);
 | 
			
		||||
	fini_client (sck->mio, &sckxtn->c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------------ */
 | 
			
		||||
 | 
			
		||||
static int listener_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
@ -72,31 +363,23 @@ static void listener_on_connect (mio_dev_sck_t* sck)
 | 
			
		||||
	if (sck->state & MIO_DEV_SCK_ACCEPTED)
 | 
			
		||||
	{
 | 
			
		||||
		/* accepted a new client */
 | 
			
		||||
		htrd_xtn_t* htrdxtn;
 | 
			
		||||
 | 
			
		||||
		printf ("** HTTS(%p) - accepted... %p %d \n", sckxtn->htts, sck, sck->sck);
 | 
			
		||||
		MIO_DEBUG3 (sck->mio, "** HTTS(%p) - accepted... %p %d \n", sckxtn->htts, sck, sck->sck);
 | 
			
		||||
 | 
			
		||||
		/* the accepted socket inherits various event callbacks. switch some of them to avoid sharing */
 | 
			
		||||
		sck->on_read = client_on_read;
 | 
			
		||||
		sck->on_write = client_on_write;
 | 
			
		||||
		sck->on_disconnect = client_on_disconnect;
 | 
			
		||||
 | 
			
		||||
		sckxtn->htrd = mio_htrd_open(sck->mio, MIO_SIZEOF(*htrdxtn));
 | 
			
		||||
		if (MIO_UNLIKELY(!sckxtn->htrd)) 
 | 
			
		||||
		if (init_client(sck->mio, &sckxtn->c, sck) <= -1)
 | 
			
		||||
		{
 | 
			
		||||
			MIO_INFO2 (sck->mio, "UNABLE TO OPEN HTTP READER FOR ACCEPTED SOCKET %p %d\n", sck, (int)sck->sck);
 | 
			
		||||
			MIO_INFO2 (sck->mio, "UNABLE TO INITIALIZE NEW CLIENT %p %d\n", sck, (int)sck->sck);
 | 
			
		||||
			mio_dev_sck_halt (sck);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			htrdxtn = mio_htrd_getxtn(sckxtn->htrd);
 | 
			
		||||
			htrdxtn->sck = sck;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (sck->state & MIO_DEV_SCK_CONNECTED)
 | 
			
		||||
	{
 | 
			
		||||
		/* this will never be triggered as the listing socket never call mio_dev_sck_connect() */
 | 
			
		||||
		printf ("** HTTS(%p) - connected... %p %d \n", sckxtn->htts, sck, sck->sck);
 | 
			
		||||
		MIO_DEBUG3 (sck->mio, "** HTTS(%p) - connected... %p %d \n", sckxtn->htts, sck, sck->sck);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* MIO_DEV_SCK_CONNECTED must not be seen here as this is only for the listener socket */
 | 
			
		||||
@ -137,11 +420,11 @@ static void listener_on_disconnect (mio_dev_sck_t* sck)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sckxtn->htrd)
 | 
			
		||||
	{
 | 
			
		||||
		mio_htrd_close (sckxtn->htrd);
 | 
			
		||||
		sckxtn->htrd = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* the client sockets are finalized in clinet_on_disconnect().
 | 
			
		||||
	 * for a listener socket, these fields must be NULL */
 | 
			
		||||
	MIO_ASSERT (sck->mio, sckxtn->c.htrd == MIO_NULL);
 | 
			
		||||
	MIO_ASSERT (sck->mio, sckxtn->c.sbuf == MIO_NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -226,3 +509,93 @@ void mio_svc_htts_stop (mio_svc_htts_t* htts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void mio_svc_htts_sendstatus (mio_svc_htts_t* htts, mio_dev_sck_t* csck, int status_code, mio_http_method_t method, const mio_http_version_t* version, int keepalive, void* extra)
 | 
			
		||||
{
 | 
			
		||||
	sck_xtn_t* csckxtn = mio_dev_sck_getxtn(csck);
 | 
			
		||||
	mio_bch_t text[1024]; /* TODO: make this buffer dynamic or scalable */
 | 
			
		||||
	mio_bch_t dtbuf[64];
 | 
			
		||||
 | 
			
		||||
	const mio_bch_t* extrapre = ""; 
 | 
			
		||||
	const mio_bch_t* extrapst = "";
 | 
			
		||||
	const mio_bch_t* extraval = "";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	text[0] = '\0';
 | 
			
		||||
 | 
			
		||||
	switch (status_code)
 | 
			
		||||
	{
 | 
			
		||||
#if 0
 | 
			
		||||
		case 301: /* Moved Permanently */ 
 | 
			
		||||
		case 302: /* Found */
 | 
			
		||||
		case 303: /* See Other (since HTTP/1.1) */
 | 
			
		||||
		case 307: /* Temporary Redirect (since HTTP/1.1) */
 | 
			
		||||
		case 308: /* Permanent Redirect (Experimental RFC; RFC 7238) */
 | 
			
		||||
		{
 | 
			
		||||
			mio_svc_htts_rsrc_reloc_t* reloc;
 | 
			
		||||
			reloc = (mio_htts_rsrc_reloc_t*)extra;
 | 
			
		||||
			extrapre = "Location: ";
 | 
			
		||||
			extrapst = (reloc->flags & MIO_SVC_HTTS_RSRC_RELOC_APPENDSLASH)? "/\r\n": "\r\n";
 | 
			
		||||
			extraval = reloc->target;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		case 304:
 | 
			
		||||
		case 200:
 | 
			
		||||
		case 201:
 | 
			
		||||
		case 202:
 | 
			
		||||
		case 203:
 | 
			
		||||
		case 204:
 | 
			
		||||
		case 205:
 | 
			
		||||
		case 206:
 | 
			
		||||
			/* nothing to do */
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
#if 0
 | 
			
		||||
			if (method != MIO_HTTP_HEAD &&
 | 
			
		||||
			    htts->opt.rcb.fmterr(htts, client, code, text, MIO_COUNTOF(text)) <= -1) return QSE_NULL;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			if (status_code == 401)
 | 
			
		||||
			{
 | 
			
		||||
				extrapre = "WWW-Authenticate: Basic realm=\"";
 | 
			
		||||
				extrapst = "\"\r\n";
 | 
			
		||||
				extraval = (const mio_bch_t*)extra;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	mio_svc_htts_fmtgmtime(htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf));
 | 
			
		||||
 | 
			
		||||
	mio_becs_fmt (csckxtn->c.sbuf, "HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %u\r\n%s%s%s\r\n%s",
 | 
			
		||||
		version->major, version->minor, status_code, mio_http_status_to_bcstr(status_code), 
 | 
			
		||||
		"SERVER-NAME", /* TODO: use actual name mio_svc_htts_getservername(). */
 | 
			
		||||
		dtbuf, /* DATE */
 | 
			
		||||
		(keepalive? "keep-alive": "close"), /* connection */
 | 
			
		||||
		mio_count_bcstr(text), /* content length */
 | 
			
		||||
		extrapre, extraval, extraval, text
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	if (mio_dev_sck_write(csck, MIO_BECS_PTR(csckxtn->c.sbuf), MIO_BECS_LEN(csckxtn->c.sbuf), MIO_NULL, MIO_NULL) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		mio_dev_sck_halt (csck);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void mio_svc_htts_fmtgmtime (mio_svc_htts_t* htts, const mio_ntime_t* nt, mio_bch_t* buf, mio_oow_t len)
 | 
			
		||||
{
 | 
			
		||||
	mio_ntime_t now;
 | 
			
		||||
 | 
			
		||||
	if (!nt) 
 | 
			
		||||
	{
 | 
			
		||||
		mio_sys_getrealtime(htts->mio, &now);
 | 
			
		||||
		nt = &now;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mio_fmt_http_time_to_bcstr(nt, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -380,9 +380,8 @@ mio_bch_t* mio_fmt_http_time_to_bcstr (const mio_ntime_t* nt, mio_bch_t* buf, mi
 | 
			
		||||
	struct tm bt;
 | 
			
		||||
 | 
			
		||||
	t = nt->sec;
 | 
			
		||||
	gmtime_r (&t, &bt);
 | 
			
		||||
	gmtime_r (&t, &bt); /* TODO: create mio_sys_gmtime() and make it system dependent */
 | 
			
		||||
 | 
			
		||||
	/* mio_fmttobcstr() works well with MIO_NULL in mio if formatting doesn't involve cross-encoding */
 | 
			
		||||
	mio_fmttobcstr (MIO_NULL, buf, bufsz, 
 | 
			
		||||
		"%hs, %d %hs %d %02d:%02d:%02d GMT",
 | 
			
		||||
		wday_name[bt.tm_wday].s,
 | 
			
		||||
@ -418,7 +417,7 @@ int mio_is_perenced_http_bcstr (const mio_bch_t* str)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_oow_t mio_perdechttpstr (const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* ndecs)
 | 
			
		||||
mio_oow_t mio_perdec_http_bcstr (const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* ndecs)
 | 
			
		||||
{
 | 
			
		||||
	const mio_bch_t* p = str;
 | 
			
		||||
	mio_bch_t* out = buf;
 | 
			
		||||
@ -460,7 +459,7 @@ mio_oow_t mio_perdechttpstr (const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nd
 | 
			
		||||
 | 
			
		||||
#define TO_HEX(v) ("0123456789ABCDEF"[(v) & 15])
 | 
			
		||||
 | 
			
		||||
mio_oow_t mio_perenchttpstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nencs)
 | 
			
		||||
mio_oow_t mio_perenc_http_bcstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nencs)
 | 
			
		||||
{
 | 
			
		||||
	const mio_bch_t* p = str;
 | 
			
		||||
	mio_bch_t* out = buf;
 | 
			
		||||
@ -469,7 +468,7 @@ mio_oow_t mio_perenchttpstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_
 | 
			
		||||
	/* this function doesn't accept the size of the buffer. the caller must 
 | 
			
		||||
	 * ensure that the buffer is large enough */
 | 
			
		||||
 | 
			
		||||
	if (opt & MIO_PERENCHTTPSTR_KEEP_SLASH)
 | 
			
		||||
	if (opt & MIO_PERENC_HTTP_KEEP_SLASH)
 | 
			
		||||
	{
 | 
			
		||||
		while (*p != '\0')
 | 
			
		||||
		{
 | 
			
		||||
@ -504,14 +503,15 @@ mio_oow_t mio_perenchttpstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_
 | 
			
		||||
	return out - buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_bch_t* mio_perenchttpstrdup (int opt, const mio_bch_t* str, mio_mmgr_t* mmgr)
 | 
			
		||||
#if 0
 | 
			
		||||
mio_bch_t* mio_perenc_http_bcstrdup (int opt, const mio_bch_t* str, mio_mmgr_t* mmgr)
 | 
			
		||||
{
 | 
			
		||||
	mio_bch_t* buf;
 | 
			
		||||
	mio_oow_t len = 0;
 | 
			
		||||
	mio_oow_t count = 0;
 | 
			
		||||
	
 | 
			
		||||
	/* count the number of characters that should be encoded */
 | 
			
		||||
	if (opt & MIO_PERENCHTTPSTR_KEEP_SLASH)
 | 
			
		||||
	if (opt & MIO_PERENC_HTTP_KEEP_SLASH)
 | 
			
		||||
	{
 | 
			
		||||
		for (len = 0; str[len] != '\0'; len++)
 | 
			
		||||
		{
 | 
			
		||||
@ -530,11 +530,12 @@ mio_bch_t* mio_perenchttpstrdup (int opt, const mio_bch_t* str, mio_mmgr_t* mmgr
 | 
			
		||||
	if (count <= 0) return (mio_bch_t*)str;
 | 
			
		||||
 | 
			
		||||
	/* allocate a buffer of an optimal size for escaping, otherwise */
 | 
			
		||||
	buf = MIO_MMGR_ALLOC (mmgr, (len  + (count * 2) + 1)  * MIO_SIZEOF(*buf));
 | 
			
		||||
	if (buf == MIO_NULL) return MIO_NULL;
 | 
			
		||||
	buf = MIO_MMGR_ALLOC(mmgr, (len  + (count * 2) + 1)  * MIO_SIZEOF(*buf));
 | 
			
		||||
	if (!buf) return MIO_NULL;
 | 
			
		||||
 | 
			
		||||
	/* perform actual escaping */
 | 
			
		||||
	mio_perenchttpstr (opt, str, buf, MIO_NULL);
 | 
			
		||||
	mio_perenc_http_bcstr (opt, str, buf, MIO_NULL);
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -49,15 +49,15 @@ typedef enum mio_htre_state_t mio_htre_state_t;
 | 
			
		||||
 | 
			
		||||
typedef int (*mio_htre_concb_t) (
 | 
			
		||||
	mio_htre_t*        re,
 | 
			
		||||
	const mio_bch_t* ptr,
 | 
			
		||||
	mio_oow_t         len,
 | 
			
		||||
	const mio_bch_t*   ptr,
 | 
			
		||||
	mio_oow_t          len,
 | 
			
		||||
	void*              ctx
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
struct mio_htre_hdrval_t
 | 
			
		||||
{
 | 
			
		||||
	const mio_bch_t* ptr;
 | 
			
		||||
	mio_oow_t         len;
 | 
			
		||||
	const mio_bch_t*   ptr;
 | 
			
		||||
	mio_oow_t          len;
 | 
			
		||||
	mio_htre_hdrval_t* next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -148,11 +148,11 @@ struct mio_http_range_t
 | 
			
		||||
typedef struct mio_http_range_t mio_http_range_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum mio_perenchttpstr_opt_t
 | 
			
		||||
enum mio_perenc_http_opt_t
 | 
			
		||||
{
 | 
			
		||||
	MIO_PERENCHTTPSTR_KEEP_SLASH = (1 << 0)
 | 
			
		||||
	MIO_PERENC_HTTP_KEEP_SLASH = (1 << 0)
 | 
			
		||||
};
 | 
			
		||||
typedef enum mio_perenchttpstr_opt_t mio_perenchttpstr_opt_t;
 | 
			
		||||
typedef enum mio_perenc_http_opt_t mio_perenc_bcstr_opt_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------------------- */
 | 
			
		||||
@ -210,37 +210,40 @@ MIO_EXPORT int mio_is_perenced_http_bcstr (
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The mio_perdechttpstr() function performs percent-decoding over a string.
 | 
			
		||||
 * The mio_perdec_http_bcstr() function performs percent-decoding over a string.
 | 
			
		||||
 * The caller must ensure that the output buffer \a buf is large enough.
 | 
			
		||||
 * If \a ndecs is not #MIO_NULL, it is set to the number of characters
 | 
			
		||||
 * decoded.  0 means no characters in the input string required decoding
 | 
			
		||||
 * \return the length of the output string.
 | 
			
		||||
 */
 | 
			
		||||
MIO_EXPORT mio_oow_t mio_perdechttpstr (
 | 
			
		||||
MIO_EXPORT mio_oow_t mio_perdec_http_bcstr (
 | 
			
		||||
	const mio_bch_t* str, 
 | 
			
		||||
	mio_bch_t*       buf,
 | 
			
		||||
	mio_oow_t*       ndecs
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The mio_perenchttpstr() function performs percent-encoding over a string.
 | 
			
		||||
 * The mio_perenc_http_bcstr() function performs percent-encoding over a string.
 | 
			
		||||
 * The caller must ensure that the output buffer \a buf is large enough.
 | 
			
		||||
 * If \a nencs is not #MIO_NULL, it is set to the number of characters
 | 
			
		||||
 * encoded.  0 means no characters in the input string required encoding.
 | 
			
		||||
 * \return the length of the output string.
 | 
			
		||||
 */
 | 
			
		||||
MIO_EXPORT mio_oow_t mio_perenchttpstr (
 | 
			
		||||
	int              opt, /**< 0 or bitwise-OR'ed of #mio_perenchttpstr_opt_t */
 | 
			
		||||
MIO_EXPORT mio_oow_t mio_perenc_http_bcstr (
 | 
			
		||||
	int              opt, /**< 0 or bitwise-OR'ed of #mio_perenc_http_bcstr_opt_t */
 | 
			
		||||
	const mio_bch_t* str, 
 | 
			
		||||
	mio_bch_t*       buf,
 | 
			
		||||
	mio_oow_t*       nencs
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT mio_bch_t* mio_perenchttpstrdup (
 | 
			
		||||
	int                opt, /**< 0 or bitwise-OR'ed of #mio_perenchttpstr_opt_t */
 | 
			
		||||
#if 0
 | 
			
		||||
/* TODO: rename this function according to the naming convension */
 | 
			
		||||
MIO_EXPORT mio_bch_t* mio_perenc_http_bcstrdup (
 | 
			
		||||
	int                opt, /**< 0 or bitwise-OR'ed of #mio_perenc_http_bcstr_opt_t */
 | 
			
		||||
	const mio_bch_t*   str, 
 | 
			
		||||
	mio_mmgr_t*        mmgr
 | 
			
		||||
);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------------- */
 | 
			
		||||
/* HTTP SERVER SERVICE                                                       */
 | 
			
		||||
@ -255,6 +258,24 @@ MIO_EXPORT void mio_svc_htts_stop (
 | 
			
		||||
	mio_svc_htts_t* htts
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT void mio_svc_htts_sendstatus (
 | 
			
		||||
	mio_svc_htts_t*           htts,
 | 
			
		||||
	mio_dev_sck_t*            csck,
 | 
			
		||||
	int                       status_code,
 | 
			
		||||
	mio_http_method_t         method,
 | 
			
		||||
	const mio_http_version_t* version,
 | 
			
		||||
	int                       keepalive,
 | 
			
		||||
	void*                     extra
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT void mio_svc_htts_fmtgmtime (
 | 
			
		||||
	mio_svc_htts_t*           htts,
 | 
			
		||||
	const mio_ntime_t*        nt,
 | 
			
		||||
	mio_bch_t*                buf,
 | 
			
		||||
	mio_oow_t                 len
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -183,6 +183,11 @@ void mio_sys_gettime (
 | 
			
		||||
	mio_ntime_t* now
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
void mio_sys_getrealtime (
 | 
			
		||||
	mio_t*       mio,
 | 
			
		||||
	mio_ntime_t* now
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1592,11 +1592,9 @@ static int fmt_put_bchars_to_uch_buf (mio_fmtout_t* fmtout, const mio_bch_t* ptr
 | 
			
		||||
	mio_oow_t bcslen, ucslen;
 | 
			
		||||
	int n;
 | 
			
		||||
 | 
			
		||||
	if (!b->mio) return -1; /* no mio, no cross encoding formatting */
 | 
			
		||||
 | 
			
		||||
	bcslen = len;
 | 
			
		||||
	ucslen = b->capa - b->len;
 | 
			
		||||
	n = mio_conv_bchars_to_uchars_with_cmgr(ptr, &bcslen, &b->ptr[b->len], &ucslen, b->mio->_cmgr, 1);
 | 
			
		||||
	n = mio_conv_bchars_to_uchars_with_cmgr(ptr, &bcslen, &b->ptr[b->len], &ucslen, (b->mio? b->mio->_cmgr: mio_get_utf8_cmgr()), 1);
 | 
			
		||||
	b->len += ucslen;
 | 
			
		||||
	if (n <= -1) 
 | 
			
		||||
	{
 | 
			
		||||
@ -1703,11 +1701,9 @@ static int fmt_put_uchars_to_bch_buf (mio_fmtout_t* fmtout, const mio_uch_t* ptr
 | 
			
		||||
	mio_oow_t bcslen, ucslen;
 | 
			
		||||
	int n;
 | 
			
		||||
 | 
			
		||||
	if (!b->mio) return -1; /* no mio, no cross encoding formatting */
 | 
			
		||||
 | 
			
		||||
	bcslen = b->capa - b->len;
 | 
			
		||||
	ucslen = len;
 | 
			
		||||
	n = mio_conv_uchars_to_bchars_with_cmgr(ptr, &ucslen, &b->ptr[b->len], &bcslen, b->mio->_cmgr);
 | 
			
		||||
	n = mio_conv_uchars_to_bchars_with_cmgr(ptr, &ucslen, &b->ptr[b->len], &bcslen, (b->mio? b->mio->_cmgr: mio_get_utf8_cmgr()));
 | 
			
		||||
	b->len += bcslen;
 | 
			
		||||
	if (n <= -1)
 | 
			
		||||
	{
 | 
			
		||||
@ -1742,7 +1738,6 @@ mio_oow_t mio_vfmttobcstr (mio_t* mio, mio_bch_t* buf, mio_oow_t bufsz, const mi
 | 
			
		||||
	fb.mio = mio;
 | 
			
		||||
	fb.ptr = buf;
 | 
			
		||||
	fb.capa = bufsz - 1;
 | 
			
		||||
 | 
			
		||||
	if (mio_bfmt_outv(&fo, fmt, ap) <= -1) return -1;
 | 
			
		||||
 | 
			
		||||
	buf[fb.len] = '\0';
 | 
			
		||||
 | 
			
		||||
@ -151,3 +151,17 @@ void mio_sys_gettime (mio_t* mio, mio_ntime_t* now)
 | 
			
		||||
	MIO_INIT_NTIME(now, tv.tv_sec, MIO_USEC_TO_NSEC(tv.tv_usec));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void mio_sys_getrealtime (mio_t* mio, mio_ntime_t* now)
 | 
			
		||||
{
 | 
			
		||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
 | 
			
		||||
	struct timespec ts;
 | 
			
		||||
	clock_gettime (CLOCK_REALTIME, &ts);
 | 
			
		||||
	MIO_INIT_NTIME(now, ts.tv_sec, ts.tv_nsec);
 | 
			
		||||
#else
 | 
			
		||||
	struct timeval tv;
 | 
			
		||||
	gettimeofday (&tv, MIO_NULL);
 | 
			
		||||
	MIO_INIT_NTIME(now, tv.tv_sec, MIO_USEC_TO_NSEC(tv.tv_usec));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user