mirror of
https://libwebsockets.org/repo/libwebsockets
synced 2024-11-24 01:39:33 +00:00
e3ed2ba690
Subject: [PATCH] fix build on QNX 6.5.0
473 lines
10 KiB
C
473 lines
10 KiB
C
/*
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
*
|
|
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
|
|
#if !defined(NO_GNU_SOURCE_THIS_TIME)
|
|
#define NO_GNU_SOURCE_THIS_TIME
|
|
#endif
|
|
#if !defined(_DARWIN_C_SOURCE)
|
|
#define _DARWIN_C_SOURCE
|
|
#endif
|
|
|
|
#include "private-lib-core.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <sys/stat.h>
|
|
#if defined(WIN32)
|
|
#include <direct.h>
|
|
#define read _read
|
|
#define open _open
|
|
#define close _close
|
|
#define write _write
|
|
#define mkdir(x,y) _mkdir(x)
|
|
#define rmdir _rmdir
|
|
#define unlink _unlink
|
|
#define HAVE_STRUCT_TIMESPEC
|
|
#if defined(pid_t)
|
|
#undef pid_t
|
|
#endif
|
|
#endif /* win32 */
|
|
|
|
#define COMBO_SIZEOF 512
|
|
|
|
#if !defined(LWS_PLAT_FREERTOS)
|
|
|
|
#if defined(WIN32)
|
|
#include "../../win32port/dirent/dirent-win32.h"
|
|
#else
|
|
#include <dirent.h>
|
|
#endif
|
|
|
|
static int filter(const struct dirent *ent)
|
|
{
|
|
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
#if !defined(WIN32)
|
|
static char csep = '/';
|
|
#else
|
|
static char csep = '\\';
|
|
#endif
|
|
|
|
static void
|
|
lws_dir_via_stat(char *combo, size_t l, const char *path, struct lws_dir_entry *lde)
|
|
{
|
|
struct stat s;
|
|
|
|
lws_strncpy(combo + l, path, COMBO_SIZEOF - l);
|
|
|
|
lde->type = LDOT_UNKNOWN;
|
|
|
|
if (!stat(combo, &s)) {
|
|
switch (s.st_mode & S_IFMT) {
|
|
case S_IFBLK:
|
|
lde->type = LDOT_BLOCK;
|
|
break;
|
|
case S_IFCHR:
|
|
lde->type = LDOT_CHAR;
|
|
break;
|
|
case S_IFDIR:
|
|
lde->type = LDOT_DIR;
|
|
break;
|
|
case S_IFIFO:
|
|
lde->type = LDOT_FIFO;
|
|
break;
|
|
#if !defined(WIN32)
|
|
case S_IFLNK:
|
|
lde->type = LDOT_LINK;
|
|
break;
|
|
#endif
|
|
case S_IFREG:
|
|
lde->type = LDOT_FILE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb)
|
|
{
|
|
struct lws_dir_entry lde;
|
|
struct dirent **namelist;
|
|
int n, i, ret = 1;
|
|
char combo[COMBO_SIZEOF];
|
|
size_t l;
|
|
|
|
l = (size_t)(ssize_t)lws_snprintf(combo, COMBO_SIZEOF - 2, "%s", dirpath);
|
|
combo[l++] = csep;
|
|
combo[l] = '\0';
|
|
|
|
n = scandir((char *)dirpath, &namelist, filter, alphasort);
|
|
if (n < 0) {
|
|
lwsl_err("Scandir on '%s' failed, errno %d\n", dirpath, LWS_ERRNO);
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < n; i++) {
|
|
#if !defined(__sun) && !defined(__QNX__)
|
|
unsigned int type = namelist[i]->d_type;
|
|
#endif
|
|
if (strchr(namelist[i]->d_name, '~'))
|
|
goto skip;
|
|
lde.name = namelist[i]->d_name;
|
|
|
|
/*
|
|
* some filesystems don't report this (ZFS) and tell that
|
|
* files are LDOT_UNKNOWN
|
|
*/
|
|
|
|
#if defined(__sun) || defined(__QNX__)
|
|
lws_dir_via_stat(combo, l, namelist[i]->d_name, &lde);
|
|
#else
|
|
/*
|
|
* XFS on Linux doesn't fill in d_type at all, always zero.
|
|
*/
|
|
|
|
if (DT_BLK != DT_UNKNOWN && type == DT_BLK)
|
|
lde.type = LDOT_BLOCK;
|
|
else if (DT_CHR != DT_UNKNOWN && type == DT_CHR)
|
|
lde.type = LDOT_CHAR;
|
|
else if (DT_DIR != DT_UNKNOWN && type == DT_DIR)
|
|
lde.type = LDOT_DIR;
|
|
else if (DT_FIFO != DT_UNKNOWN && type == DT_FIFO)
|
|
lde.type = LDOT_FIFO;
|
|
else if (DT_LNK != DT_UNKNOWN && type == DT_LNK)
|
|
lde.type = LDOT_LINK;
|
|
else if (DT_REG != DT_UNKNOWN && type == DT_REG)
|
|
lde.type = LDOT_FILE;
|
|
else if (DT_SOCK != DT_UNKNOWN && type == DT_SOCK)
|
|
lde.type = LDOTT_SOCKET;
|
|
else {
|
|
lde.type = LDOT_UNKNOWN;
|
|
lws_dir_via_stat(combo, l, namelist[i]->d_name, &lde);
|
|
}
|
|
#endif
|
|
if (cb(dirpath, user, &lde)) {
|
|
while (i < n)
|
|
free(namelist[i++]);
|
|
ret = 0; /* told to stop by cb */
|
|
goto bail;
|
|
}
|
|
skip:
|
|
free(namelist[i]);
|
|
}
|
|
|
|
bail:
|
|
free(namelist);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Check filename against one globby filter
|
|
*
|
|
* We can support things like "*.rpm"
|
|
*/
|
|
|
|
static int
|
|
lws_dir_glob_check(const char *nm, const char *filt)
|
|
{
|
|
while (*nm) {
|
|
if (*filt == '*') {
|
|
if (!strcmp(nm, filt + 1))
|
|
return 1;
|
|
} else {
|
|
if (*nm != *filt)
|
|
return 0;
|
|
filt++;
|
|
}
|
|
nm++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We get passed a single filter string, like "*.txt" or "mydir/\*.rpm" or so.
|
|
*/
|
|
|
|
int
|
|
lws_dir_glob_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
|
|
{
|
|
lws_dir_glob_t *filter = (lws_dir_glob_t*)user;
|
|
char path[384];
|
|
|
|
if (!strcmp(lde->name, ".") || !strcmp(lde->name, ".."))
|
|
return 0;
|
|
|
|
if (lde->type == LDOT_DIR)
|
|
return 0;
|
|
|
|
if (lws_dir_glob_check(lde->name, filter->filter)) {
|
|
lws_snprintf(path, sizeof(path), "%s%c%s", dirpath, csep,
|
|
lde->name);
|
|
filter->cb(filter->user, path);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
lws_dir_rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
|
|
{
|
|
char path[384];
|
|
|
|
if (!strcmp(lde->name, ".") || !strcmp(lde->name, ".."))
|
|
return 0;
|
|
|
|
lws_snprintf(path, sizeof(path), "%s%c%s", dirpath, csep, lde->name);
|
|
|
|
if (lde->type == LDOT_DIR) {
|
|
#if !defined(WIN32) && !defined(_WIN32) && !defined(__COVERITY__)
|
|
char dummy[8];
|
|
/*
|
|
* hm... eg, recursive dir symlinks can show up a LDOT_DIR
|
|
* here. If it's a symlink, don't recurse into it.
|
|
*
|
|
* Notice we immediately discard dummy without looking in it.
|
|
* There is no way to get into trouble from its lack of NUL
|
|
* termination in dummy[]. We just wanted to know if it was
|
|
* a symlink at all.
|
|
*
|
|
* Hide this from Coverity since it flags any use of readlink()
|
|
* even if safe.
|
|
*/
|
|
if (readlink(path, dummy, sizeof(dummy)) < 0)
|
|
#endif
|
|
lws_dir(path, NULL, lws_dir_rm_rf_cb);
|
|
|
|
if (rmdir(path))
|
|
lwsl_warn("%s: rmdir %s failed %d\n", __func__, path, errno);
|
|
} else {
|
|
if (unlink(path)) {
|
|
#if defined(WIN32)
|
|
SetFileAttributesA(path, FILE_ATTRIBUTE_NORMAL);
|
|
if (unlink(path))
|
|
#else
|
|
if (rmdir(path))
|
|
#endif
|
|
lwsl_warn("%s: unlink %s failed %d (type %d)\n",
|
|
__func__, path, errno, lde->type);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_PLUGINS_API)
|
|
|
|
struct lws_plugin *
|
|
lws_plugin_alloc(struct lws_plugin **pplugin)
|
|
{
|
|
struct lws_plugin *pin = lws_malloc(sizeof(*pin), __func__);
|
|
|
|
if (!pin)
|
|
return NULL;
|
|
|
|
pin->list = *pplugin;
|
|
*pplugin = pin;
|
|
|
|
return pin;
|
|
}
|
|
|
|
#if defined(LWS_BUILTIN_PLUGIN_NAMES)
|
|
|
|
extern lws_plugin_protocol_t lws_sshd_demo, lws_ssh_base;
|
|
|
|
lws_plugin_protocol_t *builtin_pcols[] = {
|
|
&lws_sshd_demo, &lws_ssh_base
|
|
};
|
|
|
|
int
|
|
lws_plugins_handle_builtin(struct lws_plugin **pplugin,
|
|
each_plugin_cb_t each, void *each_user)
|
|
{
|
|
size_t n = 0;
|
|
|
|
while (n < LWS_ARRAY_SIZE(builtin_pcols)) {
|
|
struct lws_plugin *pin = lws_plugin_alloc(pplugin);
|
|
if (!pin)
|
|
return 1;
|
|
|
|
pin->u.l = NULL;
|
|
pin->hdr = &builtin_pcols[n]->hdr;
|
|
|
|
if (each)
|
|
each(pin, each_user);
|
|
|
|
n++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
struct lws_plugins_args {
|
|
struct lws_plugin **pplugin;
|
|
const char *_class;
|
|
const char *filter;
|
|
each_plugin_cb_t each;
|
|
void *each_user;
|
|
};
|
|
|
|
static int
|
|
lws_plugins_dir_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
|
|
{
|
|
struct lws_plugins_args *pa = (struct lws_plugins_args *)user;
|
|
char path[256], base[64], *q = base;
|
|
const lws_plugin_header_t *pl;
|
|
const char *p;
|
|
|
|
if (strlen(lde->name) < 7)
|
|
return 0; /* keep going */
|
|
|
|
/*
|
|
* The actual plugin names for protocol plugins look like
|
|
* "libprotocol_lws_ssh_base.so" and for event libs
|
|
* "libwebsockets-evlib_ev.so"... to recover the base name of
|
|
* "lws_ssh_base" and "evlib_ev" we strip from the left to after the
|
|
* first _ or -, and then truncate at the first .
|
|
*/
|
|
|
|
p = lde->name;
|
|
while (*p && *p != '_' && *p != '-')
|
|
p++;
|
|
if (!*p)
|
|
return 0;
|
|
p++;
|
|
while (*p && *p != '.' && lws_ptr_diff(q, base) < (int)sizeof(base) - 1)
|
|
*q++ = *p++;
|
|
*q = '\0';
|
|
|
|
/* if he's given a filter, only match if base matches it */
|
|
if (pa->filter && strcmp(base, pa->filter))
|
|
return 0; /* keep going */
|
|
|
|
lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name);
|
|
|
|
pl = lws_plat_dlopen(pa->pplugin, path, base, pa->_class,
|
|
pa->each, pa->each_user);
|
|
|
|
/*
|
|
* If we were looking for a specific plugin, finding it should make
|
|
* us stop looking (eg, to account for directory precedence of the
|
|
* same plugin). If scanning for plugins in a dir, we always keep
|
|
* going.
|
|
*/
|
|
|
|
return pa->filter && pl;
|
|
}
|
|
|
|
int
|
|
lws_plugins_init(struct lws_plugin **pplugin, const char * const *d,
|
|
const char *_class, const char *filter,
|
|
each_plugin_cb_t each, void *each_user)
|
|
{
|
|
struct lws_plugins_args pa;
|
|
char *ld_env;
|
|
int ret = 1;
|
|
|
|
pa.pplugin = pplugin;
|
|
pa._class = _class;
|
|
pa.each = each;
|
|
pa.each_user = each_user;
|
|
pa.filter = filter;
|
|
|
|
/*
|
|
* Check LD_LIBRARY_PATH override path first if present
|
|
*/
|
|
|
|
ld_env = getenv("LD_LIBRARY_PATH");
|
|
if (ld_env) {
|
|
char temp[128];
|
|
struct lws_tokenize ts;
|
|
|
|
memset(&ts, 0, sizeof(ts));
|
|
ts.start = ld_env;
|
|
ts.len = strlen(ld_env);
|
|
ts.flags = LWS_TOKENIZE_F_SLASH_NONTERM |
|
|
LWS_TOKENIZE_F_DOT_NONTERM |
|
|
LWS_TOKENIZE_F_MINUS_NONTERM |
|
|
LWS_TOKENIZE_F_NO_INTEGERS |
|
|
LWS_TOKENIZE_F_NO_FLOATS;
|
|
|
|
do {
|
|
ts.e = (int8_t)lws_tokenize(&ts);
|
|
if (ts.e != LWS_TOKZE_TOKEN)
|
|
continue;
|
|
|
|
lws_strnncpy(temp, ts.token,
|
|
ts.token_len,
|
|
sizeof(temp));
|
|
|
|
lwsl_info("%s: trying %s\n", __func__, temp);
|
|
if (!lws_dir(temp, &pa, lws_plugins_dir_cb))
|
|
ret = 0;
|
|
|
|
} while (ts.e > 0);
|
|
}
|
|
|
|
while (d && *d) {
|
|
lwsl_info("%s: trying %s\n", __func__, *d);
|
|
if (!lws_dir(*d, &pa, lws_plugins_dir_cb))
|
|
ret = 0;
|
|
|
|
d++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each,
|
|
void *each_user)
|
|
{
|
|
struct lws_plugin *p = *pplugin, *p1;
|
|
|
|
while (p) {
|
|
if (each)
|
|
each(p, each_user);
|
|
if (p->u.l)
|
|
lws_plat_destroy_dl(p);
|
|
p1 = p->list;
|
|
p->list = NULL;
|
|
lws_free(p);
|
|
p = p1;
|
|
}
|
|
|
|
*pplugin = NULL;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|