adding some functions for multi-threading
This commit is contained in:
		@ -444,7 +444,7 @@ static mio_htrd_recbs_t file_client_htrd_recbs =
 | 
			
		||||
 | 
			
		||||
/* --------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
static int file_state_send_header_to_client (file_state_t* file_state, int status_code, int force_close)
 | 
			
		||||
static int file_state_send_header_to_client (file_state_t* file_state, int status_code, int force_close, const mio_bch_t* mime_type)
 | 
			
		||||
{
 | 
			
		||||
	mio_svc_htts_cli_t* cli = file_state->client;
 | 
			
		||||
	mio_bch_t dtbuf[64];
 | 
			
		||||
@ -457,11 +457,11 @@ static int file_state_send_header_to_client (file_state_t* file_state, int statu
 | 
			
		||||
	content_length = file_state->end_offset - file_state->start_offset + 1;
 | 
			
		||||
	if (status_code == 200 && file_state->total_size != content_length) status_code = 206;
 | 
			
		||||
 | 
			
		||||
	if (mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: %hs\r\nAccept-Ranges: bytes\r\n",
 | 
			
		||||
	if (mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: %hs\r\nAccept-Ranges: bytes\r\nContent-Type: %hs\r\n",
 | 
			
		||||
		file_state->req_version.major, file_state->req_version.minor,
 | 
			
		||||
		status_code, mio_http_status_to_bcstr(status_code),
 | 
			
		||||
		cli->htts->server_name, dtbuf,
 | 
			
		||||
		(force_close? "close": "keep-alive")) == (mio_oow_t)-1) return -1;
 | 
			
		||||
		(force_close? "close": "keep-alive"), mime_type) == (mio_oow_t)-1) return -1;
 | 
			
		||||
 | 
			
		||||
/* TODO: content_type */
 | 
			
		||||
 | 
			
		||||
@ -687,7 +687,7 @@ static MIO_INLINE void fadvise_on_peer (file_state_t* file_state)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, const mio_bch_t* docroot, const mio_bch_t* file)
 | 
			
		||||
int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, const mio_bch_t* docroot, const mio_bch_t* file, const mio_bch_t* mime_type)
 | 
			
		||||
{
 | 
			
		||||
/* TODO: ETag, Last-Modified... */
 | 
			
		||||
 | 
			
		||||
@ -824,14 +824,13 @@ int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t*
 | 
			
		||||
			mio_dev_sck_setsockopt(file_state->client->sck, SOL_TCP, TCP_CORK, &tcp_cork, MIO_SIZEOF(tcp_cork));
 | 
			
		||||
		#endif
 | 
			
		||||
 | 
			
		||||
			if (file_state_send_header_to_client(file_state, 200, 0) <= -1 ||
 | 
			
		||||
			if (file_state_send_header_to_client(file_state, 200, 0, mime_type) <= -1 ||
 | 
			
		||||
			    file_state_send_contents_to_client(file_state) <= -1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (file_state->req_method == MIO_HTTP_HEAD)
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		if (file_state_send_header_to_client(file_state, 200, 0) <= -1) goto oops;
 | 
			
		||||
		if (file_state_send_header_to_client(file_state, 200, 0, mime_type) <= -1) goto oops;
 | 
			
		||||
		file_state_mark_over (file_state, FILE_STATE_OVER_READ_FROM_PEER | FILE_STATE_OVER_WRITE_TO_PEER);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "http-prv.h"
 | 
			
		||||
#include <mio-path.h>
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------------ */
 | 
			
		||||
static int client_htrd_peek_request (mio_htrd_t* htrd, mio_htre_t* req)
 | 
			
		||||
@ -482,3 +483,9 @@ mio_bch_t* mio_svc_htts_dupmergepaths (mio_svc_htts_t* htts, const mio_bch_t* ba
 | 
			
		||||
	return xpath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_svc_htts_writetosidechan (mio_svc_htts_t* htts, const void* dptr, mio_oow_t dlen)
 | 
			
		||||
{
 | 
			
		||||
	return mio_dev_sck_writetosidechan(htts->lsck, dptr, dlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -376,6 +376,9 @@
 | 
			
		||||
/* Define to 1 if you have the <openssl/ssl.h> header file. */
 | 
			
		||||
#undef HAVE_OPENSSL_SSL_H
 | 
			
		||||
 | 
			
		||||
/* Define to 1 if you have the `pipe2' function. */
 | 
			
		||||
#undef HAVE_PIPE2
 | 
			
		||||
 | 
			
		||||
/* Define to 1 if you have the `posix_fadvise' function. */
 | 
			
		||||
#undef HAVE_POSIX_FADVISE
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -264,6 +264,12 @@ static MIO_INLINE mio_t* mio_svc_htts_getmio(mio_svc_htts_t* svc) { return mio_s
 | 
			
		||||
#	define mio_svc_htts_getmio(svc) mio_svc_getmio(svc)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT int mio_svc_htts_writetosidechan (
 | 
			
		||||
	mio_svc_htts_t* htts,
 | 
			
		||||
	const void*     dptr,
 | 
			
		||||
	mio_oow_t       dlen
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT int mio_svc_htts_setservernamewithbcstr (
 | 
			
		||||
	mio_svc_htts_t*  htts,
 | 
			
		||||
	const mio_bch_t* server_name
 | 
			
		||||
@ -282,7 +288,8 @@ MIO_EXPORT int mio_svc_htts_dofile (
 | 
			
		||||
	mio_dev_sck_t*   csck,
 | 
			
		||||
	mio_htre_t*      req,
 | 
			
		||||
	const mio_bch_t* docroot,
 | 
			
		||||
	const mio_bch_t* script
 | 
			
		||||
	const mio_bch_t* file,
 | 
			
		||||
	const mio_bch_t* mime_type
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT int mio_svc_htts_dothr (
 | 
			
		||||
 | 
			
		||||
@ -114,6 +114,11 @@ int mio_makesyshndasync (
 | 
			
		||||
	mio_syshnd_t hnd
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
int mio_makesyshndcloexec (
 | 
			
		||||
	mio_t*       mio,
 | 
			
		||||
	mio_syshnd_t hnd
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
void mio_cleartmrjobs (
 | 
			
		||||
	mio_t* mio
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -186,23 +186,6 @@ typedef struct mio_icmphdr_t mio_icmphdr_t;
 | 
			
		||||
	typedef int mio_scklen_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
#	define MIO_IOCP_KEY 1
 | 
			
		||||
	/*
 | 
			
		||||
	typedef HANDLE mio_syshnd_t;
 | 
			
		||||
	typedef SOCKET mio_sckhnd_t;
 | 
			
		||||
#	define MIO_SCKHND_INVALID (INVALID_SOCKET)
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	typedef mio_uintptr_t mio_sckhnd_t;
 | 
			
		||||
#	define MIO_SCKHND_INVALID (~(mio_sck_hnd_t)0)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
	typedef int mio_sckhnd_t;
 | 
			
		||||
#	define MIO_SCKHND_INVALID (-1)
 | 
			
		||||
	
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
@ -270,8 +253,16 @@ typedef void (*mio_dev_sck_on_connect_t) (
 | 
			
		||||
	mio_dev_sck_t* dev
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
typedef void (*mio_dev_sck_on_raw_accept_t) (
 | 
			
		||||
	mio_dev_sck_t* dev,
 | 
			
		||||
	mio_syshnd_t   syshnd
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
enum mio_dev_sck_type_t
 | 
			
		||||
{
 | 
			
		||||
	MIO_DEV_SCK_QX,
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	MIO_DEV_SCK_TCP4,
 | 
			
		||||
	MIO_DEV_SCK_TCP6,
 | 
			
		||||
	MIO_DEV_SCK_UDP4,
 | 
			
		||||
@ -285,22 +276,33 @@ enum mio_dev_sck_type_t
 | 
			
		||||
	MIO_DEV_SCK_ICMP4,
 | 
			
		||||
 | 
			
		||||
	/* ICMP at the IPv6 layer */
 | 
			
		||||
	MIO_DEV_SCK_ICMP6
 | 
			
		||||
	MIO_DEV_SCK_ICMP6,
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
	MIO_DEV_SCK_RAW,  /* raw L2-level packet */
 | 
			
		||||
#endif
 | 
			
		||||
	/* raw L2-level packet */
 | 
			
		||||
	MIO_DEV_SCK_PACKET
 | 
			
		||||
};
 | 
			
		||||
typedef enum mio_dev_sck_type_t mio_dev_sck_type_t;
 | 
			
		||||
 | 
			
		||||
enum mio_dev_sck_make_option_t
 | 
			
		||||
{
 | 
			
		||||
	/* import the system handle specified in the hnd field */
 | 
			
		||||
	MIO_DEV_SCK_MAKE_IMPSYSHND = (1 << 0) 
 | 
			
		||||
};
 | 
			
		||||
typedef enum mio_dev_sck_make_option_t mio_dev_sck_make_option_t;
 | 
			
		||||
 | 
			
		||||
typedef struct mio_dev_sck_make_t mio_dev_sck_make_t;
 | 
			
		||||
struct mio_dev_sck_make_t
 | 
			
		||||
{
 | 
			
		||||
	mio_dev_sck_type_t type;
 | 
			
		||||
 | 
			
		||||
	int options;
 | 
			
		||||
	mio_syshnd_t syshnd;
 | 
			
		||||
 | 
			
		||||
	mio_dev_sck_on_write_t on_write;
 | 
			
		||||
	mio_dev_sck_on_read_t on_read;
 | 
			
		||||
	mio_dev_sck_on_connect_t on_connect;
 | 
			
		||||
	mio_dev_sck_on_disconnect_t on_disconnect;
 | 
			
		||||
	mio_dev_sck_on_raw_accept_t on_raw_accept; /* optional */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum mio_dev_sck_bind_option_t
 | 
			
		||||
@ -362,7 +364,7 @@ struct mio_dev_sck_t
 | 
			
		||||
	MIO_DEV_HEADER;
 | 
			
		||||
 | 
			
		||||
	mio_dev_sck_type_t type;
 | 
			
		||||
	mio_sckhnd_t hnd;
 | 
			
		||||
	mio_syshnd_t hnd;
 | 
			
		||||
 | 
			
		||||
	int state;
 | 
			
		||||
 | 
			
		||||
@ -387,11 +389,11 @@ struct mio_dev_sck_t
 | 
			
		||||
	mio_dev_sck_on_write_t on_write;
 | 
			
		||||
	mio_dev_sck_on_read_t on_read;
 | 
			
		||||
 | 
			
		||||
	/* return 0 on succes, -1 on failure.
 | 
			
		||||
	 * called on a new tcp device for an accepted client or
 | 
			
		||||
	/* called on a new tcp device for an accepted client or
 | 
			
		||||
	 *        on a tcp device conntected to a remote server */
 | 
			
		||||
	mio_dev_sck_on_connect_t on_connect;
 | 
			
		||||
	mio_dev_sck_on_disconnect_t on_disconnect;
 | 
			
		||||
	mio_dev_sck_on_raw_accept_t on_raw_accept;
 | 
			
		||||
 | 
			
		||||
	/* timer job index for handling
 | 
			
		||||
	 *  - connect() timeout for a connecting socket.
 | 
			
		||||
@ -406,6 +408,7 @@ struct mio_dev_sck_t
 | 
			
		||||
	void* ssl_ctx;
 | 
			
		||||
	void* ssl;
 | 
			
		||||
 | 
			
		||||
	mio_syshnd_t side_chan; /* side-channel for MIO_DEV_SCK_QX */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum mio_dev_sck_shutdown_how_t
 | 
			
		||||
@ -415,15 +418,26 @@ enum mio_dev_sck_shutdown_how_t
 | 
			
		||||
};
 | 
			
		||||
typedef enum mio_dev_sck_shutdown_how_t mio_dev_sck_shutdown_how_t;
 | 
			
		||||
 | 
			
		||||
enum mio_dev_sck_qxmsg_cmd_t
 | 
			
		||||
{
 | 
			
		||||
	MIO_DEV_SCK_QXMSG_NEWCONN = 0
 | 
			
		||||
};
 | 
			
		||||
typedef enum mio_dev_sck_qxmsg_cmd_t mio_dev_sck_qxmsg_cmd_t;
 | 
			
		||||
 | 
			
		||||
struct mio_dev_sck_qxmsg_t
 | 
			
		||||
{
 | 
			
		||||
	mio_dev_sck_qxmsg_cmd_t cmd;
 | 
			
		||||
	mio_dev_sck_type_t scktype;
 | 
			
		||||
	mio_syshnd_t syshnd;
 | 
			
		||||
	mio_skad_t remoteaddr;
 | 
			
		||||
};
 | 
			
		||||
typedef struct mio_dev_sck_qxmsg_t mio_dev_sck_qxmsg_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT int mio_makesckasync (
 | 
			
		||||
	mio_t*       mio,
 | 
			
		||||
	mio_sckhnd_t sck
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT mio_dev_sck_t* mio_dev_sck_make (
 | 
			
		||||
@ -434,14 +448,14 @@ MIO_EXPORT mio_dev_sck_t* mio_dev_sck_make (
 | 
			
		||||
 | 
			
		||||
#if defined(MIO_HAVE_INLINE)
 | 
			
		||||
static MIO_INLINE mio_t* mio_dev_sck_getmio (mio_dev_sck_t* sck) { return mio_dev_getmio((mio_dev_t*)sck); }
 | 
			
		||||
static MIO_INLINE void* mio_dev_sck_getxtn (mio_dev_sck_t* sck) { return (void*)(sck + 1); }
 | 
			
		||||
static MIO_INLINE mio_dev_sck_type_t mio_dev_sck_gettype (mio_dev_sck_t* sck) { return sck->type; }
 | 
			
		||||
static MIO_INLINE mio_syshnd_t mio_dev_sck_getsyshnd (mio_dev_sck_t* sck) { return sck->hnd; }
 | 
			
		||||
#else
 | 
			
		||||
#	define mio_dev_sck_getmio(sck) mio_dev_getmio(sck)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(MIO_HAVE_INLINE)
 | 
			
		||||
static MIO_INLINE void* mio_dev_sck_getxtn (mio_dev_sck_t* sck) { return (void*)(sck + 1); }
 | 
			
		||||
#else
 | 
			
		||||
#	define mio_dev_sck_getxtn(sck) ((void*)(((mio_dev_sck_t*)sck) + 1))
 | 
			
		||||
#	define mio_dev_sck_gettype(sck) (((mio_dev_sck_t*)sck)->type)
 | 
			
		||||
#	define mio_dev_sck_getsyshnd(sck) (((mio_dev_sck_t*)sck)->hnd)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT int mio_dev_sck_bind (
 | 
			
		||||
@ -566,9 +580,16 @@ MIO_EXPORT int mio_dev_sck_sendfileok (
 | 
			
		||||
	mio_dev_sck_t* dev
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT int mio_dev_sck_writetosidechan (
 | 
			
		||||
	mio_dev_sck_t* htts,
 | 
			
		||||
	const void*    dptr,
 | 
			
		||||
	mio_oow_t      dlen
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT mio_uint16_t mio_checksum_ip (
 | 
			
		||||
	const void* hdr,
 | 
			
		||||
	mio_oow_t len
 | 
			
		||||
	mio_oow_t   len
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										415
									
								
								mio/lib/sck.c
									
									
									
									
									
								
							
							
						
						
									
										415
									
								
								mio/lib/sck.c
									
									
									
									
									
								
							@ -35,6 +35,7 @@
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <netinet/if_ether.h>
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_NETPACKET_PACKET_H)
 | 
			
		||||
#	include <netpacket/packet.h>
 | 
			
		||||
@ -78,28 +79,22 @@
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
int mio_makesckasync (mio_t* mio, mio_sckhnd_t sck)
 | 
			
		||||
{
 | 
			
		||||
	return mio_makesyshndasync (mio, (mio_syshnd_t)sck);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void close_async_socket (mio_t* mio, mio_sckhnd_t sck)
 | 
			
		||||
static void close_async_socket (mio_t* mio, mio_syshnd_t sck)
 | 
			
		||||
{
 | 
			
		||||
	close (sck);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static mio_sckhnd_t open_async_socket (mio_t* mio, int domain, int type, int proto)
 | 
			
		||||
static mio_syshnd_t open_async_socket (mio_t* mio, int domain, int type, int proto)
 | 
			
		||||
{
 | 
			
		||||
	mio_sckhnd_t sck = MIO_SCKHND_INVALID;
 | 
			
		||||
	mio_syshnd_t sck = MIO_SYSHND_INVALID;
 | 
			
		||||
	int flags;
 | 
			
		||||
 | 
			
		||||
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
 | 
			
		||||
	type |= SOCK_NONBLOCK;
 | 
			
		||||
	type |= SOCK_CLOEXEC;
 | 
			
		||||
	type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
 | 
			
		||||
open_socket:
 | 
			
		||||
#endif
 | 
			
		||||
	sck = socket(domain, type, proto); 
 | 
			
		||||
	if (sck == MIO_SCKHND_INVALID) 
 | 
			
		||||
	if (sck == MIO_SYSHND_INVALID) 
 | 
			
		||||
	{
 | 
			
		||||
	#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
 | 
			
		||||
		if (errno == EINVAL && (type & (SOCK_NONBLOCK | SOCK_CLOEXEC)))
 | 
			
		||||
@ -117,23 +112,96 @@ open_socket:
 | 
			
		||||
	#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flags = fcntl(sck, F_GETFD, 0);
 | 
			
		||||
	if (flags == -1) goto oops;
 | 
			
		||||
#if defined(FD_CLOEXEC)
 | 
			
		||||
	flags |= FD_CLOEXEC;
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(O_NONBLOCK)
 | 
			
		||||
	flags |= O_NONBLOCK;
 | 
			
		||||
#endif
 | 
			
		||||
	if (fcntl(sck, F_SETFD, flags) == -1) goto oops;
 | 
			
		||||
	if (mio_makesyshndasync(mio, sck) <= -1 ||
 | 
			
		||||
	    mio_makesyshndcloexec(mio, sck) <= -1) goto oops;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	return sck;
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	if (sck != MIO_SCKHND_INVALID) close (sck);
 | 
			
		||||
	if (sck != MIO_SYSHND_INVALID) close (sck);
 | 
			
		||||
	mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
	return MIO_SCKHND_INVALID;
 | 
			
		||||
	return MIO_SYSHND_INVALID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static mio_syshnd_t open_async_qx (mio_t* mio, mio_syshnd_t* side_chan)
 | 
			
		||||
{
 | 
			
		||||
	int fd[2];
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
	int type = SOCK_DGRAM;
 | 
			
		||||
 | 
			
		||||
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
 | 
			
		||||
	type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
 | 
			
		||||
open_socket:
 | 
			
		||||
#endif
 | 
			
		||||
	if (socketpair(AF_UNIX, type, 0, fd) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
	#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
 | 
			
		||||
		if (errno == EINVAL && (type & (SOCK_NONBLOCK | SOCK_CLOEXEC)))
 | 
			
		||||
		{
 | 
			
		||||
			type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
 | 
			
		||||
			goto open_socket;
 | 
			
		||||
		}
 | 
			
		||||
	#endif
 | 
			
		||||
		return MIO_SYSHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
	#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
 | 
			
		||||
		if (type & (SOCK_NONBLOCK | SOCK_CLOEXEC)) goto done;
 | 
			
		||||
	#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mio_makesyshndasync(mio, fd[0]) <= -1 ||
 | 
			
		||||
	    mio_makesyshndasync(mio, fd[1]) <= -1 ||
 | 
			
		||||
	    mio_makesyshndcloexec(mio, fd[0]) <= -1 ||
 | 
			
		||||
	    mio_makesyshndcloexec(mio, fd[1]) <= -1) 
 | 
			
		||||
	{
 | 
			
		||||
		close (fd[0]);
 | 
			
		||||
		close (fd[1]);
 | 
			
		||||
		return MIO_SYSHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	*side_chan = fd[1]; /* write end of the pipe */
 | 
			
		||||
	return fd[0]; /* read end of the pipe */
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_PIPE2)
 | 
			
		||||
	/* in linux 3.4 or higher, O_DIRECT can make the pipes work in the packet mode if the data size is <= PIPE_BUF */
 | 
			
		||||
	if (pipe2(fd, O_CLOEXEC | O_NONBLOCK) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		if  (errno == ENOSYS) goto normal_pipe;
 | 
			
		||||
		mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
		return MIO_SYSHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
	goto done;
 | 
			
		||||
 | 
			
		||||
normal_pipe:
 | 
			
		||||
#endif
 | 
			
		||||
	if (pipe(fd) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
		return MIO_SYSHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mio_makesyshndasync(mio, fd[0]) <= -1 ||
 | 
			
		||||
	    mio_makesyshndasync(mio, fd[1]) <= -1 ||
 | 
			
		||||
	    mio_makesyshndcloexec(mio, fd[0]) <= -1 ||
 | 
			
		||||
	    mio_makesyshndcloexec(mio, fd[1]) <= -1) 
 | 
			
		||||
	{
 | 
			
		||||
		close (fd[0]);
 | 
			
		||||
		close (fd[1]);
 | 
			
		||||
		return MIO_SYSHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_PIPE2)
 | 
			
		||||
done:
 | 
			
		||||
#endif
 | 
			
		||||
	*side_chan = fd[1]; /* write end of the pipe */
 | 
			
		||||
	return fd[0]; /* read end of the pipe */
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
@ -167,8 +235,13 @@ struct sck_type_map_t
 | 
			
		||||
	int extra_dev_cap;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define __AF_QX 999999
 | 
			
		||||
 | 
			
		||||
static struct sck_type_map_t sck_type_map[] =
 | 
			
		||||
{
 | 
			
		||||
	/* MIO_DEV_SCK_QX */
 | 
			
		||||
	{ __AF_QX,    0,              0,                         0 },
 | 
			
		||||
 | 
			
		||||
	/* MIO_DEV_SCK_TCP4 */
 | 
			
		||||
	{ AF_INET,    SOCK_STREAM,    0,                         MIO_DEV_CAP_STREAM },
 | 
			
		||||
 | 
			
		||||
@ -176,10 +249,10 @@ static struct sck_type_map_t sck_type_map[] =
 | 
			
		||||
	{ AF_INET6,   SOCK_STREAM,    0,                         MIO_DEV_CAP_STREAM },
 | 
			
		||||
 | 
			
		||||
	/* MIO_DEV_SCK_UPD4 */
 | 
			
		||||
	{ AF_INET,    SOCK_DGRAM,     0,                         0                                                },
 | 
			
		||||
	{ AF_INET,    SOCK_DGRAM,     0,                         0                                             },
 | 
			
		||||
 | 
			
		||||
	/* MIO_DEV_SCK_UDP6 */
 | 
			
		||||
	{ AF_INET6,   SOCK_DGRAM,     0,                         0                                                },
 | 
			
		||||
	{ AF_INET6,   SOCK_DGRAM,     0,                         0                                             },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if defined(AF_PACKET) && (MIO_SIZEOF_STRUCT_SOCKADDR_LL > 0)
 | 
			
		||||
@ -196,15 +269,26 @@ static struct sck_type_map_t sck_type_map[] =
 | 
			
		||||
	/* MIO_DEV_SCK_ARP_DGRAM */
 | 
			
		||||
	{ AF_LINK,  SOCK_DGRAM,       MIO_CONST_HTON16(MIO_ETHHDR_PROTO_ARP), 0                                 },
 | 
			
		||||
#else
 | 
			
		||||
	{ -1,       0,                0,                            0                                             },
 | 
			
		||||
	{ -1,       0,                0,                            0                                             },
 | 
			
		||||
	{ -1,       0,                0,                         0                                              },
 | 
			
		||||
	{ -1,       0,                0,                         0                                              },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* MIO_DEV_SCK_ICMP4 - IP protocol field is 1 byte only. no byte order conversion is needed */
 | 
			
		||||
	{ AF_INET,    SOCK_RAW,       IPPROTO_ICMP,              0,                                               },
 | 
			
		||||
	{ AF_INET,    SOCK_RAW,       IPPROTO_ICMP,              0,                                             },
 | 
			
		||||
 | 
			
		||||
	/* MIO_DEV_SCK_ICMP6 - IP protocol field is 1 byte only. no byte order conversion is needed */
 | 
			
		||||
	{ AF_INET6,   SOCK_RAW,       IPPROTO_ICMP,              0,                                               }
 | 
			
		||||
	{ AF_INET6,   SOCK_RAW,       IPPROTO_ICMP,              0,                                             },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if defined(AF_PACKET) && (MIO_SIZEOF_STRUCT_SOCKADDR_LL > 0)
 | 
			
		||||
	/* MIO_DEV_SCK_PACKET */
 | 
			
		||||
	{ AF_PACKET,  SOCK_RAW,       MIO_CONST_HTON16(ETH_P_ALL),            0                                 },
 | 
			
		||||
#elif defined(AF_LINK) && (MIO_SIZEOF_STRUCT_SOCKADDR_DL > 0)
 | 
			
		||||
	/* MIO_DEV_SCK_PACKET */
 | 
			
		||||
	{ AF_PACKET,  SOCK_RAW,       MIO_CONST_HTON16(ETH_P_ALL),            0                                 },
 | 
			
		||||
#else
 | 
			
		||||
	{ -1,       0,                0,                         0                                              },
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
@ -294,6 +378,8 @@ static int dev_sck_make (mio_dev_t* dev, void* ctx)
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
	mio_dev_sck_t* rdev = (mio_dev_sck_t*)dev;
 | 
			
		||||
	mio_dev_sck_make_t* arg = (mio_dev_sck_make_t*)ctx;
 | 
			
		||||
	mio_syshnd_t hnd = MIO_SYSHND_INVALID;
 | 
			
		||||
	mio_syshnd_t side_chan = MIO_SYSHND_INVALID;
 | 
			
		||||
 | 
			
		||||
	MIO_ASSERT (mio, arg->type >= 0 && arg->type < MIO_COUNTOF(sck_type_map));
 | 
			
		||||
 | 
			
		||||
@ -303,9 +389,38 @@ static int dev_sck_make (mio_dev_t* dev, void* ctx)
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rdev->hnd = open_async_socket(mio, sck_type_map[arg->type].domain, sck_type_map[arg->type].type, sck_type_map[arg->type].proto);
 | 
			
		||||
	if (rdev->hnd == MIO_SCKHND_INVALID) goto oops;
 | 
			
		||||
	if (arg->options & MIO_DEV_SCK_MAKE_IMPSYSHND)
 | 
			
		||||
	{
 | 
			
		||||
		/* Make sure to pass a proper type for a given socket handle when you use MIO_DEV_SCK_MAKE_IMPSYSHND.
 | 
			
		||||
		 * Otherwise, some innerworking of the library may go wrong */
 | 
			
		||||
		if (sck_type_map[arg->type].domain == __AF_QX)
 | 
			
		||||
		{
 | 
			
		||||
			/* can't import a handle of this type */
 | 
			
		||||
			mio_seterrnum (mio, MIO_EINVAL); 
 | 
			
		||||
			goto oops;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		hnd = arg->syshnd;
 | 
			
		||||
		if (hnd == MIO_SYSHND_INVALID)
 | 
			
		||||
		{
 | 
			
		||||
			mio_seterrnum (mio, MIO_EINVAL); 
 | 
			
		||||
			goto oops;
 | 
			
		||||
		}
 | 
			
		||||
		if (mio_makesyshndasync(mio, hnd) <= -1) goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	else if (sck_type_map[arg->type].domain == __AF_QX)
 | 
			
		||||
	{
 | 
			
		||||
		hnd = open_async_qx(mio, &side_chan);
 | 
			
		||||
		if (hnd == MIO_SYSHND_INVALID) goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		hnd = open_async_socket(mio, sck_type_map[arg->type].domain, sck_type_map[arg->type].type, sck_type_map[arg->type].proto);
 | 
			
		||||
		if (hnd == MIO_SYSHND_INVALID) goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rdev->hnd = hnd;
 | 
			
		||||
	rdev->side_chan = side_chan;
 | 
			
		||||
	rdev->dev_cap = MIO_DEV_CAP_IN | MIO_DEV_CAP_OUT | sck_type_map[arg->type].extra_dev_cap;
 | 
			
		||||
	rdev->on_write = arg->on_write;
 | 
			
		||||
	rdev->on_read = arg->on_read;
 | 
			
		||||
@ -317,11 +432,8 @@ static int dev_sck_make (mio_dev_t* dev, void* ctx)
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	if (rdev->hnd != MIO_SCKHND_INVALID)
 | 
			
		||||
	{
 | 
			
		||||
		close_async_socket (mio, rdev->hnd);
 | 
			
		||||
		rdev->hnd = MIO_SCKHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
	if (hnd != MIO_SYSHND_INVALID) close_async_socket (mio, hnd);
 | 
			
		||||
	if (side_chan != MIO_SYSHND_INVALID) close (rdev->side_chan);
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -340,18 +452,8 @@ static int dev_sck_make_client (mio_dev_t* dev, void* ctx)
 | 
			
		||||
	rdev->hnd = *clisckhnd;
 | 
			
		||||
	rdev->tmrjob_index = MIO_TMRIDX_INVALID;
 | 
			
		||||
 | 
			
		||||
	if (mio_makesckasync(mio, rdev->hnd) <= -1) return -1;
 | 
			
		||||
#if defined(FD_CLOEXEC)
 | 
			
		||||
	{
 | 
			
		||||
		int flags = fcntl(rdev->hnd, F_GETFD, 0);
 | 
			
		||||
		if (fcntl(rdev->hnd, F_SETFD, flags | FD_CLOEXEC) == -1)
 | 
			
		||||
		{
 | 
			
		||||
			mio_seterrbfmtwithsyserr (mio, 0, errno, "unable to set FD_CLOEXEC");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (mio_makesyshndasync(mio, rdev->hnd) <= -1 ||
 | 
			
		||||
	    mio_makesyshndcloexec(mio, rdev->hnd) <= -1) return -1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -398,12 +500,17 @@ static int dev_sck_kill (mio_dev_t* dev, int force)
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (rdev->hnd != MIO_SCKHND_INVALID) 
 | 
			
		||||
	if (rdev->hnd != MIO_SYSHND_INVALID) 
 | 
			
		||||
	{
 | 
			
		||||
		close_async_socket (mio, rdev->hnd);
 | 
			
		||||
		rdev->hnd = MIO_SCKHND_INVALID;
 | 
			
		||||
		rdev->hnd = MIO_SYSHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rdev->side_chan != MIO_SYSHND_INVALID)
 | 
			
		||||
	{
 | 
			
		||||
		close (rdev->hnd);
 | 
			
		||||
		rdev->hnd = MIO_SYSHND_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1255,6 +1362,7 @@ static mio_dev_mth_t dev_mth_clisck =
 | 
			
		||||
	dev_sck_sendfile_stateful,
 | 
			
		||||
	dev_sck_ioctl
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
static int harvest_outgoing_connection (mio_dev_sck_t* rdev)
 | 
			
		||||
@ -1349,55 +1457,23 @@ static int harvest_outgoing_connection (mio_dev_sck_t* rdev)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int accept_incoming_connection (mio_dev_sck_t* rdev)
 | 
			
		||||
static int make_accepted_client_connection (mio_dev_sck_t* rdev, mio_syshnd_t clisck, mio_skad_t* remoteaddr)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = rdev->mio;
 | 
			
		||||
	mio_sckhnd_t clisck;
 | 
			
		||||
	mio_skad_t remoteaddr;
 | 
			
		||||
	mio_scklen_t addrlen;
 | 
			
		||||
	mio_dev_sck_t* clidev;
 | 
			
		||||
	int flags;
 | 
			
		||||
	mio_scklen_t addrlen;
 | 
			
		||||
 | 
			
		||||
	/* this is a server(lisening) socket */
 | 
			
		||||
 | 
			
		||||
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) && defined(HAVE_ACCEPT4)
 | 
			
		||||
	flags = SOCK_NONBLOCK | SOCK_CLOEXEC;
 | 
			
		||||
 | 
			
		||||
	addrlen = MIO_SIZEOF(remoteaddr);
 | 
			
		||||
	clisck = accept4(rdev->hnd, (struct sockaddr*)&remoteaddr, &addrlen, flags);
 | 
			
		||||
	if (clisck == MIO_SCKHND_INVALID)
 | 
			
		||||
	if (rdev->on_raw_accept)
 | 
			
		||||
	{
 | 
			
		||||
		 if (errno != ENOSYS)
 | 
			
		||||
		 {
 | 
			
		||||
			if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
 | 
			
		||||
			if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */
 | 
			
		||||
 | 
			
		||||
			mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
			return -1;
 | 
			
		||||
		 }
 | 
			
		||||
 | 
			
		||||
		 // go on for the normal 3-parameter accept
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		 goto accept_done;
 | 
			
		||||
		/* this is a special optional callback. If you don't want a client socket device 
 | 
			
		||||
		 * to be created upon accept, you may implement the on_raw_accept() handler. 
 | 
			
		||||
		 * the socket handle is delated to the callback. */
 | 
			
		||||
		rdev->on_raw_accept (rdev, clisck);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
	addrlen = MIO_SIZEOF(remoteaddr);
 | 
			
		||||
	clisck = accept(rdev->hnd, (struct sockaddr*)&remoteaddr, &addrlen);
 | 
			
		||||
	if (clisck == MIO_SCKHND_INVALID)
 | 
			
		||||
	{
 | 
			
		||||
		if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
 | 
			
		||||
		if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */
 | 
			
		||||
 | 
			
		||||
		mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
accept_done:
 | 
			
		||||
	/* use rdev->dev_size when instantiating a client sck device
 | 
			
		||||
	 * instead of MIO_SIZEOF(mio_dev_sck_t). therefore, the 
 | 
			
		||||
	 * instead of MIO_SIZEOF(mio_dev_sck_t). therefore, the  
 | 
			
		||||
	 * extension area as big as that of the master sck device
 | 
			
		||||
	 * is created in the client sck device */
 | 
			
		||||
	clidev = (mio_dev_sck_t*)mio_dev_make(mio, rdev->dev_size, &dev_mth_clisck, rdev->dev_evcb, &clisck); 
 | 
			
		||||
@ -1407,10 +1483,14 @@ accept_done:
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
// TODO:
 | 
			
		||||
//if (clidev->type == MIO_DEV_SCK_QX) change it to the specified type..
 | 
			
		||||
// TODO:
 | 
			
		||||
 | 
			
		||||
	MIO_ASSERT (mio, clidev->hnd == clisck);
 | 
			
		||||
 | 
			
		||||
	clidev->dev_cap |= MIO_DEV_CAP_IN | MIO_DEV_CAP_OUT | MIO_DEV_CAP_STREAM;
 | 
			
		||||
	clidev->remoteaddr = remoteaddr;
 | 
			
		||||
	clidev->remoteaddr = *remoteaddr;
 | 
			
		||||
 | 
			
		||||
	addrlen = MIO_SIZEOF(clidev->localaddr);
 | 
			
		||||
	if (getsockname(clisck, (struct sockaddr*)&clidev->localaddr, &addrlen) == -1) clidev->localaddr = rdev->localaddr;
 | 
			
		||||
@ -1491,6 +1571,55 @@ accept_done:
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int accept_incoming_connection (mio_dev_sck_t* rdev)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = rdev->mio;
 | 
			
		||||
	mio_syshnd_t clisck;
 | 
			
		||||
	mio_skad_t remoteaddr;
 | 
			
		||||
	mio_scklen_t addrlen;
 | 
			
		||||
	int flags;
 | 
			
		||||
 | 
			
		||||
	/* this is a server(lisening) socket */
 | 
			
		||||
 | 
			
		||||
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) && defined(HAVE_ACCEPT4)
 | 
			
		||||
	flags = SOCK_NONBLOCK | SOCK_CLOEXEC;
 | 
			
		||||
 | 
			
		||||
	addrlen = MIO_SIZEOF(remoteaddr);
 | 
			
		||||
	clisck = accept4(rdev->hnd, (struct sockaddr*)&remoteaddr, &addrlen, flags);
 | 
			
		||||
	if (clisck <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		 if (errno != ENOSYS)
 | 
			
		||||
		 {
 | 
			
		||||
			if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
 | 
			
		||||
			if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */
 | 
			
		||||
 | 
			
		||||
			mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
			return -1;
 | 
			
		||||
		 }
 | 
			
		||||
 | 
			
		||||
		 /* go on for the normal 3-parameter accept */
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		 goto accept_done;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
	addrlen = MIO_SIZEOF(remoteaddr);
 | 
			
		||||
	clisck = accept(rdev->hnd, (struct sockaddr*)&remoteaddr, &addrlen);
 | 
			
		||||
	if (clisck <=  -1)
 | 
			
		||||
	{
 | 
			
		||||
		if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
 | 
			
		||||
		if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */
 | 
			
		||||
 | 
			
		||||
		mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
accept_done:
 | 
			
		||||
	return make_accepted_client_connection (rdev, clisck, &remoteaddr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dev_evcb_sck_ready_stateful (mio_dev_t* dev, int events)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
@ -1686,7 +1815,7 @@ static int dev_evcb_sck_ready_stateless (mio_dev_t* dev, int events)
 | 
			
		||||
		mio_scklen_t len;
 | 
			
		||||
 | 
			
		||||
		len = MIO_SIZEOF(errcode);
 | 
			
		||||
		if (getsockopt (rdev->hnd, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1)
 | 
			
		||||
		if (getsockopt(rdev->hnd, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1)
 | 
			
		||||
		{
 | 
			
		||||
			/* the error number is set to the socket error code.
 | 
			
		||||
			 * errno resulting from getsockopt() doesn't reflect the actual
 | 
			
		||||
@ -1733,6 +1862,8 @@ static int dev_evcb_sck_on_write_stateless (mio_dev_t* dev, mio_iolen_t wrlen, v
 | 
			
		||||
	return rdev->on_write(rdev, wrlen, wrctx, dstaddr->ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
static mio_dev_evcb_t dev_sck_event_callbacks_stateful =
 | 
			
		||||
{
 | 
			
		||||
	dev_evcb_sck_ready_stateful,
 | 
			
		||||
@ -1746,6 +1877,86 @@ static mio_dev_evcb_t dev_sck_event_callbacks_stateless =
 | 
			
		||||
	dev_evcb_sck_on_read_stateless,
 | 
			
		||||
	dev_evcb_sck_on_write_stateless
 | 
			
		||||
};
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
static int dev_evcb_sck_ready_qx (mio_dev_t* dev, int events)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
	mio_dev_sck_t* rdev = (mio_dev_sck_t*)dev;
 | 
			
		||||
 | 
			
		||||
	if (events & MIO_DEV_EVENT_ERR)
 | 
			
		||||
	{
 | 
			
		||||
		int errcode;
 | 
			
		||||
		mio_scklen_t len;
 | 
			
		||||
 | 
			
		||||
		len = MIO_SIZEOF(errcode);
 | 
			
		||||
		if (getsockopt(rdev->hnd, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1)
 | 
			
		||||
		{
 | 
			
		||||
			/* the error number is set to the socket error code.
 | 
			
		||||
			 * errno resulting from getsockopt() doesn't reflect the actual
 | 
			
		||||
			 * socket error. so errno is not used to set the error number.
 | 
			
		||||
			 * instead, the generic device error MIO_EDEVERRR is used */
 | 
			
		||||
			mio_seterrbfmt (mio, MIO_EDEVERR, "device error - unable to get SO_ERROR");
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			mio_seterrwithsyserr (rdev->mio, 0, errcode);
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	else if (events & MIO_DEV_EVENT_HUP)
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrnum (mio, MIO_EDEVHUP);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1; /* the device is ok. carry on reading or writing */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int dev_evcb_sck_on_read_qx (mio_dev_t* dev, const void* data, mio_iolen_t dlen, const mio_devaddr_t* srcaddr)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
	mio_dev_sck_t* rdev = (mio_dev_sck_t*)dev;
 | 
			
		||||
	mio_dev_sck_qxmsg_t* qxmsg;
 | 
			
		||||
 | 
			
		||||
	if (dlen != MIO_SIZEOF(*qxmsg))
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrbfmt (mio, MIO_EINVAL, "wrong qx packet size");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	qxmsg = (mio_dev_sck_qxmsg_t*)data;
 | 
			
		||||
	if (qxmsg->cmd == MIO_DEV_SCK_QXMSG_NEWCONN)
 | 
			
		||||
	{
 | 
			
		||||
		if (make_accepted_client_connection(rdev, qxmsg->syshnd, &qxmsg->remoteaddr) <= -1) 
 | 
			
		||||
		{
 | 
			
		||||
			close (qxmsg->syshnd);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrbfmt (mio, MIO_EINVAL, "wrong qx command code");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dev_evcb_sck_on_write_qx (mio_dev_t* dev, mio_iolen_t wrlen, void* wrctx, const mio_devaddr_t* dstaddr)
 | 
			
		||||
{
 | 
			
		||||
	/*mio_dev_sck_t* rdev = (mio_dev_sck_t*)dev;*/
 | 
			
		||||
	/* this should not be called */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static mio_dev_evcb_t dev_sck_event_callbacks_qx =
 | 
			
		||||
{
 | 
			
		||||
	dev_evcb_sck_ready_qx,
 | 
			
		||||
	dev_evcb_sck_on_read_qx,
 | 
			
		||||
	dev_evcb_sck_on_write_qx
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
@ -1759,7 +1970,13 @@ mio_dev_sck_t* mio_dev_sck_make (mio_t* mio, mio_oow_t xtnsize, const mio_dev_sc
 | 
			
		||||
		return MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sck_type_map[info->type].extra_dev_cap & MIO_DEV_CAP_STREAM) /* can't use the IS_STATEFUL() macro yet */
 | 
			
		||||
	if (info->type == MIO_DEV_SCK_QX)
 | 
			
		||||
	{
 | 
			
		||||
		rdev = (mio_dev_sck_t*)mio_dev_make(
 | 
			
		||||
			mio, MIO_SIZEOF(mio_dev_sck_t) + xtnsize,
 | 
			
		||||
			&dev_sck_methods_stateless, &dev_sck_event_callbacks_qx, (void*)info);
 | 
			
		||||
	}
 | 
			
		||||
	else if (sck_type_map[info->type].extra_dev_cap & MIO_DEV_CAP_STREAM) /* can't use the IS_STATEFUL() macro yet */
 | 
			
		||||
	{
 | 
			
		||||
		rdev = (mio_dev_sck_t*)mio_dev_make(
 | 
			
		||||
			mio, MIO_SIZEOF(mio_dev_sck_t) + xtnsize,
 | 
			
		||||
@ -1858,6 +2075,18 @@ int mio_dev_sck_sendfileok (mio_dev_sck_t* dev)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_dev_sck_writetosidechan (mio_dev_sck_t* dev, const void* dptr, mio_oow_t dlen)
 | 
			
		||||
{
 | 
			
		||||
	if (dev->side_chan == MIO_SYSHND_INVALID)
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrnum (dev->mio, MIO_ENOCAPA);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	write (dev->side_chan, dptr, dlen);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
mio_uint16_t mio_checksum_ip (const void* hdr, mio_oow_t len)
 | 
			
		||||
 | 
			
		||||
@ -41,13 +41,36 @@ int mio_sys_initmux (mio_t* mio)
 | 
			
		||||
	mio_sys_mux_t* mux = &mio->sysdep->mux;
 | 
			
		||||
 | 
			
		||||
#if defined(USE_EPOLL)
 | 
			
		||||
	mux->hnd = epoll_create(1000); /* TODO: choose proper initial size? */
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_EPOLL_CREATE1)
 | 
			
		||||
	mux->hnd = epoll_create1(O_CLOEXEC);
 | 
			
		||||
	if (mux->hnd == -1)
 | 
			
		||||
	{
 | 
			
		||||
		if (errno == ENOSYS) goto normal_epoll_create; /* kernel doesn't support it */
 | 
			
		||||
		mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	goto epoll_create_done;
 | 
			
		||||
 | 
			
		||||
normal_epoll_create:
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	mux->hnd = epoll_create(16384); /* TODO: choose proper initial size? */
 | 
			
		||||
	if (mux->hnd == -1)
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(FD_CLOEXEC)
 | 
			
		||||
	{
 | 
			
		||||
		int flags = fcntl(mux->hnd, F_GETFD, 0);
 | 
			
		||||
		if (flags >= 0) fcntl(mux->hnd, F_SETFD, flags | FD_CLOEXEC);
 | 
			
		||||
	}
 | 
			
		||||
#endif /* FD_CLOEXEC */
 | 
			
		||||
 | 
			
		||||
epoll_create_done:
 | 
			
		||||
#endif /* USE_EPOLL */
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@ -254,7 +277,7 @@ int mio_sys_ctrlmux (mio_t* mio, mio_sys_mux_cmd_t cmd, mio_dev_t* dev, int dev_
 | 
			
		||||
	}
 | 
			
		||||
	if (dev_cap & MIO_DEV_CAP_OUT_WATCHED) events |= EPOLLOUT;
 | 
			
		||||
 | 
			
		||||
	ev.events = events | EPOLLHUP | EPOLLERR /*| EPOLLET*/;
 | 
			
		||||
	ev.events = events | EPOLLHUP | EPOLLERR /*| EPOLLET*/; /* TODO: ready to support edge-trigger? */
 | 
			
		||||
	ev.data.ptr = dev;
 | 
			
		||||
 | 
			
		||||
	switch (cmd)
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ struct mio_sys_mux_t
 | 
			
		||||
struct mio_sys_mux_t
 | 
			
		||||
{
 | 
			
		||||
	int hnd;
 | 
			
		||||
	struct epoll_event revs[128]; /* TODO: is it a good size? */
 | 
			
		||||
	struct epoll_event revs[1024]; /* TODO: is it a good size? */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -90,3 +90,22 @@ int mio_makesyshndasync (mio_t* mio, mio_syshnd_t hnd)
 | 
			
		||||
	return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_makesyshndcloexec (mio_t* mio, mio_syshnd_t hnd)
 | 
			
		||||
{
 | 
			
		||||
#if defined(F_GETFL) && defined(F_SETFL) && defined(FD_CLOEXEC)
 | 
			
		||||
	int flags;
 | 
			
		||||
 | 
			
		||||
	if ((flags = fcntl(hnd, F_GETFD)) <= -1 ||
 | 
			
		||||
	    (flags = fcntl(hnd, F_SETFD, flags | FD_CLOEXEC)) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrwithsyserr (mio, 0, errno);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
#else
 | 
			
		||||
	mio_seterrnum (mio, MIO_ENOIMPL);
 | 
			
		||||
	return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user