deleted more system dependent code from qse_httpd_t
This commit is contained in:
parent
8b95a1d26c
commit
6c8755de00
@ -39,21 +39,6 @@ struct qse_ipad6_t
|
|||||||
};
|
};
|
||||||
#include <qse/unpack.h>
|
#include <qse/unpack.h>
|
||||||
|
|
||||||
struct qse_ipad_t
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
QSE_IPAD_V4,
|
|
||||||
QSE_IPAD_V6
|
|
||||||
} type;
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
qse_ipad4_t v4;
|
|
||||||
qse_ipad6_t v6;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -52,6 +52,22 @@ struct qse_nwad_t
|
|||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum qse_nwadtostr_flag_t
|
||||||
|
{
|
||||||
|
QSE_NWADTOSTR_ADDR = (1 << 0),
|
||||||
|
#define QSE_NWADTOMBS_ADDR QSE_NWADTOSTR_ADDR
|
||||||
|
#define QSE_NWADTOWCS_ADDR QSE_NWADTOSTR_ADDR
|
||||||
|
|
||||||
|
QSE_NWADTOSTR_PORT = (1 << 1),
|
||||||
|
#define QSE_NWADTOMBS_PORT QSE_NWADTOSTR_PORT
|
||||||
|
#define QSE_NWADTOWCS_PORT QSE_NWADTOSTR_PORT
|
||||||
|
|
||||||
|
QSE_NWADTOSTR_ALL = (QSE_NWADTOSTR_ADDR | QSE_NWADTOSTR_PORT)
|
||||||
|
#define QSE_NWADTOMBS_ALL QSE_NWADTOSTR_ALL
|
||||||
|
#define QSE_NWADTOWCS_ALL QSE_NWADTOSTR_ALL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -81,23 +97,25 @@ int qse_wcsntonwad (
|
|||||||
qse_size_t qse_nwadtombs (
|
qse_size_t qse_nwadtombs (
|
||||||
const qse_nwad_t* nwad,
|
const qse_nwad_t* nwad,
|
||||||
qse_mchar_t* mbs,
|
qse_mchar_t* mbs,
|
||||||
qse_size_t len
|
qse_size_t len,
|
||||||
|
int flags
|
||||||
);
|
);
|
||||||
|
|
||||||
qse_size_t qse_nwadtowcs (
|
qse_size_t qse_nwadtowcs (
|
||||||
const qse_nwad_t* nwad,
|
const qse_nwad_t* nwad,
|
||||||
qse_wchar_t* wcs,
|
qse_wchar_t* wcs,
|
||||||
qse_size_t len
|
qse_size_t len,
|
||||||
|
int flags
|
||||||
);
|
);
|
||||||
|
|
||||||
#if defined(QSE_CHAR_IS_MCHAR)
|
#if defined(QSE_CHAR_IS_MCHAR)
|
||||||
# define qse_strtonwad(ptr,nwad) qse_mbstonwad(ptr,nwad)
|
# define qse_strtonwad(ptr,nwad) qse_mbstonwad(ptr,nwad)
|
||||||
# define qse_strntonwad(ptr,len,nwad) qse_mbsntonwad(ptr,len,nwad)
|
# define qse_strntonwad(ptr,len,nwad) qse_mbsntonwad(ptr,len,nwad)
|
||||||
# define qse_nwadtostr(nwad,ptr,len) qse_nwadtombs(nwad,ptr,len)
|
# define qse_nwadtostr(nwad,ptr,len,flags) qse_nwadtombs(nwad,ptr,len,flags)
|
||||||
#else
|
#else
|
||||||
# define qse_strtonwad(ptr,nwad) qse_wcstonwad(ptr,nwad)
|
# define qse_strtonwad(ptr,nwad) qse_wcstonwad(ptr,nwad)
|
||||||
# define qse_strntonwad(ptr,len,nwad) qse_wcsntonwad(ptr,len,nwad)
|
# define qse_strntonwad(ptr,len,nwad) qse_wcsntonwad(ptr,len,nwad)
|
||||||
# define qse_nwadtostr(nwad,ptr,len) qse_nwadtowcs(nwad,ptr,len)
|
# define qse_nwadtostr(nwad,ptr,len,flags) qse_nwadtowcs(nwad,ptr,len,flags)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <qse/types.h>
|
#include <qse/types.h>
|
||||||
#include <qse/macros.h>
|
#include <qse/macros.h>
|
||||||
#include <qse/net/htre.h>
|
#include <qse/net/htre.h>
|
||||||
|
#include <qse/cmn/nwad.h>
|
||||||
#include <qse/cmn/time.h>
|
#include <qse/cmn/time.h>
|
||||||
|
|
||||||
typedef struct qse_httpd_t qse_httpd_t;
|
typedef struct qse_httpd_t qse_httpd_t;
|
||||||
@ -32,17 +33,25 @@ typedef struct qse_httpd_client_t qse_httpd_client_t;
|
|||||||
enum qse_httpd_errnum_t
|
enum qse_httpd_errnum_t
|
||||||
{
|
{
|
||||||
QSE_HTTPD_ENOERR,
|
QSE_HTTPD_ENOERR,
|
||||||
|
|
||||||
QSE_HTTPD_ENOMEM,
|
QSE_HTTPD_ENOMEM,
|
||||||
QSE_HTTPD_EINVAL,
|
QSE_HTTPD_EINVAL,
|
||||||
QSE_HTTPD_ENOENT,
|
|
||||||
QSE_HTTPD_EACCES,
|
QSE_HTTPD_EACCES,
|
||||||
QSE_HTTPD_EINTERN,
|
QSE_HTTPD_ENOENT,
|
||||||
|
QSE_HTTPD_EEXIST,
|
||||||
|
QSE_HTTPD_EINTR,
|
||||||
|
QSE_HTTPD_EAGAIN,
|
||||||
|
|
||||||
QSE_HTTPD_EIOMUX,
|
QSE_HTTPD_EIOMUX,
|
||||||
QSE_HTTPD_ESUBSYS,
|
|
||||||
QSE_HTTPD_ESOCKET,
|
|
||||||
QSE_HTTPD_EDISCON, /* client disconnnected */
|
QSE_HTTPD_EDISCON, /* client disconnnected */
|
||||||
QSE_HTTPD_EBADREQ, /* bad request */
|
QSE_HTTPD_EBADREQ, /* bad request */
|
||||||
QSE_HTTPD_ETASK
|
QSE_HTTPD_ETASK,
|
||||||
|
|
||||||
|
QSE_HTTPD_EINTERN,
|
||||||
|
QSE_HTTPD_ESYSERR,
|
||||||
|
QSE_HTTPD_ENOIMPL,
|
||||||
|
|
||||||
|
QSE_HTTPD_EOTHER
|
||||||
};
|
};
|
||||||
typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
|
typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
|
||||||
|
|
||||||
@ -60,9 +69,28 @@ struct qse_httpd_stat_t
|
|||||||
const qse_mchar_t* mime;
|
const qse_mchar_t* mime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct qse_httpd_server_t qse_httpd_server_t;
|
||||||
|
struct qse_httpd_server_t
|
||||||
|
{
|
||||||
|
qse_httpd_server_t* next;
|
||||||
|
|
||||||
|
qse_nwad_t nwad;
|
||||||
|
int secure;
|
||||||
|
|
||||||
|
/* set by server.open callback */
|
||||||
|
qse_ubi_t handle;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
|
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
|
||||||
struct qse_httpd_cbs_t
|
struct qse_httpd_cbs_t
|
||||||
{
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int (*open) (qse_httpd_t* httpd, qse_httpd_server_t* server);
|
||||||
|
void (*close) (qse_httpd_t* httpd, qse_httpd_server_t* server);
|
||||||
|
int (*accept) (qse_httpd_t* httpd, qse_httpd_server_t* server, qse_httpd_client_t* client);
|
||||||
|
} server;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int (*readable) (
|
int (*readable) (
|
||||||
@ -98,16 +126,27 @@ struct qse_httpd_cbs_t
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
void (*close) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client);
|
||||||
|
|
||||||
|
void (*shutdown) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client);
|
||||||
|
|
||||||
/* action */
|
/* action */
|
||||||
qse_ssize_t (*recv) (qse_httpd_t* httpd,
|
qse_ssize_t (*recv) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_mchar_t* buf, qse_size_t bufsize);
|
qse_mchar_t* buf, qse_size_t bufsize);
|
||||||
|
|
||||||
qse_ssize_t (*send) (qse_httpd_t* httpd,
|
qse_ssize_t (*send) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
const qse_mchar_t* buf, qse_size_t bufsize);
|
const qse_mchar_t* buf, qse_size_t bufsize);
|
||||||
|
|
||||||
qse_ssize_t (*sendfile) (qse_httpd_t* httpd,
|
qse_ssize_t (*sendfile) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_ubi_t handle, qse_foff_t* offset, qse_size_t count);
|
qse_ubi_t handle, qse_foff_t* offset, qse_size_t count);
|
||||||
|
|
||||||
@ -229,7 +268,7 @@ void qse_httpd_stop (
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
int qse_httpd_addlistener (
|
int qse_httpd_addserver (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
const qse_char_t* uri
|
const qse_char_t* uri
|
||||||
);
|
);
|
||||||
|
@ -397,140 +397,194 @@ done:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_size_t qse_nwadtombs (const qse_nwad_t* nwad, qse_mchar_t* buf, qse_size_t len)
|
qse_size_t qse_nwadtombs (
|
||||||
|
const qse_nwad_t* nwad, qse_mchar_t* buf, qse_size_t len, int flags)
|
||||||
{
|
{
|
||||||
qse_size_t xlen = 0;
|
qse_size_t xlen = 0;
|
||||||
|
|
||||||
|
/* unsupported types will result in an empty string */
|
||||||
|
|
||||||
switch (nwad->type)
|
switch (nwad->type)
|
||||||
{
|
{
|
||||||
case QSE_NWAD_IN4:
|
case QSE_NWAD_IN4:
|
||||||
if (xlen + 1 < len)
|
if (flags & QSE_NWADTOMBS_ADDR)
|
||||||
{
|
{
|
||||||
xlen = qse_ipad4tombs (&nwad->u.in4.addr, buf, len);
|
if (xlen + 1 >= len) goto done;
|
||||||
if (xlen + 1 < len && nwad->u.in4.port != 0)
|
xlen += qse_ipad4tombs (&nwad->u.in4.addr, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOMBS_PORT)
|
||||||
|
{
|
||||||
|
if (!(flags & QSE_NWADTOMBS_ADDR) ||
|
||||||
|
nwad->u.in4.port != 0)
|
||||||
{
|
{
|
||||||
buf[xlen++] = QSE_MT(':');
|
if (flags & QSE_NWADTOMBS_ADDR)
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
{
|
||||||
xlen += qse_fmtuintmaxtombs (
|
if (xlen + 1 >= len) goto done;
|
||||||
&buf[xlen], len - xlen,
|
buf[xlen++] = QSE_MT(':');
|
||||||
qse_ntoh16(nwad->u.in4.port),
|
|
||||||
10, 0, QSE_WT('\0'), QSE_NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_fmtuintmaxtombs (
|
||||||
|
&buf[xlen], len - xlen,
|
||||||
|
qse_ntoh16(nwad->u.in4.port),
|
||||||
|
10, 0, QSE_MT('\0'), QSE_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QSE_NWAD_IN6:
|
case QSE_NWAD_IN6:
|
||||||
if (xlen + 1 < len)
|
if (flags & QSE_NWADTOMBS_PORT)
|
||||||
{
|
{
|
||||||
if (nwad->u.in6.port != 0) buf[xlen++] = QSE_MT('[');
|
if (!(flags & QSE_NWADTOMBS_ADDR) ||
|
||||||
|
nwad->u.in6.port != 0)
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
{
|
||||||
xlen += qse_ipad6tombs (&nwad->u.in6.addr, buf, len);
|
if (xlen + 1 >= len) goto done;
|
||||||
if (xlen + 1 < len && nwad->u.in6.scope != 0)
|
buf[xlen++] = QSE_MT('[');
|
||||||
{
|
|
||||||
buf[xlen++] = QSE_MT('%');
|
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
|
||||||
xlen += qse_fmtuintmaxtombs (
|
|
||||||
&buf[xlen], len - xlen,
|
|
||||||
nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xlen + 1 < len && nwad->u.in6.port != 0)
|
|
||||||
{
|
|
||||||
buf[xlen++] = QSE_MT(']');
|
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
|
||||||
buf[xlen++] = QSE_MT(':');
|
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
|
||||||
xlen += qse_fmtuintmaxtombs (
|
|
||||||
&buf[xlen], len - xlen,
|
|
||||||
qse_ntoh16(nwad->u.in6.port),
|
|
||||||
10, 0, QSE_WT('\0'), QSE_NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOMBS_ADDR)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_ipad6tombs (&nwad->u.in6.addr, &buf[xlen], len - xlen);
|
||||||
|
|
||||||
|
if (nwad->u.in6.scope != 0)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
buf[xlen++] = QSE_MT('%');
|
||||||
|
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_fmtuintmaxtombs (
|
||||||
|
&buf[xlen], len - xlen,
|
||||||
|
nwad->u.in6.scope, 10, 0, QSE_MT('\0'), QSE_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOMBS_PORT)
|
||||||
|
{
|
||||||
|
if (!(flags & QSE_NWADTOMBS_ADDR) ||
|
||||||
|
nwad->u.in6.port != 0)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
buf[xlen++] = QSE_MT(']');
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOMBS_ADDR)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
buf[xlen++] = QSE_MT(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_fmtuintmaxtombs (
|
||||||
|
&buf[xlen], len - xlen,
|
||||||
|
qse_ntoh16(nwad->u.in6.port),
|
||||||
|
10, 0, QSE_MT('\0'), QSE_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xlen + 1 < len) buf[xlen] = QSE_MT('\0');
|
done:
|
||||||
|
if (xlen < len) buf[xlen] = QSE_MT('\0');
|
||||||
return xlen;
|
return xlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_size_t qse_nwadtowcs (const qse_nwad_t* nwad, qse_wchar_t* buf, qse_size_t len)
|
|
||||||
|
qse_size_t qse_nwadtowcs (
|
||||||
|
const qse_nwad_t* nwad, qse_wchar_t* buf, qse_size_t len, int flags)
|
||||||
{
|
{
|
||||||
qse_size_t xlen = 0;
|
qse_size_t xlen = 0;
|
||||||
|
|
||||||
|
/* unsupported types will result in an empty string */
|
||||||
|
|
||||||
switch (nwad->type)
|
switch (nwad->type)
|
||||||
{
|
{
|
||||||
case QSE_NWAD_IN4:
|
case QSE_NWAD_IN4:
|
||||||
if (xlen + 1 < len)
|
if (flags & QSE_NWADTOWCS_ADDR)
|
||||||
{
|
{
|
||||||
xlen = qse_ipad4towcs (&nwad->u.in4.addr, buf, len);
|
if (xlen + 1 >= len) goto done;
|
||||||
if (xlen + 1 < len && nwad->u.in4.port != 0)
|
xlen += qse_ipad4towcs (&nwad->u.in4.addr, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOWCS_PORT)
|
||||||
|
{
|
||||||
|
if (!(flags & QSE_NWADTOMBS_ADDR) ||
|
||||||
|
nwad->u.in4.port != 0)
|
||||||
{
|
{
|
||||||
buf[xlen++] = QSE_WT(':');
|
if (flags & QSE_NWADTOMBS_ADDR)
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
{
|
||||||
xlen += qse_fmtuintmaxtowcs (
|
if (xlen + 1 >= len) goto done;
|
||||||
&buf[xlen], len - xlen,
|
buf[xlen++] = QSE_WT(':');
|
||||||
qse_ntoh16(nwad->u.in4.port),
|
|
||||||
10, 0, QSE_WT('\0'), QSE_NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_fmtuintmaxtowcs (
|
||||||
|
&buf[xlen], len - xlen,
|
||||||
|
qse_ntoh16(nwad->u.in4.port),
|
||||||
|
10, 0, QSE_WT('\0'), QSE_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QSE_NWAD_IN6:
|
case QSE_NWAD_IN6:
|
||||||
if (xlen + 1 < len)
|
if (flags & QSE_NWADTOWCS_PORT)
|
||||||
{
|
{
|
||||||
if (nwad->u.in6.port != 0) buf[xlen++] = QSE_WT('[');
|
if (!(flags & QSE_NWADTOMBS_ADDR) ||
|
||||||
|
nwad->u.in6.port != 0)
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
{
|
||||||
xlen += qse_ipad6towcs (&nwad->u.in6.addr, &buf[xlen], len - xlen);
|
if (xlen + 1 >= len) goto done;
|
||||||
if (xlen + 1 < len && nwad->u.in6.scope != 0)
|
buf[xlen++] = QSE_WT('[');
|
||||||
{
|
|
||||||
buf[xlen++] = QSE_WT('%');
|
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
|
||||||
xlen += qse_fmtuintmaxtowcs (
|
|
||||||
&buf[xlen], len - xlen,
|
|
||||||
nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xlen + 1 < len && nwad->u.in6.port != 0)
|
|
||||||
{
|
|
||||||
buf[xlen++] = QSE_WT(']');
|
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
|
||||||
buf[xlen++] = QSE_WT(':');
|
|
||||||
if (xlen + 1 < len)
|
|
||||||
{
|
|
||||||
xlen += qse_fmtuintmaxtowcs (
|
|
||||||
&buf[xlen], len - xlen,
|
|
||||||
qse_ntoh16(nwad->u.in6.port),
|
|
||||||
10, 0, QSE_WT('\0'), QSE_NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOWCS_ADDR)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_ipad6towcs (&nwad->u.in6.addr, &buf[xlen], len - xlen);
|
||||||
|
|
||||||
|
if (nwad->u.in6.scope != 0)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
buf[xlen++] = QSE_WT('%');
|
||||||
|
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_fmtuintmaxtowcs (
|
||||||
|
&buf[xlen], len - xlen,
|
||||||
|
nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOWCS_PORT)
|
||||||
|
{
|
||||||
|
if (!(flags & QSE_NWADTOMBS_ADDR) ||
|
||||||
|
nwad->u.in6.port != 0)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
buf[xlen++] = QSE_WT(']');
|
||||||
|
|
||||||
|
if (flags & QSE_NWADTOMBS_ADDR)
|
||||||
|
{
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
buf[xlen++] = QSE_WT(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xlen + 1 >= len) goto done;
|
||||||
|
xlen += qse_fmtuintmaxtowcs (
|
||||||
|
&buf[xlen], len - xlen,
|
||||||
|
qse_ntoh16(nwad->u.in6.port),
|
||||||
|
10, 0, QSE_WT('\0'), QSE_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
if (xlen < len) buf[xlen] = QSE_WT('\0');
|
if (xlen < len) buf[xlen] = QSE_WT('\0');
|
||||||
return xlen;
|
return xlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ libqsenet_la_SOURCES = \
|
|||||||
htrd.c \
|
htrd.c \
|
||||||
httpd.h \
|
httpd.h \
|
||||||
httpd.c \
|
httpd.c \
|
||||||
httpd_task.c
|
httpd-task.c
|
||||||
|
|
||||||
libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
|
libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
|
||||||
libqsenet_la_LIBADD = -lqsecmn
|
libqsenet_la_LIBADD = -lqsecmn
|
||||||
|
@ -73,7 +73,7 @@ am__installdirs = "$(DESTDIR)$(libdir)"
|
|||||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||||
libqsenet_la_DEPENDENCIES =
|
libqsenet_la_DEPENDENCIES =
|
||||||
am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \
|
am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \
|
||||||
httpd_task.lo
|
httpd-task.lo
|
||||||
libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS)
|
libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS)
|
||||||
libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||||
@ -255,7 +255,7 @@ libqsenet_la_SOURCES = \
|
|||||||
htrd.c \
|
htrd.c \
|
||||||
httpd.h \
|
httpd.h \
|
||||||
httpd.c \
|
httpd.c \
|
||||||
httpd_task.c
|
httpd-task.c
|
||||||
|
|
||||||
libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
|
libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
|
||||||
libqsenet_la_LIBADD = -lqsecmn
|
libqsenet_la_LIBADD = -lqsecmn
|
||||||
@ -336,8 +336,8 @@ distclean-compile:
|
|||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htrd.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htrd.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htre.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htre.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-task.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd_task.Plo@am__quote@
|
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
static int task_main_disconnect (
|
static int task_main_disconnect (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
{
|
{
|
||||||
shutdown (client->handle.i, SHUT_RDWR);
|
httpd->cbs->client.shutdown (httpd, client);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1497,46 +1497,20 @@ qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), qse_htre_getqpathptr(req), qse_htre_getqpat
|
|||||||
qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), tmp);
|
qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SERVER_HOST, REMOTE_HOST,
|
|
||||||
{
|
{
|
||||||
qse_mchar_t port[16];
|
qse_mchar_t addr[128];
|
||||||
snprintf (port, QSE_COUNTOF(port),
|
qse_nwadtombs (&client->local_addr,
|
||||||
QSE_MT("%d"), (int)ntohs(client->local_addr.in4.sin_port));
|
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_PORT);
|
||||||
qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), port);
|
qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), addr);
|
||||||
|
qse_nwadtombs (&client->local_addr,
|
||||||
snprintf (port, QSE_COUNTOF(port),
|
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_ADDR);
|
||||||
QSE_MT("%d"), (int)ntohs(client->remote_addr.in4.sin_port));
|
qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), addr);
|
||||||
qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), port);
|
qse_nwadtombs (&client->remote_addr,
|
||||||
}
|
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_PORT);
|
||||||
|
qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), addr);
|
||||||
#if defined(AF_INET6)
|
qse_nwadtombs (&client->remote_addr,
|
||||||
if (client->local_addr.in4.sin_family == AF_INET6)
|
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_ADDR);
|
||||||
{
|
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), addr);
|
||||||
qse_mchar_t ipaddr[128];
|
|
||||||
inet_ntop (client->local_addr.in6.sin6_family, &client->local_addr.in6.sin6_addr, ipaddr, QSE_COUNTOF(ipaddr));
|
|
||||||
qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), ipaddr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
qse_mchar_t ipaddr[128];
|
|
||||||
inet_ntop (client->local_addr.in4.sin_family, &client->local_addr.in4.sin_addr, ipaddr, QSE_COUNTOF(ipaddr));
|
|
||||||
qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), ipaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(AF_INET6)
|
|
||||||
if (client->remote_addr.in4.sin_family == AF_INET6)
|
|
||||||
{
|
|
||||||
qse_mchar_t ipaddr[128];
|
|
||||||
inet_ntop (client->remote_addr.in6.sin6_family, &client->remote_addr.in6.sin6_addr, ipaddr, QSE_COUNTOF(ipaddr));
|
|
||||||
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), ipaddr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
qse_mchar_t ipaddr[128];
|
|
||||||
inet_ntop (client->remote_addr.in4.sin_family, &client->remote_addr.in4.sin_addr, ipaddr, QSE_COUNTOF(ipaddr));
|
|
||||||
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), ipaddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
@ -29,11 +29,7 @@
|
|||||||
#include <qse/cmn/chr.h>
|
#include <qse/cmn/chr.h>
|
||||||
#include <qse/cmn/str.h>
|
#include <qse/cmn/str.h>
|
||||||
#include <qse/cmn/mbwc.h>
|
#include <qse/cmn/mbwc.h>
|
||||||
|
#include <qse/cmn/hton.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#include <qse/cmn/stdio.h>
|
#include <qse/cmn/stdio.h>
|
||||||
|
|
||||||
@ -50,7 +46,8 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd)
|
|||||||
#define DEFAULT_PORT 80
|
#define DEFAULT_PORT 80
|
||||||
#define DEFAULT_SECURE_PORT 443
|
#define DEFAULT_SECURE_PORT 443
|
||||||
|
|
||||||
static void free_listener_list (qse_httpd_t* httpd, listener_t* l);
|
static void free_server_list (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_server_t* server);
|
||||||
|
|
||||||
qse_httpd_t* qse_httpd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
qse_httpd_t* qse_httpd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
||||||
{
|
{
|
||||||
@ -80,7 +77,9 @@ int qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr)
|
|||||||
{
|
{
|
||||||
QSE_MEMSET (httpd, 0, QSE_SIZEOF(*httpd));
|
QSE_MEMSET (httpd, 0, QSE_SIZEOF(*httpd));
|
||||||
httpd->mmgr = mmgr;
|
httpd->mmgr = mmgr;
|
||||||
httpd->listener.max = -1;
|
|
||||||
|
/* TODO: abstract away this field */
|
||||||
|
httpd->server.max = -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -88,8 +87,8 @@ int qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr)
|
|||||||
void qse_httpd_fini (qse_httpd_t* httpd)
|
void qse_httpd_fini (qse_httpd_t* httpd)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
free_listener_list (httpd, httpd->listener.list);
|
free_server_list (httpd, httpd->server.list);
|
||||||
httpd->listener.list = QSE_NULL;
|
httpd->server.list = QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qse_httpd_stop (qse_httpd_t* httpd)
|
void qse_httpd_stop (qse_httpd_t* httpd)
|
||||||
@ -255,133 +254,151 @@ static qse_htrd_recbs_t htrd_recbs =
|
|||||||
htrd_handle_request
|
htrd_handle_request
|
||||||
};
|
};
|
||||||
|
|
||||||
static void deactivate_listener (qse_httpd_t* httpd, listener_t* l)
|
/* --------------------------------------------------- */
|
||||||
|
|
||||||
|
static void deactivate_servers (qse_httpd_t* httpd)
|
||||||
{
|
{
|
||||||
QSE_ASSERT (l->handle >= 0);
|
qse_httpd_server_t* server;
|
||||||
|
|
||||||
/* TODO: callback httpd->cbs.listener_deactivated (httpd, l);*/
|
for (server = httpd->server.list; server; server = server->next)
|
||||||
/* TODO: suport https... */
|
|
||||||
close (l->handle);
|
|
||||||
l->handle = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_listener_sockaddr (const listener_t* l, sockaddr_t* addr)
|
|
||||||
{
|
|
||||||
int addrsize;
|
|
||||||
|
|
||||||
QSE_MEMSET (addr, 0, QSE_SIZEOF(*addr));
|
|
||||||
|
|
||||||
switch (l->family)
|
|
||||||
{
|
{
|
||||||
case AF_INET:
|
httpd->cbs->server.close (httpd, server);
|
||||||
{
|
|
||||||
addr->in4.sin_family = l->family;
|
|
||||||
addr->in4.sin_addr = l->addr.in4;
|
|
||||||
addr->in4.sin_port = htons (l->port);
|
|
||||||
addrsize = QSE_SIZEOF(addr->in4);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef AF_INET6
|
|
||||||
case AF_INET6:
|
|
||||||
{
|
|
||||||
addr->in6.sin6_family = l->family;
|
|
||||||
addr->in6.sin6_addr = l->addr.in6;
|
|
||||||
addr->in6.sin6_port = htons (l->port);
|
|
||||||
/* TODO: addr.in6.sin6_scope_id */
|
|
||||||
addrsize = QSE_SIZEOF(addr->in6);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
QSE_ASSERT (!"This should never happen");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return addrsize;
|
FD_ZERO (&httpd->server.set);
|
||||||
|
httpd->server.max = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int activate_listener (qse_httpd_t* httpd, listener_t* l)
|
static int activate_servers (qse_httpd_t* httpd)
|
||||||
{
|
{
|
||||||
/* TODO: suport https... */
|
qse_httpd_server_t* server;
|
||||||
int s = -1, flag;
|
|
||||||
sockaddr_t addr;
|
|
||||||
int addrsize;
|
|
||||||
|
|
||||||
QSE_ASSERT (l->handle <= -1);
|
/* TODO: delete these two variables */
|
||||||
|
fd_set server_set;
|
||||||
|
int server_max = -1;
|
||||||
|
|
||||||
s = socket (l->family, SOCK_STREAM, IPPROTO_TCP);
|
FD_ZERO (&server_set);
|
||||||
if (s <= -1) goto oops_esocket;
|
|
||||||
|
|
||||||
flag = 1;
|
for (server = httpd->server.list; server; server = server->next)
|
||||||
setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &flag, QSE_SIZEOF(flag));
|
{
|
||||||
|
if (httpd->cbs->server.open (httpd, server) <= -1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
addrsize = get_listener_sockaddr (l, &addr);
|
/* TODO: abstract away these 2 lines to a callback ... */
|
||||||
|
FD_SET (server->handle.i, &server_set);
|
||||||
/* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the
|
if (server->handle.i >= server_max) server_max = server->handle.i;
|
||||||
* address size for AF_INET. */
|
}
|
||||||
/*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/
|
|
||||||
if (bind (s, (struct sockaddr*)&addr, addrsize) <= -1) goto oops_esocket;
|
|
||||||
if (listen (s, 10) <= -1) goto oops_esocket;
|
|
||||||
|
|
||||||
flag = fcntl (s, F_GETFL);
|
|
||||||
if (flag >= 0) fcntl (s, F_SETFL, flag | O_NONBLOCK);
|
|
||||||
fcntl (s, F_SETFD, FD_CLOEXEC);
|
|
||||||
|
|
||||||
l->handle = s;
|
|
||||||
s = -1;
|
|
||||||
|
|
||||||
|
/* abstract away these 2 lines also */
|
||||||
|
httpd->server.set = server_set;
|
||||||
|
httpd->server.max = server_max;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
oops_esocket:
|
|
||||||
httpd->errnum = QSE_HTTPD_ESOCKET;
|
|
||||||
if (s >= 0) close (s);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deactivate_listeners (qse_httpd_t* httpd)
|
static void free_server_list (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||||
{
|
{
|
||||||
listener_t* l;
|
while (server)
|
||||||
|
|
||||||
for (l = httpd->listener.list; l; l = l->next)
|
|
||||||
{
|
{
|
||||||
if (l->handle >= 0) deactivate_listener (httpd, l);
|
qse_httpd_server_t* next = server->next;
|
||||||
|
|
||||||
|
httpd->cbs->server.close (httpd, server);
|
||||||
|
qse_httpd_freemem (httpd, server);
|
||||||
|
|
||||||
|
server = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
FD_ZERO (&httpd->listener.set);
|
|
||||||
httpd->listener.max = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int activate_listeners (qse_httpd_t* httpd)
|
static qse_httpd_server_t* parse_server_uri (
|
||||||
|
qse_httpd_t* httpd, const qse_char_t* uri)
|
||||||
{
|
{
|
||||||
listener_t* l;
|
qse_httpd_server_t* server;
|
||||||
fd_set listener_set;
|
qse_uint16_t default_port;
|
||||||
int listener_max = -1;
|
qse_cstr_t tmp;
|
||||||
|
|
||||||
FD_ZERO (&listener_set);
|
server = qse_httpd_allocmem (httpd, QSE_SIZEOF(*server));
|
||||||
for (l = httpd->listener.list; l; l = l->next)
|
if (server == QSE_NULL) goto oops; /* alloc set error number. */
|
||||||
|
|
||||||
|
QSE_MEMSET (server, 0, QSE_SIZEOF(*server));
|
||||||
|
|
||||||
|
/* check the protocol part */
|
||||||
|
tmp.ptr = uri;
|
||||||
|
while (*uri != QSE_T(':'))
|
||||||
{
|
{
|
||||||
if (l->handle <= -1)
|
if (*uri == QSE_T('\0'))
|
||||||
{
|
{
|
||||||
if (activate_listener (httpd, l) <= -1) goto oops;
|
httpd->errnum = QSE_HTTPD_EINVAL;
|
||||||
/*TODO: callback httpd->cbs.listener_activated (httpd, l);*/
|
goto oops;
|
||||||
}
|
}
|
||||||
|
uri++;
|
||||||
|
}
|
||||||
|
tmp.len = uri - tmp.ptr;
|
||||||
|
if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0)
|
||||||
|
{
|
||||||
|
server->secure = 0;
|
||||||
|
default_port = DEFAULT_PORT;
|
||||||
|
}
|
||||||
|
else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0)
|
||||||
|
{
|
||||||
|
server->secure = 1;
|
||||||
|
default_port = DEFAULT_SECURE_PORT;
|
||||||
|
}
|
||||||
|
else goto oops;
|
||||||
|
|
||||||
FD_SET (l->handle, &listener_set);
|
uri++; /* skip : */
|
||||||
if (l->handle >= listener_max) listener_max = l->handle;
|
if (*uri != QSE_T('/'))
|
||||||
|
{
|
||||||
|
httpd->errnum = QSE_HTTPD_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
uri++; /* skip / */
|
||||||
|
if (*uri != QSE_T('/'))
|
||||||
|
{
|
||||||
|
httpd->errnum = QSE_HTTPD_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
uri++; /* skip / */
|
||||||
|
|
||||||
|
if (qse_strtonwad (uri, &server->nwad) <= -1)
|
||||||
|
{
|
||||||
|
httpd->errnum = QSE_HTTPD_EINVAL;
|
||||||
|
goto oops;
|
||||||
}
|
}
|
||||||
|
|
||||||
httpd->listener.set = listener_set;
|
if (server->nwad.type == QSE_NWAD_IN4)
|
||||||
httpd->listener.max = listener_max;
|
{
|
||||||
return 0;
|
if (server->nwad.u.in4.port == 0)
|
||||||
|
server->nwad.u.in4.port = qse_hton16(default_port);
|
||||||
|
}
|
||||||
|
else if (server->nwad.type == QSE_NWAD_IN6)
|
||||||
|
{
|
||||||
|
if (server->nwad.u.in6.port == 0)
|
||||||
|
server->nwad.u.in6.port = qse_hton16(default_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
deactivate_listeners (httpd);
|
if (server) qse_httpd_freemem (httpd, server);
|
||||||
return -1;
|
return QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qse_httpd_addserver (qse_httpd_t* httpd, const qse_char_t* uri)
|
||||||
|
{
|
||||||
|
qse_httpd_server_t* server;
|
||||||
|
|
||||||
|
server = parse_server_uri (httpd, uri);
|
||||||
|
if (server == QSE_NULL) return -1;
|
||||||
|
|
||||||
|
server->next = httpd->server.list;
|
||||||
|
httpd->server.list = server;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------- */
|
||||||
|
|
||||||
static void init_client_array (qse_httpd_t* httpd)
|
static void init_client_array (qse_httpd_t* httpd)
|
||||||
{
|
{
|
||||||
client_array_t* array = &httpd->client.array;
|
client_array_t* array = &httpd->client.array;
|
||||||
@ -406,7 +423,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Debug: closing socket %d\n"), array->data[fd].ha
|
|||||||
if (httpd->cbs->client.closed)
|
if (httpd->cbs->client.closed)
|
||||||
httpd->cbs->client.closed (httpd, &array->data[fd]);
|
httpd->cbs->client.closed (httpd, &array->data[fd]);
|
||||||
|
|
||||||
close (array->data[fd].handle.i);
|
httpd->cbs->client.close (httpd, &array->data[fd]);
|
||||||
array->size--;
|
array->size--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -480,79 +497,41 @@ static qse_httpd_client_t* insert_into_client_array (
|
|||||||
return &array->data[fd];
|
return &array->data[fd];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int accept_client_from_listener (qse_httpd_t* httpd, listener_t* l)
|
static int accept_client_from_server (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||||
{
|
{
|
||||||
int flag;
|
|
||||||
|
|
||||||
#ifdef HAVE_SOCKLEN_T
|
|
||||||
socklen_t addrlen;
|
|
||||||
#else
|
|
||||||
int addrlen;
|
|
||||||
#endif
|
|
||||||
qse_httpd_client_t clibuf;
|
qse_httpd_client_t clibuf;
|
||||||
qse_httpd_client_t* client;
|
qse_httpd_client_t* client;
|
||||||
|
|
||||||
QSE_MEMSET (&clibuf, 0, QSE_SIZEOF(clibuf));
|
QSE_MEMSET (&clibuf, 0, QSE_SIZEOF(clibuf));
|
||||||
clibuf.secure = l->secure;
|
|
||||||
|
|
||||||
addrlen = QSE_SIZEOF(clibuf.remote_addr);
|
if (httpd->cbs->server.accept (httpd, server, &clibuf) <= -1) return -1;
|
||||||
clibuf.handle.i = accept (
|
|
||||||
l->handle, (struct sockaddr*)&clibuf.remote_addr, &addrlen);
|
|
||||||
if (clibuf.handle.i <= -1)
|
|
||||||
{
|
|
||||||
httpd->errnum = QSE_HTTPD_ESOCKET;
|
|
||||||
qse_fprintf (QSE_STDERR, QSE_T("Error: accept returned failure\n"));
|
|
||||||
goto oops;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* select() uses a fixed-size array so the file descriptor can not
|
/* TODO: check maximum number of client. if exceed call client.close */
|
||||||
* exceeded FD_SETSIZE */
|
|
||||||
if (clibuf.handle.i >= FD_SETSIZE)
|
|
||||||
{
|
|
||||||
close (clibuf.handle.i);
|
|
||||||
qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
|
|
||||||
/* httpd->errnum = QSE_HTTPD_EOVERFLOW; */
|
|
||||||
goto oops;
|
|
||||||
}
|
|
||||||
|
|
||||||
addrlen = QSE_SIZEOF(clibuf.local_addr);
|
|
||||||
if (getsockname (clibuf.handle.i, (struct sockaddr*)&clibuf.local_addr, &addrlen) <= -1)
|
|
||||||
get_listener_sockaddr (l, &clibuf.local_addr);
|
|
||||||
|
|
||||||
/* set the nonblock flag in case read() after select() blocks
|
|
||||||
* for various reasons - data received may be dropped after
|
|
||||||
* arrival for wrong checksum, for example. */
|
|
||||||
flag = fcntl (clibuf.handle.i, F_GETFL);
|
|
||||||
if (flag >= 0) fcntl (clibuf.handle.i, F_SETFL, flag | O_NONBLOCK);
|
|
||||||
|
|
||||||
flag = fcntl (clibuf.handle.i, F_GETFD);
|
|
||||||
if (flag >= 0) fcntl (clibuf.handle.i, F_SETFD, flag | FD_CLOEXEC);
|
|
||||||
|
|
||||||
|
clibuf.secure = server->secure;
|
||||||
client = insert_into_client_array (httpd, &clibuf);
|
client = insert_into_client_array (httpd, &clibuf);
|
||||||
|
|
||||||
if (client == QSE_NULL)
|
if (client == QSE_NULL)
|
||||||
{
|
{
|
||||||
close (clibuf.handle.i);
|
httpd->cbs->client.close (httpd, &clibuf);
|
||||||
goto oops;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_printf (QSE_T("connection %d accepted\n"), clibuf.handle.i);
|
qse_printf (QSE_T("connection %d accepted\n"), clibuf.handle.i);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
oops:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void accept_client_from_listeners (qse_httpd_t* httpd, fd_set* r)
|
static void accept_client_from_servers (qse_httpd_t* httpd, fd_set* r)
|
||||||
{
|
{
|
||||||
listener_t* l;
|
qse_httpd_server_t* server;
|
||||||
|
|
||||||
for (l = httpd->listener.list; l; l = l->next)
|
for (server = httpd->server.list; server; server = server->next)
|
||||||
{
|
{
|
||||||
if (FD_ISSET(l->handle, r))
|
/* TODO: abstract this part... */
|
||||||
|
if (FD_ISSET(server->handle.i, r))
|
||||||
{
|
{
|
||||||
accept_client_from_listener (httpd, l);
|
accept_client_from_server (httpd, server);
|
||||||
|
|
||||||
/* TODO: if (accept_client_from_listener (httpd, l) <= -1)
|
/* TODO: if (accept_client_from_listener (httpd, l) <= -1)
|
||||||
httpd->cbs.on_error (httpd, l).... */
|
httpd->cbs.on_error (httpd, l).... */
|
||||||
}
|
}
|
||||||
@ -570,8 +549,8 @@ static int make_fd_set_from_client_array (
|
|||||||
|
|
||||||
/* qse_http_loop() needs to monitor listner handles
|
/* qse_http_loop() needs to monitor listner handles
|
||||||
* to handle a new client connection. */
|
* to handle a new client connection. */
|
||||||
max = httpd->listener.max;
|
max = httpd->server.max;
|
||||||
*r = httpd->listener.set;
|
*r = httpd->server.set;
|
||||||
FD_ZERO (w);
|
FD_ZERO (w);
|
||||||
|
|
||||||
for (fd = 0; fd < ca->capa; fd++)
|
for (fd = 0; fd < ca->capa; fd++)
|
||||||
@ -695,22 +674,22 @@ reread:
|
|||||||
m = httpd->cbs->client.recv (httpd, client, buf, QSE_SIZEOF(buf));
|
m = httpd->cbs->client.recv (httpd, client, buf, QSE_SIZEOF(buf));
|
||||||
if (m <= -1)
|
if (m <= -1)
|
||||||
{
|
{
|
||||||
// TODO: handle errno in the callback... and devise a new return value
|
if (httpd->errnum == QSE_HTTPD_EAGAIN)
|
||||||
// to indicate no data at this momemnt (EAGAIN, EWOULDBLOCK)...
|
|
||||||
// EINTR to be hnalded inside callback if needed...
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
|
||||||
{
|
{
|
||||||
/* nothing to read yet. */
|
/* nothing to read yet. */
|
||||||
qse_fprintf (QSE_STDERR, QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i);
|
qse_fprintf (QSE_STDERR, QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i);
|
||||||
return 0; /* return ok */
|
return 0; /* return ok */
|
||||||
}
|
}
|
||||||
else if (errno != EINTR)
|
else if (httpd->errnum == QSE_HTTPD_EINTR)
|
||||||
{
|
{
|
||||||
httpd->errnum = QSE_HTTPD_ESOCKET;
|
goto reread;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */
|
||||||
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), client->handle.i);
|
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), client->handle.i);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
goto reread;
|
|
||||||
}
|
}
|
||||||
else if (m == 0)
|
else if (m == 0)
|
||||||
{
|
{
|
||||||
@ -748,7 +727,7 @@ int qse_httpd_loop (qse_httpd_t* httpd, qse_httpd_cbs_t* cbs)
|
|||||||
httpd->stopreq = 0;
|
httpd->stopreq = 0;
|
||||||
httpd->cbs = cbs;
|
httpd->cbs = cbs;
|
||||||
|
|
||||||
QSE_ASSERTX (httpd->listener.list != QSE_NULL,
|
QSE_ASSERTX (httpd->server.list != QSE_NULL,
|
||||||
"Add listeners before calling qse_httpd_loop()"
|
"Add listeners before calling qse_httpd_loop()"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -756,14 +735,14 @@ int qse_httpd_loop (qse_httpd_t* httpd, qse_httpd_cbs_t* cbs)
|
|||||||
"Set httpd callbacks before calling qse_httpd_loop()"
|
"Set httpd callbacks before calling qse_httpd_loop()"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (httpd->listener.list == QSE_NULL)
|
if (httpd->server.list == QSE_NULL)
|
||||||
{
|
{
|
||||||
/* no listener specified */
|
/* no listener specified */
|
||||||
httpd->errnum = QSE_HTTPD_EINVAL;
|
httpd->errnum = QSE_HTTPD_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activate_listeners (httpd) <= -1) return -1;
|
if (activate_servers (httpd) <= -1) return -1;
|
||||||
|
|
||||||
init_client_array (httpd);
|
init_client_array (httpd);
|
||||||
|
|
||||||
@ -794,7 +773,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check the listener activity */
|
/* check the listener activity */
|
||||||
accept_client_from_listeners (httpd, &r);
|
accept_client_from_servers (httpd, &r);
|
||||||
|
|
||||||
/* check the client activity */
|
/* check the client activity */
|
||||||
for (fd = 0; fd < httpd->client.array.capa; fd++)
|
for (fd = 0; fd < httpd->client.array.capa; fd++)
|
||||||
@ -904,218 +883,11 @@ qse_printf (QSE_T(".....TRIGGER WRITABLE....\n"));
|
|||||||
}
|
}
|
||||||
|
|
||||||
fini_client_array (httpd);
|
fini_client_array (httpd);
|
||||||
deactivate_listeners (httpd);
|
deactivate_servers (httpd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_listener (qse_httpd_t* httpd, listener_t* l)
|
/* --------------------------------------------------- */
|
||||||
{
|
|
||||||
if (l->host) qse_httpd_freemem (httpd, l->host);
|
|
||||||
if (l->handle >= 0) close (l->handle);
|
|
||||||
qse_httpd_freemem (httpd, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_listener_list (qse_httpd_t* httpd, listener_t* l)
|
|
||||||
{
|
|
||||||
while (l)
|
|
||||||
{
|
|
||||||
listener_t* cur = l;
|
|
||||||
l = l->next;
|
|
||||||
free_listener (httpd, cur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static listener_t* parse_listener_uri (
|
|
||||||
qse_httpd_t* httpd, const qse_char_t* uri)
|
|
||||||
{
|
|
||||||
const qse_char_t* p = uri;
|
|
||||||
listener_t* ltmp = QSE_NULL;
|
|
||||||
qse_cstr_t tmp;
|
|
||||||
qse_mchar_t* host;
|
|
||||||
int x;
|
|
||||||
|
|
||||||
ltmp = qse_httpd_allocmem (httpd, QSE_SIZEOF(*ltmp));
|
|
||||||
if (ltmp == QSE_NULL) goto oops; /* alloc set error number. so goto oops */
|
|
||||||
|
|
||||||
QSE_MEMSET (ltmp, 0, QSE_SIZEOF(*ltmp));
|
|
||||||
ltmp->handle = -1;
|
|
||||||
|
|
||||||
/* check the protocol part */
|
|
||||||
tmp.ptr = p;
|
|
||||||
while (*p != QSE_T(':'))
|
|
||||||
{
|
|
||||||
if (*p == QSE_T('\0')) goto oops_einval;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
tmp.len = p - tmp.ptr;
|
|
||||||
if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0)
|
|
||||||
{
|
|
||||||
ltmp->secure = 0;
|
|
||||||
ltmp->port = DEFAULT_PORT;
|
|
||||||
}
|
|
||||||
else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0)
|
|
||||||
{
|
|
||||||
ltmp->secure = 1;
|
|
||||||
ltmp->port = DEFAULT_SECURE_PORT;
|
|
||||||
}
|
|
||||||
else goto oops;
|
|
||||||
|
|
||||||
p++; /* skip : */
|
|
||||||
if (*p != QSE_T('/')) goto oops_einval;
|
|
||||||
p++; /* skip / */
|
|
||||||
if (*p != QSE_T('/')) goto oops_einval;
|
|
||||||
p++; /* skip / */
|
|
||||||
|
|
||||||
#ifdef AF_INET6
|
|
||||||
if (*p == QSE_T('['))
|
|
||||||
{
|
|
||||||
/* IPv6 address */
|
|
||||||
p++; /* skip [ */
|
|
||||||
|
|
||||||
for (tmp.ptr = p; *p != QSE_T(']'); p++)
|
|
||||||
{
|
|
||||||
if (*p == QSE_T('\0')) goto oops_einval;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.len = p - tmp.ptr;
|
|
||||||
ltmp->family = AF_INET6;
|
|
||||||
|
|
||||||
p++; /* skip ] */
|
|
||||||
if (*p != QSE_T(':') && *p != QSE_T('\0')) goto oops_einval;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
/* host name or IPv4 address */
|
|
||||||
for (tmp.ptr = p; ; p++)
|
|
||||||
{
|
|
||||||
if (*p == QSE_T(':') || *p == QSE_T('\0')) break;
|
|
||||||
}
|
|
||||||
tmp.len = p - tmp.ptr;
|
|
||||||
ltmp->family = AF_INET;
|
|
||||||
#ifdef AF_INET6
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ltmp->host = qse_strxdup (tmp.ptr, tmp.len, httpd->mmgr);
|
|
||||||
if (ltmp->host == QSE_NULL) goto oops_enomem;
|
|
||||||
|
|
||||||
#ifdef QSE_CHAR_IS_WCHAR
|
|
||||||
host = qse_wcstombsdup (ltmp->host, httpd->mmgr);
|
|
||||||
if (host == QSE_NULL) goto oops_enomem;
|
|
||||||
#else
|
|
||||||
host = ltmp->host;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
x = inet_pton (ltmp->family, host, <mp->addr);
|
|
||||||
#ifdef QSE_CHAR_IS_WCHAR
|
|
||||||
qse_httpd_freemem (httpd, host);
|
|
||||||
#endif
|
|
||||||
if (x != 1)
|
|
||||||
{
|
|
||||||
/* TODO: need to support host names???
|
|
||||||
if (getaddrinfo... )....
|
|
||||||
or CALL a user callback for name resolution?
|
|
||||||
if (httpd->cbs.resolve_hostname (httpd, ltmp->host) <= -1) must call this with host before freeing it up????
|
|
||||||
*/
|
|
||||||
goto oops_einval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*p == QSE_T(':'))
|
|
||||||
{
|
|
||||||
unsigned int port = 0;
|
|
||||||
|
|
||||||
/* port number */
|
|
||||||
p++;
|
|
||||||
|
|
||||||
for (tmp.ptr = p; QSE_ISDIGIT(*p); p++)
|
|
||||||
port = port * 10 + (*p - QSE_T('0'));
|
|
||||||
|
|
||||||
tmp.len = p - tmp.ptr;
|
|
||||||
if (tmp.len <= 0 ||
|
|
||||||
tmp.len >= 6 ||
|
|
||||||
port > QSE_TYPE_MAX(unsigned short)) goto oops_einval;
|
|
||||||
ltmp->port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip spaces */
|
|
||||||
while (QSE_ISSPACE(*p)) p++;
|
|
||||||
|
|
||||||
return ltmp;
|
|
||||||
|
|
||||||
oops_einval:
|
|
||||||
httpd->errnum = QSE_HTTPD_EINVAL;
|
|
||||||
goto oops;
|
|
||||||
|
|
||||||
oops_enomem:
|
|
||||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
|
||||||
goto oops;
|
|
||||||
|
|
||||||
oops:
|
|
||||||
if (ltmp) free_listener (httpd, ltmp);
|
|
||||||
return QSE_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_listener (qse_httpd_t* httpd, const qse_char_t* uri)
|
|
||||||
{
|
|
||||||
listener_t* lsn;
|
|
||||||
|
|
||||||
lsn = parse_listener_uri (httpd, uri);
|
|
||||||
if (lsn == QSE_NULL) return -1;
|
|
||||||
|
|
||||||
lsn->next = httpd->listener.list;
|
|
||||||
httpd->listener.list = lsn;
|
|
||||||
/*
|
|
||||||
TODO: mutex protection...
|
|
||||||
if in the activated state...
|
|
||||||
activate_additional_listeners (httpd, l)
|
|
||||||
recalc httpd->listener.set.
|
|
||||||
recalc httpd->listener.max.
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int delete_listeners (qse_httpd_t* httpd, const qse_char_t* uri)
|
|
||||||
{
|
|
||||||
listener_t* lh, * li, * hl;
|
|
||||||
|
|
||||||
lh = parse_listener_uri (httpd, uri, QSE_NULL);
|
|
||||||
if (lh == QSE_NULL) return -1;
|
|
||||||
|
|
||||||
for (li = lh; li; li = li->next)
|
|
||||||
{
|
|
||||||
for (hl = httpd->listener.list; hl; hl = hl->next)
|
|
||||||
{
|
|
||||||
if (li->secure == hl->secuire &&
|
|
||||||
li->addr == hl->addr &&
|
|
||||||
li->port == hl->port)
|
|
||||||
{
|
|
||||||
mark_delete
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int qse_httpd_addlistener (qse_httpd_t* httpd, const qse_char_t* uri)
|
|
||||||
{
|
|
||||||
return add_listener (httpd, uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
int qse_httpd_dellistener (qse_httpd_t* httpd, const qse_char_t* uri)
|
|
||||||
{
|
|
||||||
return delete_listeners (httpd, uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
void qse_httpd_clearlisteners (qse_httpd_t* httpd)
|
|
||||||
{
|
|
||||||
deactivate_listeners (httpd);
|
|
||||||
free_listener_list (httpd, httpd->listener.list);
|
|
||||||
httpd->listener.list = QSE_NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entask (
|
qse_httpd_task_t* qse_httpd_entask (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
|
@ -25,27 +25,16 @@
|
|||||||
|
|
||||||
#include <qse/net/httpd.h>
|
#include <qse/net/httpd.h>
|
||||||
#include <qse/net/htrd.h>
|
#include <qse/net/htrd.h>
|
||||||
|
#include <qse/cmn/nwad.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
/* REMOVE THESE headers after abstracting away select()/fd_set */
|
||||||
#include <netinet/in.h>
|
#include <sys/time.h>
|
||||||
#include <arpa/inet.h>
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifndef SHUT_RDWR
|
|
||||||
# define SHUT_RDWR 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct client_array_t client_array_t;
|
typedef struct client_array_t client_array_t;
|
||||||
|
|
||||||
union sockaddr_t
|
|
||||||
{
|
|
||||||
struct sockaddr_in in4;
|
|
||||||
#ifdef AF_INET6
|
|
||||||
struct sockaddr_in6 in6;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union sockaddr_t sockaddr_t;
|
|
||||||
|
|
||||||
typedef struct task_queue_node_t task_queue_node_t;
|
typedef struct task_queue_node_t task_queue_node_t;
|
||||||
struct task_queue_node_t
|
struct task_queue_node_t
|
||||||
{
|
{
|
||||||
@ -58,12 +47,14 @@ struct qse_httpd_client_t
|
|||||||
{
|
{
|
||||||
qse_ubi_t handle;
|
qse_ubi_t handle;
|
||||||
qse_ubi_t handle2;
|
qse_ubi_t handle2;
|
||||||
|
qse_nwad_t local_addr;
|
||||||
|
qse_nwad_t remote_addr;
|
||||||
|
|
||||||
|
/* ------------------------------ */
|
||||||
|
|
||||||
int ready;
|
int ready;
|
||||||
int secure;
|
int secure;
|
||||||
int bad;
|
int bad;
|
||||||
sockaddr_t local_addr;
|
|
||||||
sockaddr_t remote_addr;
|
|
||||||
qse_htrd_t* htrd;
|
qse_htrd_t* htrd;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@ -84,26 +75,6 @@ struct client_array_t
|
|||||||
qse_httpd_client_t* data;
|
qse_httpd_client_t* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct listener_t listener_t;
|
|
||||||
struct listener_t
|
|
||||||
{
|
|
||||||
int family;/* AF_INET, AF_INET6 */
|
|
||||||
int secure;
|
|
||||||
|
|
||||||
qse_char_t* host;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct in_addr in4;
|
|
||||||
#ifdef AF_INET6
|
|
||||||
struct in6_addr in6;
|
|
||||||
#endif
|
|
||||||
} addr;
|
|
||||||
|
|
||||||
int port;
|
|
||||||
int handle;
|
|
||||||
listener_t* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct qse_httpd_t
|
struct qse_httpd_t
|
||||||
{
|
{
|
||||||
QSE_DEFINE_COMMON_FIELDS (httpd)
|
QSE_DEFINE_COMMON_FIELDS (httpd)
|
||||||
@ -120,10 +91,10 @@ struct qse_httpd_t
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
listener_t* list;
|
qse_httpd_server_t* list;
|
||||||
fd_set set;
|
fd_set set;
|
||||||
int max;
|
int max;
|
||||||
} listener;
|
} server;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -105,7 +105,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qse_nwadtostr (&nwad, buf, QSE_COUNTOF(buf));
|
qse_nwadtostr (&nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL);
|
||||||
qse_printf (QSE_T("Converted <%s> to <%s>\n"), ipstr[i], buf);
|
qse_printf (QSE_T("Converted <%s> to <%s>\n"), ipstr[i], buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qse_nwadtombs (&nwad, mbsbuf, QSE_COUNTOF(mbsbuf));
|
qse_nwadtombs (&nwad, mbsbuf, QSE_COUNTOF(mbsbuf), QSE_NWADTOMBS_ALL);
|
||||||
qse_printf (QSE_T("Converted <%hs> to <%hs>\n"), ipstr_mbs[i], mbsbuf);
|
qse_printf (QSE_T("Converted <%hs> to <%hs>\n"), ipstr_mbs[i], mbsbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qse_nwadtowcs (&nwad, wcsbuf, QSE_COUNTOF(wcsbuf));
|
qse_nwadtowcs (&nwad, wcsbuf, QSE_COUNTOF(wcsbuf), QSE_NWADTOWCS_ALL);
|
||||||
qse_printf (QSE_T("Converted <%ls> to <%ls>\n"), ipstr_wcs[i], wcsbuf);
|
qse_printf (QSE_T("Converted <%ls> to <%ls>\n"), ipstr_wcs[i], wcsbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
@ -125,6 +127,37 @@ static qse_ssize_t xsendfile_ssl (
|
|||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
/* ------------------------------------------------------------------- */
|
||||||
|
static qse_httpd_errnum_t syserr_to_errnum (int e)
|
||||||
|
{
|
||||||
|
switch (e)
|
||||||
|
{
|
||||||
|
case ENOMEM:
|
||||||
|
return QSE_HTTPD_ENOMEM;
|
||||||
|
|
||||||
|
case EINVAL:
|
||||||
|
return QSE_HTTPD_EINVAL;
|
||||||
|
|
||||||
|
case EACCES:
|
||||||
|
return QSE_HTTPD_EACCES;
|
||||||
|
|
||||||
|
case ENOENT:
|
||||||
|
return QSE_HTTPD_ENOENT;
|
||||||
|
|
||||||
|
case EEXIST:
|
||||||
|
return QSE_HTTPD_EEXIST;
|
||||||
|
|
||||||
|
case EINTR:
|
||||||
|
return QSE_HTTPD_EINTR;
|
||||||
|
|
||||||
|
case EAGAIN:
|
||||||
|
/*case EWOULDBLOCK:*/
|
||||||
|
return QSE_HTTPD_EAGAIN;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return QSE_HTTPD_ESYSERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
typedef struct httpd_xtn_t httpd_xtn_t;
|
typedef struct httpd_xtn_t httpd_xtn_t;
|
||||||
@ -190,6 +223,190 @@ static void fini_xtn_ssl (httpd_xtn_t* xtn)
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static int sockaddr_to_nwad (
|
||||||
|
const struct sockaddr_storage* addr, qse_nwad_t* nwad)
|
||||||
|
{
|
||||||
|
int addrsize = -1;
|
||||||
|
|
||||||
|
switch (addr->ss_family)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
{
|
||||||
|
struct sockaddr_in* in;
|
||||||
|
in = (struct sockaddr_in*)addr;
|
||||||
|
addrsize = QSE_SIZEOF(*in);
|
||||||
|
|
||||||
|
memset (nwad, 0, QSE_SIZEOF(*nwad));
|
||||||
|
nwad->type = QSE_NWAD_IN4;
|
||||||
|
nwad->u.in4.addr.value = in->sin_addr.s_addr;
|
||||||
|
nwad->u.in4.port = in->sin_port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(AF_INET6)
|
||||||
|
case AF_INET6:
|
||||||
|
{
|
||||||
|
struct sockaddr_in6* in;
|
||||||
|
in = (struct sockaddr_in6*)addr;
|
||||||
|
addrsize = QSE_SIZEOF(*in);
|
||||||
|
|
||||||
|
memset (nwad, 0, QSE_SIZEOF(*nwad));
|
||||||
|
nwad->type = QSE_NWAD_IN6;
|
||||||
|
memcpy (&nwad->u.in6.addr, &in->sin6_addr, QSE_SIZEOF(nwad->u.in6.addr));
|
||||||
|
nwad->u.in6.scope = in->sin6_scope_id;
|
||||||
|
nwad->u.in6.port = in->sin6_port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return addrsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nwad_to_sockaddr (
|
||||||
|
const qse_nwad_t* nwad, struct sockaddr_storage* addr)
|
||||||
|
{
|
||||||
|
int addrsize = -1;
|
||||||
|
|
||||||
|
switch (nwad->type)
|
||||||
|
{
|
||||||
|
case QSE_NWAD_IN4:
|
||||||
|
{
|
||||||
|
struct sockaddr_in* in;
|
||||||
|
|
||||||
|
in = (struct sockaddr_in*)addr;
|
||||||
|
addrsize = QSE_SIZEOF(*in);
|
||||||
|
memset (in, 0, addrsize);
|
||||||
|
|
||||||
|
in->sin_family = AF_INET;
|
||||||
|
in->sin_addr.s_addr = nwad->u.in4.addr.value;
|
||||||
|
in->sin_port = nwad->u.in4.port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QSE_NWAD_IN6:
|
||||||
|
{
|
||||||
|
#if defined(AF_INET6)
|
||||||
|
struct sockaddr_in6* in;
|
||||||
|
|
||||||
|
in = (struct sockaddr_in6*)addr;
|
||||||
|
addrsize = QSE_SIZEOF(*in);
|
||||||
|
memset (in, 0, addrsize);
|
||||||
|
|
||||||
|
in->sin6_family = AF_INET6;
|
||||||
|
memcpy (&in->sin6_addr, &nwad->u.in6.addr, QSE_SIZEOF(nwad->u.in6.addr));
|
||||||
|
in->sin6_scope_id = nwad->u.in6.scope;
|
||||||
|
in->sin6_port = nwad->u.in6.port;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addrsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||||
|
{
|
||||||
|
int fd = -1, flag;
|
||||||
|
/* TODO: if AF_INET6 is not defined sockaddr_storage is not available...
|
||||||
|
* create your own union or somehting similar... */
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
int addrsize;
|
||||||
|
|
||||||
|
addrsize = nwad_to_sockaddr (&server->nwad, &addr);
|
||||||
|
if (addrsize <= -1)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (fd <= -1) goto oops;
|
||||||
|
|
||||||
|
flag = 1;
|
||||||
|
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flag, QSE_SIZEOF(flag));
|
||||||
|
|
||||||
|
/* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the
|
||||||
|
* address size for AF_INET. */
|
||||||
|
/*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/
|
||||||
|
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1) goto oops;
|
||||||
|
if (listen (fd, 10) <= -1) goto oops;
|
||||||
|
|
||||||
|
flag = fcntl (fd, F_GETFL);
|
||||||
|
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
|
||||||
|
|
||||||
|
flag = fcntl (fd, F_GETFD);
|
||||||
|
if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC);
|
||||||
|
|
||||||
|
server->handle.i = fd;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
oops:
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
if (fd >= 0) close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||||
|
{
|
||||||
|
close (server->handle.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int server_accept (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_server_t* server, qse_httpd_client_t* client)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
|
||||||
|
#ifdef HAVE_SOCKLEN_T
|
||||||
|
socklen_t addrlen;
|
||||||
|
#else
|
||||||
|
int addrlen;
|
||||||
|
#endif
|
||||||
|
int fd, flag;
|
||||||
|
|
||||||
|
addrlen = QSE_SIZEOF(addr);
|
||||||
|
fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen);
|
||||||
|
if (fd <= -1)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum (errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd >= FD_SETSIZE)
|
||||||
|
{
|
||||||
|
qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
|
||||||
|
/*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag = fcntl (fd, F_GETFL);
|
||||||
|
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
|
||||||
|
|
||||||
|
flag = fcntl (fd, F_GETFD);
|
||||||
|
if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC);
|
||||||
|
|
||||||
|
if (sockaddr_to_nwad (&addr, &client->remote_addr) <= -1)
|
||||||
|
{
|
||||||
|
/* TODO: logging */
|
||||||
|
client->remote_addr = server->nwad;
|
||||||
|
}
|
||||||
|
|
||||||
|
addrlen = QSE_SIZEOF(addr);
|
||||||
|
if (getsockname (fd, (struct sockaddr*)&addr, &addrlen) <= -1 ||
|
||||||
|
sockaddr_to_nwad (&addr, &client->local_addr) <= -1)
|
||||||
|
{
|
||||||
|
/* TODO: logging */
|
||||||
|
client->local_addr = server->nwad;
|
||||||
|
}
|
||||||
|
|
||||||
|
client->handle.i = fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int mux_readable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
|
static int mux_readable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
|
||||||
{
|
{
|
||||||
fd_set r;
|
fd_set r;
|
||||||
@ -245,9 +462,7 @@ static int file_stat (
|
|||||||
/* TODO: lstat? or stat? */
|
/* TODO: lstat? or stat? */
|
||||||
if (stat (path, &st) <= -1)
|
if (stat (path, &st) <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd,
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
(errno == ENOENT? QSE_HTTPD_ENOENT:
|
|
||||||
errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,9 +508,7 @@ qse_printf (QSE_T("opening file [%hs] for reading\n"), path);
|
|||||||
fd = open (path, flags, 0);
|
fd = open (path, flags, 0);
|
||||||
if (fd <= -1)
|
if (fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd,
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
(errno == ENOENT? QSE_HTTPD_ENOENT:
|
|
||||||
errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,9 +536,7 @@ qse_printf (QSE_T("opening file [%hs] for writing\n"), path);
|
|||||||
fd = open (path, flags, 0644);
|
fd = open (path, flags, 0644);
|
||||||
if (fd <= -1)
|
if (fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd,
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
(errno == ENOENT? QSE_HTTPD_ENOENT:
|
|
||||||
errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,17 +565,39 @@ static qse_ssize_t file_write (
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
|
static void client_close (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||||
|
{
|
||||||
|
close (client->handle.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_shutdown (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||||
|
{
|
||||||
|
shutdown (client->handle.i, SHUT_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
static qse_ssize_t client_recv (
|
static qse_ssize_t client_recv (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
qse_mchar_t* buf, qse_size_t bufsize)
|
qse_mchar_t* buf, qse_size_t bufsize)
|
||||||
{
|
{
|
||||||
if (client->secure)
|
if (client->secure)
|
||||||
{
|
{
|
||||||
return SSL_read (client->handle2.ptr, buf, bufsize);
|
int ret = SSL_read (client->handle2.ptr, buf, bufsize);
|
||||||
|
if (ret <= -1)
|
||||||
|
{
|
||||||
|
if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_READ)
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN);
|
||||||
|
else
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return read (client->handle.i, buf, bufsize);
|
ssize_t ret = read (client->handle.i, buf, bufsize);
|
||||||
|
if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,11 +607,21 @@ static qse_ssize_t client_send (
|
|||||||
{
|
{
|
||||||
if (client->secure)
|
if (client->secure)
|
||||||
{
|
{
|
||||||
return SSL_write (client->handle2.ptr, buf, bufsize);
|
int ret = SSL_write (client->handle2.ptr, buf, bufsize);
|
||||||
|
if (ret <= -1)
|
||||||
|
{
|
||||||
|
if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_WRITE)
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN);
|
||||||
|
else
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return write (client->handle.i, buf, bufsize);
|
ssize_t ret = write (client->handle.i, buf, bufsize);
|
||||||
|
if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,6 +908,9 @@ int list_directory (qse_httpd_t* httpd, const qse_mchar_t* path)
|
|||||||
|
|
||||||
static qse_httpd_cbs_t httpd_cbs =
|
static qse_httpd_cbs_t httpd_cbs =
|
||||||
{
|
{
|
||||||
|
/* server */
|
||||||
|
{ server_open, server_close, server_accept },
|
||||||
|
|
||||||
/* multiplexer */
|
/* multiplexer */
|
||||||
{ mux_readable, mux_writable },
|
{ mux_readable, mux_writable },
|
||||||
|
|
||||||
@ -679,7 +925,9 @@ static qse_httpd_cbs_t httpd_cbs =
|
|||||||
},
|
},
|
||||||
|
|
||||||
/* client connection */
|
/* client connection */
|
||||||
{ client_recv,
|
{ client_close,
|
||||||
|
client_shutdown,
|
||||||
|
client_recv,
|
||||||
client_send,
|
client_send,
|
||||||
client_sendfile,
|
client_sendfile,
|
||||||
client_accepted,
|
client_accepted,
|
||||||
@ -730,7 +978,7 @@ int httpd_main (int argc, qse_char_t* argv[])
|
|||||||
|
|
||||||
for (i = 1; i < argc; i++)
|
for (i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
if (qse_httpd_addlistener (httpd, argv[i]) <= -1)
|
if (qse_httpd_addserver (httpd, argv[i]) <= -1)
|
||||||
{
|
{
|
||||||
qse_fprintf (QSE_STDERR,
|
qse_fprintf (QSE_STDERR,
|
||||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user