init
This commit is contained in:
commit
d2a3bcb744
32 changed files with 3298 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.a
|
||||
*.o
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2026, Pyrite development team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
24
Makefile
Normal file
24
Makefile
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# This is jst a template... PPR can be built manually pretty easily
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
|
||||
.PHONY: all install clean
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
OBJS = src/core.o
|
||||
OBJS += src/base/poll.o src/base/file.o src/base/socket.o src/base/arpa.o src/base/string.o src/base/dlfcn.o src/base/unistd.o src/base/stat.o src/base/dirent.o src/base/time.o
|
||||
OBJS += src/base/mutex.o src/base/thread.o src/base/process.o
|
||||
OBJS += src/hash/md5.o src/hash/sha256.o src/hash/blake2s.o
|
||||
OBJS += src/misc/url.o src/misc/wildcard.o
|
||||
|
||||
all: libppr.a
|
||||
|
||||
.c.o:
|
||||
$(CC) -c -I include -o $@ $<
|
||||
|
||||
libppr.a: $(OBJS)
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f *.a src/*.o src/*/*.o
|
||||
15
include/ppr.h
Normal file
15
include/ppr.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef __PPR_H__
|
||||
#define __PPR_H__
|
||||
|
||||
#include <ppr_base.h>
|
||||
|
||||
/* hash */
|
||||
#include <ppr_sha256.h>
|
||||
#include <ppr_md5.h>
|
||||
#include <ppr_blake2s.h>
|
||||
|
||||
/* misc */
|
||||
#include <ppr_url.h>
|
||||
#include <ppr_wildcard.h>
|
||||
|
||||
#endif
|
||||
230
include/ppr_base.h
Normal file
230
include/ppr_base.h
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
#ifndef __PPR_BASE_H__
|
||||
#define __PPR_BASE_H__
|
||||
|
||||
#include <ppr_machdep.h>
|
||||
|
||||
/* poll.c definitions */
|
||||
#define PPR_POLLIN (1 << 0)
|
||||
#define PPR_POLLPRI (1 << 1)
|
||||
#define PPR_POLLOUT (1 << 2)
|
||||
|
||||
struct ppr_pollfd {
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
|
||||
void* user;
|
||||
};
|
||||
|
||||
/* file.c definitions */
|
||||
typedef void PPR_FILE;
|
||||
|
||||
/* socket.c definitions */
|
||||
enum ppr_socket_protocol {
|
||||
PPR_PF_UNSPEC = 0,
|
||||
PPR_PF_INET,
|
||||
PPR_PF_INET6,
|
||||
PPR_PF_UNIX
|
||||
};
|
||||
|
||||
enum ppr_socket_address {
|
||||
PPR_AF_UNSPEC = 0,
|
||||
PPR_AF_INET,
|
||||
PPR_AF_INET6,
|
||||
PPR_AF_UNIX
|
||||
};
|
||||
|
||||
enum ppr_socket_type {
|
||||
PPR_SOCK_STREAM = 0,
|
||||
PPR_SOCK_DGRAM
|
||||
};
|
||||
|
||||
enum ppr_socket_ip_protocol {
|
||||
PPR_IPPROTO_TCP = 1,
|
||||
PPR_IPPROTO_UDP
|
||||
};
|
||||
|
||||
struct ppr_sockaddr {
|
||||
unsigned short sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
union ppr_in_addr_union {
|
||||
ppr_uint8_t addr8[4];
|
||||
ppr_uint16_t addr16[2];
|
||||
ppr_uint32_t addr32[1];
|
||||
};
|
||||
|
||||
struct ppr_in_addr {
|
||||
union ppr_in_addr_union u;
|
||||
};
|
||||
|
||||
struct ppr_sockaddr_in {
|
||||
unsigned short sin_family;
|
||||
ppr_uint16_t sin_port;
|
||||
struct ppr_in_addr sin_addr;
|
||||
};
|
||||
|
||||
union ppr_in6_addr_union {
|
||||
ppr_uint8_t addr8[16];
|
||||
ppr_uint16_t addr16[8];
|
||||
ppr_uint32_t addr32[4];
|
||||
};
|
||||
|
||||
struct ppr_in6_addr {
|
||||
union ppr_in6_addr_union u;
|
||||
};
|
||||
|
||||
struct ppr_sockaddr_in6 {
|
||||
unsigned short sin6_family;
|
||||
ppr_uint16_t sin6_port;
|
||||
struct ppr_in6_addr sin6_addr;
|
||||
};
|
||||
|
||||
struct ppr_sockaddr_storage {
|
||||
unsigned short ss_family;
|
||||
char ss_pad[128];
|
||||
};
|
||||
|
||||
struct ppr_sockaddr_un {
|
||||
unsigned short sun_family;
|
||||
char sun_path[104];
|
||||
};
|
||||
|
||||
/* stat.c definitions */
|
||||
#define PPR_S_IFREG (1 << 0)
|
||||
#define PPR_S_IFDIR (1 << 1)
|
||||
#define PPR_S_ISREG(x) ((x) & PPR_S_IFREG)
|
||||
#define PPR_S_ISDIR(x) ((x) & PPR_S_IFDIR)
|
||||
|
||||
struct ppr_stat {
|
||||
ppr_size_t st_size;
|
||||
ppr_time_t st_modtime;
|
||||
int st_mode;
|
||||
};
|
||||
|
||||
/* dirent.c definitions */
|
||||
typedef void PPR_DIR;
|
||||
|
||||
struct ppr_dirent {
|
||||
char d_name[512];
|
||||
char d_fullname[1024];
|
||||
struct ppr_stat d_stat;
|
||||
};
|
||||
|
||||
/* time.c definitions */
|
||||
struct ppr_tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
|
||||
/* thread.c definitions */
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
struct ppr_semaphore_usage {
|
||||
long sem;
|
||||
ppr_bool used;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* core.c */
|
||||
void ppr_init(void);
|
||||
void ppr_uninit(void);
|
||||
|
||||
/* poll.c */
|
||||
int ppr_poll(struct ppr_pollfd* fds, int nfds, int timeout);
|
||||
|
||||
/* file.c */
|
||||
PPR_FILE* ppr_fopen(const char* path, const char* mode);
|
||||
int ppr_fread(void* ptr, int size, int nmemb, PPR_FILE* stream);
|
||||
int ppr_fwrite(const void* ptr, int size, int nmemb, PPR_FILE* stream);
|
||||
void ppr_fclose(PPR_FILE* stream);
|
||||
|
||||
/* socket.c */
|
||||
extern struct ppr_in_addr ppr_inaddr_any;
|
||||
extern struct ppr_in6_addr ppr_in6addr_any;
|
||||
|
||||
void ppr_socket_init(void);
|
||||
int ppr_socket(int domain, int type, int protocol);
|
||||
int ppr_recv(int s, void* buf, int len, int flags);
|
||||
int ppr_send(int s, const void* msg, int len, int flags);
|
||||
int ppr_bind(int s, const struct ppr_sockaddr* name, int namelen);
|
||||
int ppr_connect(int s, const struct ppr_sockaddr* name, int namelen);
|
||||
int ppr_listen(int s, int backlog);
|
||||
int ppr_accept(int s, struct ppr_sockaddr* addr, int* addrlen);
|
||||
void ppr_socket_close(int d);
|
||||
void ppr_socket_uninit(void);
|
||||
ppr_bool ppr_socket_has_ipv6(void);
|
||||
|
||||
/* arpa.c */
|
||||
ppr_uint16_t ppr_htons(ppr_uint16_t host16);
|
||||
const char* ppr_inet_ntop(struct ppr_sockaddr* src, char* dst);
|
||||
struct ppr_sockaddr* ppr_inet_addr(const char* addr, int* len);
|
||||
|
||||
/* string.c */
|
||||
char* ppr_strdup(const char* str);
|
||||
char* ppr_strvacat(const char* a, ...);
|
||||
void ppr_strappend(char** dst, const char* src);
|
||||
char* ppr_strsafehtml(const char* s);
|
||||
|
||||
/* dlfcn.c */
|
||||
void* ppr_dlopen(const char* path);
|
||||
void* ppr_dlsym(void* handle, const char* symbol);
|
||||
int ppr_dlclose(void* handle);
|
||||
|
||||
/* unistd.c */
|
||||
int ppr_gethostname(char* name, int namelen);
|
||||
void ppr_msleep(int ms);
|
||||
|
||||
/* stat.c */
|
||||
int ppr_stat(const char* path, struct ppr_stat* s);
|
||||
|
||||
/* thread.c */
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
extern struct ppr_semaphore_usage ppr_semaphores[];
|
||||
|
||||
long ppr_thread_open_semaphore(long initial);
|
||||
void ppr_thread_close_semaphore(long sem);
|
||||
#endif
|
||||
|
||||
void* ppr_thread_create(void (*entry)(void* param), void* param);
|
||||
void ppr_thread_join(void* handle);
|
||||
void ppr_thread_destroy(void* handle);
|
||||
void ppr_thread_init(void);
|
||||
void ppr_thread_uninit(void);
|
||||
|
||||
/* mutex.c */
|
||||
void* ppr_mutex_create(void);
|
||||
void ppr_mutex_lock(void* handle);
|
||||
void ppr_mutex_unlock(void* handle);
|
||||
void ppr_mutex_destroy(void* handle);
|
||||
|
||||
/* process.c */
|
||||
void* ppr_process_create(const char* exec, char** env);
|
||||
void ppr_process_close(void* handle);
|
||||
int ppr_process_write(void* handle, const void* data, int len);
|
||||
int ppr_process_read(void* handle, void* data, int len);
|
||||
void ppr_process_destroy(void* handle);
|
||||
|
||||
/* dirent.c */
|
||||
PPR_DIR* ppr_opendir(const char* path);
|
||||
struct ppr_dirent* ppr_readdir(PPR_DIR* handle);
|
||||
void ppr_closedir(PPR_DIR* handle);
|
||||
int ppr_scandir(const char* dirname, struct ppr_dirent*** namelist, int (*selectfn)(const struct ppr_dirent* d), int (*compar)(const struct ppr_dirent** d1, const struct ppr_dirent** d2));
|
||||
int ppr_alphasort(const struct ppr_dirent** d1, const struct ppr_dirent** d2);
|
||||
|
||||
/* time.c */
|
||||
extern void* ppr_gmtime_mutex;
|
||||
extern void* ppr_localtime_mutex;
|
||||
|
||||
ppr_time_t ppr_time(void);
|
||||
void ppr_gmtime(struct ppr_tm* tm, ppr_time_t t);
|
||||
void ppr_localtime(struct ppr_tm* tm, ppr_time_t t);
|
||||
|
||||
#endif
|
||||
78
include/ppr_blake2s.h
Normal file
78
include/ppr_blake2s.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
#ifndef PPR_BLAKE2S_H
|
||||
#define PPR_BLAKE2S_H
|
||||
|
||||
#include <ppr_machdep.h>
|
||||
|
||||
enum ppr_blake2s_constant {
|
||||
BLAKE2S_BLOCKBYTES = 64,
|
||||
BLAKE2S_OUTBYTES = 32,
|
||||
BLAKE2S_KEYBYTES = 32,
|
||||
BLAKE2S_SALTBYTES = 8,
|
||||
BLAKE2S_PERSONALBYTES = 8
|
||||
};
|
||||
|
||||
typedef struct ppr_blake2s_state__ {
|
||||
ppr_uint32_t h[8];
|
||||
ppr_uint32_t t[2];
|
||||
ppr_uint32_t f[2];
|
||||
ppr_uint8_t buf[BLAKE2S_BLOCKBYTES];
|
||||
ppr_size_t buflen;
|
||||
ppr_size_t outlen;
|
||||
ppr_uint8_t last_node;
|
||||
} ppr_blake2s_state;
|
||||
|
||||
#ifdef PPR_HAS_PACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct ppr_blake2s_param__ {
|
||||
ppr_uint8_t digest_length; /* 1 */
|
||||
ppr_uint8_t key_length; /* 2 */
|
||||
ppr_uint8_t fanout; /* 3 */
|
||||
ppr_uint8_t depth; /* 4 */
|
||||
ppr_uint32_t leaf_length; /* 8 */
|
||||
ppr_uint32_t node_offset; /* 12 */
|
||||
ppr_uint16_t xof_length; /* 14 */
|
||||
ppr_uint8_t node_depth; /* 15 */
|
||||
ppr_uint8_t inner_length; /* 16 */
|
||||
/* ppr_uint8_t reserved[0]; */
|
||||
ppr_uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
|
||||
ppr_uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
|
||||
};
|
||||
#ifdef PPR_HAS_PACK
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
typedef struct ppr_blake2s_param__ ppr_blake2s_param;
|
||||
|
||||
#if 0
|
||||
/* Padded structs result in a compile-time error */
|
||||
enum {
|
||||
BLAKE2_DUMMY_1 = 1/(int)(sizeof(ppr_blake2s_param) == BLAKE2S_OUTBYTES)
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Streaming API */
|
||||
int ppr_blake2s_init(ppr_blake2s_state* S, ppr_size_t outlen);
|
||||
int ppr_blake2s_init_key(ppr_blake2s_state* S, ppr_size_t outlen, const void* key, ppr_size_t keylen);
|
||||
int ppr_blake2s_init_param(ppr_blake2s_state* S, const ppr_blake2s_param* P);
|
||||
int ppr_blake2s_update(ppr_blake2s_state* S, const void* in, ppr_size_t inlen);
|
||||
int ppr_blake2s_final(ppr_blake2s_state* S, void* out, ppr_size_t outlen);
|
||||
|
||||
/* Simple API */
|
||||
int ppr_blake2s(void* out, ppr_size_t outlen, const void* in, ppr_size_t inlen, const void* key, ppr_size_t keylen);
|
||||
|
||||
#endif
|
||||
87
include/ppr_int.h
Normal file
87
include/ppr_int.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef __PPR_INT_H__
|
||||
#define __PPR_INT_H__
|
||||
|
||||
/* generic section */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <nwnamspc.h>
|
||||
#include <nwadv.h>
|
||||
#endif
|
||||
|
||||
#if defined(PPR_IS_UNIX)
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#if defined(PPR_IS_UNIX) || defined(PPR_IS_PSP) || defined(PPR_IS_PS2) || defined(PPR_IS_NETWARE)
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
/* thread section */
|
||||
#if defined(PPR_IS_WIN32)
|
||||
#if !defined(PPR_USE_CREATETHREAD)
|
||||
#include <process.h>
|
||||
#endif
|
||||
#elif defined(PPR_IS_UNIX) || defined(PPR_IS_PSP) || defined(PPR_IS_PS2)
|
||||
#include <pthread.h>
|
||||
#define PPR_USE_PTHREAD
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
#include <nwthread.h>
|
||||
#include <nwsemaph.h>
|
||||
#endif
|
||||
|
||||
/* socket section */
|
||||
#if defined(PPR_IS_WIN32)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <ws2ipdef.h>
|
||||
|
||||
#ifndef IPPROTO_IPV6
|
||||
#define IPPROTO_IPV6 41
|
||||
#endif
|
||||
|
||||
#ifndef IPV6_V6ONLY
|
||||
#define IPV6_V6ONLY 27
|
||||
#endif
|
||||
#else
|
||||
#if defined(PPR_HAS_POLL)
|
||||
#include <poll.h>
|
||||
#else
|
||||
|
||||
#if !defined(PPR_IS_NETWARE)
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
#include <sys/bsdskt.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#if defined(PPR_HAS_UNIX_SOCKET)
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* windows.h wants to be the last one included */
|
||||
#if defined(PPR_IS_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
100
include/ppr_machdep.h
Normal file
100
include/ppr_machdep.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#ifndef __PPR_MACHDEP_H__
|
||||
#define __PPR_MACHDEP_H__
|
||||
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__sun__)
|
||||
#define PPR_IS_UNIX
|
||||
#elif defined(_WIN32)
|
||||
#define PPR_IS_WIN32
|
||||
#elif defined(_PSP)
|
||||
#define PPR_IS_PSP
|
||||
#elif defined(_EE)
|
||||
#define PPR_IS_PS2
|
||||
#elif defined(__NETWARE__)
|
||||
#define PPR_IS_NETWARE
|
||||
#endif
|
||||
|
||||
/*** Platform differences */
|
||||
|
||||
#if defined(PPR_IS_WIN32) || defined(PPR_IS_NETWARE)
|
||||
#define ppr_newline "\r\n"
|
||||
#else
|
||||
#define ppr_newline "\n"
|
||||
#endif
|
||||
|
||||
#undef PPR_HAS_IPV6
|
||||
#undef PPR_HAS_POLL
|
||||
#undef PPR_HAS_FORK
|
||||
#undef PPR_HAS_UNIX_SOCKET
|
||||
#undef PPR_USE_SOCKLEN_T
|
||||
|
||||
/* Windows */
|
||||
#if defined(PPR_IS_WIN32)
|
||||
#define PPR_HAS_IPV6
|
||||
#endif
|
||||
|
||||
/* PSP/PS2 */
|
||||
#if defined(PPR_IS_PSP) || defined(PPR_IS_PS2)
|
||||
#define PPR_USE_SOCKLEN_T
|
||||
#endif
|
||||
|
||||
/* NetWare */
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
/* Nothing */
|
||||
#endif
|
||||
|
||||
/* BSD family */
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__sun__)
|
||||
#define PPR_HAS_IPV6
|
||||
#define PPR_HAS_POLL
|
||||
#define PPR_HAS_FORK
|
||||
#define PPR_HAS_UNIX_SOCKET
|
||||
#define PPR_USE_SOCKLEN_T
|
||||
#endif
|
||||
|
||||
/*** Compiler differences ***/
|
||||
|
||||
#undef PPR_HAS_PACK
|
||||
|
||||
#if defined(__WATCOMC__) || defined(__GNUC__)
|
||||
#define PPR_HAS_PACK
|
||||
#endif
|
||||
|
||||
typedef unsigned char ppr_bool;
|
||||
#define ppr_false 0
|
||||
#define ppr_true 1
|
||||
|
||||
#if defined(_MSC_VER) || defined(__WATCOMC__)
|
||||
typedef unsigned __int8 ppr_uint8_t;
|
||||
typedef unsigned __int16 ppr_uint16_t;
|
||||
typedef unsigned __int32 ppr_uint32_t;
|
||||
|
||||
typedef __int8 ppr_int8_t;
|
||||
typedef __int16 ppr_int16_t;
|
||||
typedef __int32 ppr_int32_t;
|
||||
|
||||
typedef __int64 ppr_size_t;
|
||||
#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) || defined(__clang__))
|
||||
typedef unsigned char ppr_uint8_t;
|
||||
typedef unsigned short ppr_uint16_t;
|
||||
typedef unsigned int ppr_uint32_t;
|
||||
|
||||
typedef signed char ppr_int8_t;
|
||||
typedef short ppr_int16_t;
|
||||
typedef int ppr_int32_t;
|
||||
|
||||
typedef long long ppr_size_t;
|
||||
#else
|
||||
typedef unsigned char ppr_uint8_t;
|
||||
typedef unsigned short ppr_uint16_t;
|
||||
typedef unsigned int ppr_uint32_t;
|
||||
|
||||
typedef signed char ppr_int8_t;
|
||||
typedef short ppr_int16_t;
|
||||
typedef int ppr_int32_t;
|
||||
|
||||
typedef long ppr_size_t;
|
||||
#endif
|
||||
|
||||
typedef ppr_size_t ppr_time_t;
|
||||
|
||||
#endif
|
||||
43
include/ppr_md5.h
Normal file
43
include/ppr_md5.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
|
||||
** **
|
||||
** License to copy and use this software is granted provided that **
|
||||
** it is identified as the "RSA Data Security, Inc. MD5 Message **
|
||||
** Digest Algorithm" in all material mentioning or referencing this **
|
||||
** software or this function. **
|
||||
** **
|
||||
** License is also granted to make and use derivative works **
|
||||
** provided that such works are identified as "derived from the RSA **
|
||||
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
|
||||
** material mentioning or referencing the derived work. **
|
||||
** **
|
||||
** RSA Data Security, Inc. makes no representations concerning **
|
||||
** either the merchantability of this software or the suitability **
|
||||
** of this software for any particular purpose. It is provided "as **
|
||||
** is" without express or implied warranty of any kind. **
|
||||
** **
|
||||
** These notices must be retained in any copies of any part of this **
|
||||
** documentation and/or software. **
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __PPR_MD5_H__
|
||||
#define __PPR_MD5_H__
|
||||
|
||||
#include <ppr_machdep.h>
|
||||
|
||||
typedef struct ppr_md5_context ppr_md5_context_t;
|
||||
|
||||
struct ppr_md5_context {
|
||||
ppr_uint32_t i[2]; /* number of _bits_ handled mod 2^64 */
|
||||
ppr_uint32_t buf[4]; /* scratch buffer */
|
||||
unsigned char in[64]; /* input buffer */
|
||||
unsigned char digest[16]; /* actual digest after MD5Final call */
|
||||
};
|
||||
|
||||
void ppr_md5_init(ppr_md5_context_t* mdContext);
|
||||
void ppr_md5_update(ppr_md5_context_t* mdContext, const void* inBuf, unsigned int inLen);
|
||||
void ppr_md5_final(ppr_md5_context_t* mdContext);
|
||||
|
||||
#endif
|
||||
8
include/ppr_sha256.h
Normal file
8
include/ppr_sha256.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __PPR_SHA256_H__
|
||||
#define __PPR_SHA256_H__
|
||||
|
||||
#include <ppr_machdep.h>
|
||||
|
||||
void ppr_sha256(void* output, const void* data, ppr_size_t len);
|
||||
|
||||
#endif
|
||||
25
include/ppr_url.h
Normal file
25
include/ppr_url.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef __PPR_URL_H__
|
||||
#define __PPR_URL_H__
|
||||
|
||||
#include <ppr_machdep.h>
|
||||
|
||||
typedef struct ppr_url ppr_url_t;
|
||||
|
||||
struct ppr_url {
|
||||
char* scheme;
|
||||
char* userinfo;
|
||||
char* host;
|
||||
int port;
|
||||
char* path;
|
||||
char* query;
|
||||
char* fragment;
|
||||
};
|
||||
|
||||
ppr_bool ppr_url_decode(char* out, const char* input, int len);
|
||||
ppr_bool ppr_url_encode(char* out, const char* input, int len);
|
||||
|
||||
void ppr_url_init(ppr_url_t* url);
|
||||
ppr_bool ppr_url_parse(ppr_url_t* url, const char* str);
|
||||
void ppr_url_deinit(ppr_url_t* url);
|
||||
|
||||
#endif
|
||||
8
include/ppr_wildcard.h
Normal file
8
include/ppr_wildcard.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __PPR_WILDCARD_H__
|
||||
#define __PPR_WILDCARD_H__
|
||||
|
||||
#include <ppr_machdep.h>
|
||||
|
||||
ppr_bool ppr_wildcard(const char* wildcard, const char* target);
|
||||
|
||||
#endif
|
||||
247
src/base/arpa.c
Normal file
247
src/base/arpa.c
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
ppr_uint16_t ppr_htons(ppr_uint16_t host16) {
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
unsigned char buf[2];
|
||||
|
||||
buf[0] = (host16 >> 8) & 0xff;
|
||||
buf[1] = (host16 >> 0) & 0xff;
|
||||
|
||||
return *(ppr_uint16_t*)buf;
|
||||
#else
|
||||
return htons(host16);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int sort_v6(const void* _a, const void* _b) {
|
||||
int* a = (int*)_a;
|
||||
int* b = (int*)_b;
|
||||
|
||||
if(a[1] > b[1]) return -1;
|
||||
if(a[1] < b[1]) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* ppr_inet_ntop(struct ppr_sockaddr* src, char* dst) {
|
||||
if(src->sa_family == PPR_AF_INET) {
|
||||
struct ppr_sockaddr_in* addr = (struct ppr_sockaddr_in*)src;
|
||||
int i;
|
||||
|
||||
dst[0] = 0;
|
||||
|
||||
for(i = 0; i < 4; i++) {
|
||||
if(i > 0) strcat(dst, ".");
|
||||
sprintf(dst + strlen(dst), "%d", (int)addr->sin_addr.u.addr8[i]);
|
||||
}
|
||||
return dst;
|
||||
} else if(src->sa_family == PPR_AF_INET6) {
|
||||
struct ppr_sockaddr_in6* addr = (struct ppr_sockaddr_in6*)src;
|
||||
int i;
|
||||
char v6[8][5];
|
||||
int l[8][2]; /* index, count */
|
||||
int c = -1;
|
||||
int z = 0;
|
||||
int max = 8;
|
||||
|
||||
dst[0] = 0;
|
||||
|
||||
for(i = 0; i < 16; i += 2) {
|
||||
v6[i / 2][0] = 0;
|
||||
|
||||
if(addr->sin6_addr.u.addr8[i + 0] > 0) {
|
||||
sprintf(v6[i / 2], "%x", (int)addr->sin6_addr.u.addr8[i + 0]);
|
||||
}
|
||||
if(addr->sin6_addr.u.addr8[i + 0] > 0 && !(addr->sin6_addr.u.addr8[i + 1] & 0xf0)) strcat(v6[i / 2], "0");
|
||||
sprintf(v6[i / 2] + strlen(v6[i / 2]), "%x", (int)addr->sin6_addr.u.addr8[i + 1]);
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++) l[i][0] = l[i][1] = 0;
|
||||
|
||||
for(i = 7; i >= 0; i--) {
|
||||
if(z && strcmp(v6[i], "0") == 0) {
|
||||
l[c][0] = i;
|
||||
l[c][1]++;
|
||||
continue;
|
||||
} else if(z) {
|
||||
z = 0;
|
||||
}
|
||||
|
||||
if(strcmp(v6[i], "0") == 0) {
|
||||
z = 1;
|
||||
|
||||
c++;
|
||||
|
||||
l[c][0] = i;
|
||||
l[c][1] = 1;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
qsort(l, 8, sizeof(int) * 2, sort_v6);
|
||||
|
||||
dst[0] = 0;
|
||||
for(i = 0; i < max; i++) {
|
||||
if(i > 0 || l[0][1] == 8) strcat(dst, ":");
|
||||
if(i == l[0][0] && l[0][1] > 0) {
|
||||
if(i == 0 || (i + l[0][1] - 1) == (max - 1)) strcat(dst, ":");
|
||||
|
||||
i += l[0][1] - 1;
|
||||
} else {
|
||||
strcat(dst, v6[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(memcmp(dst, "::ffff:", 7) == 0) {
|
||||
struct ppr_sockaddr_in in;
|
||||
|
||||
dst[7] = 0;
|
||||
|
||||
in.sin_family = PPR_AF_INET;
|
||||
memcpy(&in.sin_addr, &addr->sin6_addr.u.addr8[12], 4);
|
||||
|
||||
ppr_inet_ntop((struct ppr_sockaddr*)&in, dst + 7);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ppr_sockaddr* ppr_inet_addr(const char* addr, int* len) {
|
||||
int d = 0;
|
||||
int i;
|
||||
const char* v4[4];
|
||||
|
||||
v4[0] = addr;
|
||||
|
||||
for(i = 0; addr[i] != 0; i++) {
|
||||
if(addr[i] == '.') {
|
||||
d++;
|
||||
|
||||
v4[d] = &addr[i + 1];
|
||||
} else if('0' <= addr[i] && addr[i] <= '9') {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* IPv4 */
|
||||
if(d == 3 && addr[i] == 0) {
|
||||
struct ppr_sockaddr_in* in = malloc(sizeof(*in));
|
||||
|
||||
in->sin_family = PPR_AF_INET;
|
||||
for(i = 0; i < 4; i++) in->sin_addr.u.addr8[i] = atoi(v4[i]);
|
||||
|
||||
*len = sizeof(*in);
|
||||
|
||||
return (struct ppr_sockaddr*)in;
|
||||
}
|
||||
|
||||
for(i = 0; addr[i] != 0; i++) {
|
||||
if(addr[i] == '[' && i == 0) {
|
||||
} else if(addr[i] == ']' && i == (strlen(addr) - 1)) {
|
||||
} else if(addr[i] == ':') {
|
||||
} else if('0' <= addr[i] && addr[i] <= '9') {
|
||||
} else if('a' <= addr[i] && addr[i] <= 'f') {
|
||||
} else if('A' <= addr[i] && addr[i] <= 'F') {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* IPv6 */
|
||||
if(addr[i] == 0) {
|
||||
const char* b = addr;
|
||||
int e = 0;
|
||||
struct ppr_sockaddr_in6* in6 = malloc(sizeof(*in6));
|
||||
int incr = 0;
|
||||
|
||||
in6->sin6_family = PPR_AF_INET6;
|
||||
|
||||
memset(in6->sin6_addr.u.addr8, 0, 16);
|
||||
|
||||
for(i = 0;; i++) {
|
||||
if(addr[i] == 0 || addr[i] == ']' || addr[i] == ':') {
|
||||
char* n = malloc(&addr[i] - b + 1);
|
||||
|
||||
n[&addr[i] - b] = 0;
|
||||
memcpy(n, b, &addr[i] - b);
|
||||
|
||||
if(strlen(n) == 0) {
|
||||
e++;
|
||||
} else {
|
||||
int j;
|
||||
int f = strlen(n) - 1;
|
||||
int old = incr;
|
||||
int inc = 0;
|
||||
|
||||
e = 0;
|
||||
|
||||
incr++;
|
||||
for(j = f; j >= 0; j--) {
|
||||
char byte = n[j];
|
||||
|
||||
if('0' <= byte && byte <= '9') {
|
||||
byte = byte - '0';
|
||||
} else if('a' <= byte && byte <= 'f') {
|
||||
byte = byte - 'a' + 10;
|
||||
} else if('A' <= byte && byte <= 'F') {
|
||||
byte = byte - 'A' + 10;
|
||||
}
|
||||
|
||||
in6->sin6_addr.u.addr8[incr] = in6->sin6_addr.u.addr8[incr] | (byte << (4 * inc));
|
||||
inc++;
|
||||
|
||||
if(j == (f - 1)) {
|
||||
incr--;
|
||||
inc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
incr = old + 2;
|
||||
|
||||
if(incr > 16) {
|
||||
free(n);
|
||||
free(in6);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(n);
|
||||
|
||||
if(e == 2) {
|
||||
int len = 16 - incr;
|
||||
int c = 0;
|
||||
int j;
|
||||
|
||||
for(j = i + 1; addr[j] != ']' && addr[j] != 0; j++) {
|
||||
if(j == (i + 1) && !(addr[j] == ']' || addr[j] == 0)) c++;
|
||||
if(addr[j] == ':') c++;
|
||||
}
|
||||
|
||||
incr += len - c * 2;
|
||||
|
||||
if(incr > 16) {
|
||||
free(in6);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
b = &addr[i + 1];
|
||||
|
||||
if(addr[i] == 0 || addr[i] == ']') break;
|
||||
} else if(addr[i] == '[') {
|
||||
b = &addr[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
*len = sizeof(*in6);
|
||||
|
||||
return (struct ppr_sockaddr*)in6;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
125
src/base/dirent.c
Normal file
125
src/base/dirent.c
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
#if defined(PPR_IS_WIN32)
|
||||
typedef struct dir {
|
||||
ppr_bool next;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA ffd;
|
||||
|
||||
char* path;
|
||||
struct ppr_dirent dirent;
|
||||
} dir_t;
|
||||
#else
|
||||
typedef struct dir {
|
||||
DIR* dir;
|
||||
|
||||
char* path;
|
||||
struct ppr_dirent dirent;
|
||||
} dir_t;
|
||||
#endif
|
||||
|
||||
PPR_DIR* ppr_opendir(const char* path) {
|
||||
dir_t* dir = malloc(sizeof(*dir));
|
||||
#if defined(PPR_IS_WIN32)
|
||||
char* p = ppr_strvacat(path, (path[strlen(path) - 1] == '/' || path[strlen(path) - 1] == '\\') ? "" : (strchr(path, '/') != NULL ? "/" : "\\"), "*", NULL);
|
||||
|
||||
if((dir->hFind = FindFirstFile(p, &dir->ffd)) == INVALID_HANDLE_VALUE) {
|
||||
free(p);
|
||||
free(dir);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
free(p);
|
||||
|
||||
dir->next = ppr_true;
|
||||
#else
|
||||
if((dir->dir = opendir(path)) == NULL) {
|
||||
free(dir);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
dir->path = ppr_strdup(path);
|
||||
|
||||
return (PPR_DIR*)dir;
|
||||
}
|
||||
|
||||
struct ppr_dirent* ppr_readdir(PPR_DIR* handle) {
|
||||
dir_t* dir = handle;
|
||||
#if defined(PPR_IS_WIN32)
|
||||
if(!dir->next) return NULL;
|
||||
|
||||
strcpy(dir->dirent.d_name, dir->ffd.cFileName);
|
||||
#else
|
||||
struct dirent* d;
|
||||
|
||||
if((d = readdir(dir->dir)) == NULL) return NULL;
|
||||
|
||||
strcpy(dir->dirent.d_name, d->d_name);
|
||||
#endif
|
||||
|
||||
strcpy(dir->dirent.d_fullname, dir->path);
|
||||
if(dir->path[strlen(dir->path) - 1] != '/' && dir->path[strlen(dir->path) - 1] != '\\') {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
strcat(dir->dirent.d_fullname, strchr(dir->path, '/') != NULL ? "/" : "\\");
|
||||
#else
|
||||
strcat(dir->dirent.d_fullname, "/");
|
||||
#endif
|
||||
}
|
||||
strcat(dir->dirent.d_fullname, dir->dirent.d_name);
|
||||
|
||||
memset(&dir->dirent.d_stat, 0, sizeof(dir->dirent.d_stat));
|
||||
ppr_stat(dir->dirent.d_fullname, &dir->dirent.d_stat);
|
||||
|
||||
return &dir->dirent;
|
||||
}
|
||||
|
||||
void ppr_closedir(PPR_DIR* handle) {
|
||||
dir_t* dir = handle;
|
||||
#if defined(PPR_IS_WIN32)
|
||||
FindClose(dir->hFind);
|
||||
#else
|
||||
closedir(dir->dir);
|
||||
#endif
|
||||
|
||||
free(dir->path);
|
||||
|
||||
free(dir);
|
||||
}
|
||||
|
||||
int ppr_scandir(const char* dirname, struct ppr_dirent*** namelist, int (*selectfn)(const struct ppr_dirent* d), int (*compar)(const struct ppr_dirent** d1, const struct ppr_dirent** d2)) {
|
||||
PPR_DIR* dir = ppr_opendir(dirname);
|
||||
struct ppr_dirent* d;
|
||||
int n = 0;
|
||||
int n2 = 0;
|
||||
if(dir == NULL) return -1;
|
||||
|
||||
while((d = ppr_readdir(dir)) != NULL) n++;
|
||||
|
||||
ppr_closedir(dir);
|
||||
|
||||
if((dir = ppr_opendir(dirname)) == NULL) return -1;
|
||||
|
||||
*namelist = malloc(sizeof(**namelist) * n);
|
||||
|
||||
while(n2 < n && (d = ppr_readdir(dir)) != NULL) {
|
||||
if(selectfn != NULL && !selectfn(d)) continue;
|
||||
|
||||
(*namelist)[n2] = malloc(sizeof(***namelist));
|
||||
memcpy((*namelist)[n2], d, sizeof(*d));
|
||||
|
||||
n2++;
|
||||
}
|
||||
|
||||
ppr_closedir(dir);
|
||||
|
||||
qsort(*namelist, n2, sizeof(**namelist), (int (*)(const void* d1, const void* d2))compar);
|
||||
|
||||
return n2;
|
||||
}
|
||||
|
||||
int ppr_alphasort(const struct ppr_dirent** d1, const struct ppr_dirent** d2) {
|
||||
return strcmp((*d1)->d_name, (*d2)->d_name);
|
||||
}
|
||||
45
src/base/dlfcn.c
Normal file
45
src/base/dlfcn.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
void* ppr_dlopen(const char* path) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
return LoadLibrary(path);
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
return dlopen(path, RTLD_LAZY | RTLD_LOCAL);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
unsigned int handle = FindNLMHandle(path);
|
||||
|
||||
if(handle == 0) {
|
||||
spawnlp(P_NOWAIT | P_SPAWN_IN_CURRENT_DOMAIN, path, NULL);
|
||||
handle = FindNLMHandle(path);
|
||||
}
|
||||
|
||||
return (void*)handle;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void* ppr_dlsym(void* handle, const char* symbol) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
return GetProcAddress(handle, symbol);
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
return dlsym(handle, symbol);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
return ImportSymbol((unsigned int)handle, symbol);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ppr_dlclose(void* handle) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
return FreeLibrary(handle) ? 0 : 1;
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
return dlclose(handle);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
61
src/base/file.c
Normal file
61
src/base/file.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
PPR_FILE* ppr_fopen(const char* path, const char* mode) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
DWORD ac = 0;
|
||||
DWORD dis = 0;
|
||||
DWORD fl = FILE_ATTRIBUTE_NORMAL;
|
||||
HANDLE h;
|
||||
|
||||
if(mode[0] == 'r') {
|
||||
ac = GENERIC_READ;
|
||||
dis = OPEN_EXISTING;
|
||||
} else if(mode[0] == 'w') {
|
||||
ac = GENERIC_WRITE;
|
||||
dis = CREATE_ALWAYS;
|
||||
} else if(mode[0] == 'a') {
|
||||
ac = GENERIC_WRITE | FILE_APPEND_DATA;
|
||||
dis = OPEN_ALWAYS;
|
||||
}
|
||||
|
||||
h = CreateFile(path, ac, FILE_SHARE_READ, NULL, dis, fl, NULL);
|
||||
if(h == INVALID_HANDLE_VALUE) return NULL;
|
||||
|
||||
return (PPR_FILE*)h;
|
||||
#else
|
||||
return (PPR_FILE*)fopen(path, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ppr_fread(void* ptr, int size, int nmemb, PPR_FILE* stream) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
DWORD dw;
|
||||
|
||||
if(!ReadFile((HANDLE)stream, ptr, size * nmemb, &dw, NULL)) return -1;
|
||||
|
||||
return dw;
|
||||
#else
|
||||
return fread(ptr, size, nmemb, (FILE*)stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ppr_fwrite(const void* ptr, int size, int nmemb, PPR_FILE* stream) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
DWORD dw;
|
||||
|
||||
if(!WriteFile((HANDLE)stream, ptr, size * nmemb, &dw, NULL)) return -1;
|
||||
|
||||
return dw;
|
||||
#else
|
||||
return fwrite(ptr, size, nmemb, (FILE*)stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_fclose(PPR_FILE* stream) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
CloseHandle((HANDLE)stream);
|
||||
#else
|
||||
fclose((FILE*)stream);
|
||||
#endif
|
||||
}
|
||||
62
src/base/mutex.c
Normal file
62
src/base/mutex.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
void* ppr_mutex_create(void) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
return CreateEvent(NULL, FALSE, TRUE, NULL);
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
pthread_mutex_t* mutex = malloc(sizeof(*mutex));
|
||||
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
|
||||
return mutex;
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
LONG* mutex = malloc(sizeof(*mutex));
|
||||
|
||||
*mutex = ppr_thread_open_semaphore(1);
|
||||
|
||||
return mutex;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_mutex_lock(void* handle) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
WaitForSingleObject(handle, INFINITE);
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
pthread_mutex_lock(handle);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
WaitOnLocalSemaphore(*(LONG*)handle);
|
||||
#else
|
||||
(void)handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_mutex_unlock(void* handle) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
SetEvent(handle);
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
pthread_mutex_unlock(handle);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
SignalLocalSemaphore(*(LONG*)handle);
|
||||
#else
|
||||
(void)handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_mutex_destroy(void* handle) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
CloseHandle(handle);
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
pthread_mutex_destroy(handle);
|
||||
|
||||
free(handle);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
ppr_thread_close_semaphore(*(LONG*)handle);
|
||||
|
||||
free(handle);
|
||||
#else
|
||||
(void)handle;
|
||||
#endif
|
||||
}
|
||||
62
src/base/poll.c
Normal file
62
src/base/poll.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
int ppr_poll(struct ppr_pollfd* fds, int nfds, int timeout) {
|
||||
#if defined(PPR_HAS_POLL)
|
||||
struct pollfd* pfds = malloc(sizeof(*pfds) * nfds);
|
||||
int i;
|
||||
int st;
|
||||
|
||||
for(i = 0; i < nfds; i++) {
|
||||
pfds[i].fd = fds[i].fd;
|
||||
pfds[i].events = 0;
|
||||
fds[i].revents = 0;
|
||||
|
||||
if(fds[i].events & PPR_POLLIN) pfds[i].events |= POLLIN;
|
||||
if(fds[i].events & PPR_POLLPRI) pfds[i].events |= POLLPRI;
|
||||
if(fds[i].events & PPR_POLLOUT) pfds[i].events |= POLLOUT;
|
||||
}
|
||||
|
||||
st = poll(pfds, nfds, timeout);
|
||||
|
||||
if(st > 0) {
|
||||
for(i = 0; i < nfds; i++) {
|
||||
if(pfds[i].revents & POLLIN) fds[i].revents |= PPR_POLLIN;
|
||||
if(pfds[i].revents & POLLPRI) fds[i].revents |= PPR_POLLPRI;
|
||||
if(pfds[i].revents & POLLOUT) fds[i].revents |= PPR_POLLOUT;
|
||||
}
|
||||
}
|
||||
|
||||
free(pfds);
|
||||
|
||||
return st;
|
||||
#else
|
||||
fd_set rfds;
|
||||
fd_set wfds;
|
||||
int i;
|
||||
struct timeval tv;
|
||||
int st;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
|
||||
for(i = 0; i < nfds; i++) {
|
||||
if(fds[i].events & PPR_POLLIN) FD_SET(fds[i].fd, &rfds);
|
||||
if(fds[i].events & PPR_POLLOUT) FD_SET(fds[i].fd, &wfds);
|
||||
|
||||
fds[i].revents = 0;
|
||||
}
|
||||
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000;
|
||||
|
||||
st = select(FD_SETSIZE, &rfds, &wfds, NULL, &tv);
|
||||
|
||||
for(i = 0; i < nfds; i++) {
|
||||
if(FD_ISSET(fds[i].fd, &rfds)) fds[i].revents |= PPR_POLLIN;
|
||||
if(FD_ISSET(fds[i].fd, &wfds)) fds[i].revents |= PPR_POLLOUT;
|
||||
}
|
||||
|
||||
return st;
|
||||
#endif
|
||||
}
|
||||
271
src/base/process.c
Normal file
271
src/base/process.c
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
typedef struct process {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
HANDLE process;
|
||||
HANDLE thread;
|
||||
HANDLE h_stdin;
|
||||
HANDLE h_stdout;
|
||||
HANDLE h_stderr;
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
pid_t pid;
|
||||
int fd_stdin;
|
||||
int fd_stdout;
|
||||
int fd_stderr;
|
||||
#else
|
||||
void* reserved;
|
||||
#endif
|
||||
} process_t;
|
||||
|
||||
static ppr_bool is_allowed_env(const char* n) {
|
||||
char* p = ppr_strdup(n);
|
||||
char* s;
|
||||
|
||||
if((s = strchr(p, '=')) != NULL) s[0] = 0;
|
||||
|
||||
if(strcmp(p, "PATH") == 0) return ppr_true;
|
||||
|
||||
return ppr_false;
|
||||
}
|
||||
|
||||
void* ppr_process_create(const char* exec, char** env) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
process_t* proc = malloc(sizeof(*proc));
|
||||
SECURITY_ATTRIBUTES attr;
|
||||
HANDLE pipe_stdin[2];
|
||||
HANDLE pipe_stdout[2];
|
||||
HANDLE pipe_stderr[2];
|
||||
char path[2048];
|
||||
char* envs;
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
char* d_envs = GetEnvironmentStrings();
|
||||
char* d_envs2;
|
||||
int envs_len = 0;
|
||||
int i;
|
||||
|
||||
d_envs2 = d_envs;
|
||||
while(*d_envs2) {
|
||||
if(is_allowed_env(d_envs2)) envs_len += strlen(d_envs2) + 1;
|
||||
|
||||
d_envs2 += strlen(d_envs2) + 1;
|
||||
}
|
||||
|
||||
for(i = 0; env[i] != NULL; i++) envs_len += strlen(env[i]) + 1;
|
||||
envs_len++;
|
||||
|
||||
envs = malloc(envs_len);
|
||||
envs_len = 0;
|
||||
|
||||
d_envs2 = d_envs;
|
||||
while(*d_envs2) {
|
||||
if(is_allowed_env(d_envs2)) {
|
||||
strcpy(envs + envs_len, d_envs2);
|
||||
envs_len += strlen(d_envs2) + 1;
|
||||
}
|
||||
|
||||
d_envs2 += strlen(d_envs2) + 1;
|
||||
}
|
||||
|
||||
for(i = 0; env[i] != NULL; i++) {
|
||||
strcpy(envs + envs_len, env[i]);
|
||||
envs_len += strlen(env[i]) + 1;
|
||||
}
|
||||
FreeEnvironmentStrings(d_envs);
|
||||
|
||||
envs[envs_len] = 0;
|
||||
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
|
||||
memset(&si, 0, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
sprintf(path, "\"%s\"", exec);
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.nLength = sizeof(attr);
|
||||
attr.bInheritHandle = TRUE;
|
||||
|
||||
CreatePipe(&pipe_stdin[0], &pipe_stdin[1], &attr, 0);
|
||||
SetHandleInformation(pipe_stdin[1], HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
CreatePipe(&pipe_stdout[0], &pipe_stdout[1], &attr, 0);
|
||||
SetHandleInformation(pipe_stdout[0], HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
CreatePipe(&pipe_stderr[0], &pipe_stderr[1], &attr, 0);
|
||||
SetHandleInformation(pipe_stderr[0], HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
si.hStdInput = pipe_stdin[0];
|
||||
si.hStdOutput = pipe_stdout[1];
|
||||
si.hStdError = pipe_stderr[1];
|
||||
|
||||
if(!CreateProcess(NULL, path, NULL, NULL, TRUE, 0, envs, NULL, &si, &pi)) {
|
||||
int i;
|
||||
|
||||
free(proc);
|
||||
free(envs);
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
CloseHandle(pipe_stdin[i]);
|
||||
CloseHandle(pipe_stdout[i]);
|
||||
CloseHandle(pipe_stderr[i]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} else {
|
||||
CloseHandle(pipe_stdin[0]);
|
||||
CloseHandle(pipe_stdout[1]);
|
||||
CloseHandle(pipe_stderr[1]);
|
||||
|
||||
proc->process = pi.hProcess;
|
||||
proc->thread = pi.hThread;
|
||||
proc->h_stdin = pipe_stdin[1];
|
||||
proc->h_stdout = pipe_stdout[0];
|
||||
proc->h_stderr = pipe_stderr[0];
|
||||
}
|
||||
|
||||
free(envs);
|
||||
|
||||
return proc;
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
process_t* proc = malloc(sizeof(*proc));
|
||||
int pipe_stdin[2];
|
||||
int pipe_stdout[2];
|
||||
int pipe_stderr[2];
|
||||
char** envs = NULL;
|
||||
int i;
|
||||
int c = 0;
|
||||
|
||||
extern char** environ;
|
||||
|
||||
for(i = 0; environ[i] != NULL; i++) {
|
||||
if(is_allowed_env(environ[i])) c++;
|
||||
}
|
||||
for(i = 0; env != NULL && env[i] != NULL; i++) c++;
|
||||
|
||||
envs = malloc(sizeof(*envs) * (c + 1));
|
||||
|
||||
c = 0;
|
||||
for(i = 0; environ[i] != NULL; i++) {
|
||||
if(is_allowed_env(environ[i])) envs[c++] = environ[i];
|
||||
}
|
||||
for(i = 0; env != NULL && env[i] != NULL; i++) envs[c++] = env[i];
|
||||
envs[c] = 0;
|
||||
|
||||
pipe(pipe_stdin);
|
||||
pipe(pipe_stdout);
|
||||
pipe(pipe_stderr);
|
||||
|
||||
if((proc->pid = fork()) == 0) {
|
||||
int basefd = pipe_stdout[1] > pipe_stderr[1] ? pipe_stdout[1] : pipe_stderr[1];
|
||||
int infd = basefd + 3;
|
||||
int outfd = basefd + 4;
|
||||
int errfd = basefd + 5;
|
||||
|
||||
free(proc);
|
||||
|
||||
close(pipe_stdin[1]);
|
||||
close(pipe_stdout[0]);
|
||||
close(pipe_stderr[0]);
|
||||
|
||||
dup2(pipe_stdin[0], infd);
|
||||
dup2(pipe_stdout[1], outfd);
|
||||
dup2(pipe_stderr[1], errfd);
|
||||
close(pipe_stdin[0]);
|
||||
close(pipe_stdout[1]);
|
||||
close(pipe_stderr[1]);
|
||||
dup2(infd, 0);
|
||||
dup2(outfd, 1);
|
||||
dup2(errfd, 2);
|
||||
close(infd);
|
||||
close(outfd);
|
||||
close(errfd);
|
||||
|
||||
execle(exec, exec, NULL, envs);
|
||||
|
||||
_exit(-1);
|
||||
} else {
|
||||
close(pipe_stdin[0]);
|
||||
close(pipe_stdout[1]);
|
||||
close(pipe_stderr[1]);
|
||||
|
||||
proc->fd_stdin = pipe_stdin[1];
|
||||
proc->fd_stdout = pipe_stdout[0];
|
||||
proc->fd_stderr = pipe_stderr[0];
|
||||
}
|
||||
|
||||
free(envs);
|
||||
|
||||
return proc;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_process_close(void* handle) {
|
||||
process_t* proc = handle;
|
||||
#if defined(PPR_IS_WIN32)
|
||||
CloseHandle(proc->h_stdin);
|
||||
proc->h_stdin = NULL;
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
close(proc->fd_stdin);
|
||||
proc->fd_stdin = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ppr_process_write(void* handle, const void* data, int len) {
|
||||
process_t* proc = handle;
|
||||
#if defined(PPR_IS_WIN32)
|
||||
DWORD r;
|
||||
|
||||
if(!WriteFile(proc->h_stdin, data, len, &r, NULL)) return -1;
|
||||
|
||||
return r;
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
return write(proc->fd_stdin, data, len);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ppr_process_read(void* handle, void* data, int len) {
|
||||
process_t* proc = handle;
|
||||
#if defined(PPR_IS_WIN32)
|
||||
DWORD r;
|
||||
|
||||
if(!ReadFile(proc->h_stdout, data, len, &r, NULL)) return -1;
|
||||
|
||||
return r;
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
return read(proc->fd_stdout, data, len);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_process_destroy(void* handle) {
|
||||
process_t* proc = handle;
|
||||
#if defined(PPR_IS_WIN32)
|
||||
if(proc->h_stdin != NULL) CloseHandle(proc->h_stdin);
|
||||
CloseHandle(proc->h_stdout);
|
||||
CloseHandle(proc->h_stderr);
|
||||
|
||||
WaitForSingleObject(proc->process, INFINITE);
|
||||
|
||||
CloseHandle(proc->process);
|
||||
CloseHandle(proc->thread);
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
int st;
|
||||
|
||||
if(proc->fd_stdin >= 0) close(proc->fd_stdin);
|
||||
close(proc->fd_stdout);
|
||||
close(proc->fd_stderr);
|
||||
|
||||
do {
|
||||
waitpid(proc->pid, &st, 0);
|
||||
} while(!WIFEXITED(st));
|
||||
#endif
|
||||
free(proc);
|
||||
}
|
||||
276
src/base/socket.c
Normal file
276
src/base/socket.c
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
#if !defined(IPPROTO_TCP)
|
||||
#define IPPROTO_TCP 0
|
||||
#endif
|
||||
|
||||
#if !defined(IPPROTO_UDP)
|
||||
#define IPPROTO_UDP 0
|
||||
#endif
|
||||
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
struct in_addr {
|
||||
ppr_uint32_t s_addr;
|
||||
};
|
||||
struct sockaddr_in {
|
||||
ppr_uint16_t sin_family;
|
||||
ppr_uint16_t sin_port;
|
||||
struct in_addr sin_addr;
|
||||
ppr_uint8_t sin_zero[8];
|
||||
};
|
||||
#endif
|
||||
|
||||
void ppr_socket_init(void) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
WSADATA wsa;
|
||||
|
||||
WSAStartup(MAKEWORD(2, 0), &wsa);
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_socket_uninit(void) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
WSACleanup();
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
#endif
|
||||
}
|
||||
|
||||
int ppr_socket(int domain, int type, int protocol) {
|
||||
int d = PF_UNSPEC, t = 0, p = 0;
|
||||
int s;
|
||||
int nbyt;
|
||||
|
||||
if(domain == PPR_PF_INET) {
|
||||
d = PF_INET;
|
||||
#if defined(PPR_HAS_IPV6)
|
||||
} else if(domain == PPR_PF_INET6) {
|
||||
d = PF_INET6;
|
||||
#endif
|
||||
#if defined(PPR_HAS_UNIX_SOCKET)
|
||||
} else if(domain == PPR_PF_UNIX) {
|
||||
d = PF_UNIX;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(type == PPR_SOCK_STREAM) {
|
||||
t = SOCK_STREAM;
|
||||
} else if(type == PPR_SOCK_DGRAM) {
|
||||
t = SOCK_DGRAM;
|
||||
}
|
||||
|
||||
if(protocol == PPR_IPPROTO_TCP) {
|
||||
p = IPPROTO_TCP;
|
||||
} else if(protocol == PPR_IPPROTO_UDP) {
|
||||
p = IPPROTO_UDP;
|
||||
}
|
||||
|
||||
s = socket(d, t, p);
|
||||
|
||||
#if defined(PPR_IS_WIN32)
|
||||
if(s == INVALID_SOCKET) s = -1;
|
||||
#endif
|
||||
|
||||
if(s >= 0 && t == SOCK_STREAM && p == IPPROTO_TCP) {
|
||||
int yes = 1;
|
||||
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(yes));
|
||||
}
|
||||
|
||||
#if defined(PPR_HAS_IPV6)
|
||||
if(s >= 0 && d == PF_INET6) {
|
||||
int yes = 1;
|
||||
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(yes));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(s >= 0) {
|
||||
nbyt = 65535;
|
||||
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&nbyt, sizeof(nbyt));
|
||||
nbyt = 65535;
|
||||
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&nbyt, sizeof(nbyt));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* we ignore flags for now */
|
||||
int ppr_recv(int s, void* buf, int len, int flags) {
|
||||
(void)flags;
|
||||
|
||||
return recv(s, buf, len, 0);
|
||||
}
|
||||
|
||||
int ppr_send(int s, const void* msg, int len, int flags) {
|
||||
(void)flags;
|
||||
|
||||
return send(s, (void*)msg, len, 0);
|
||||
}
|
||||
|
||||
static struct sockaddr* conv_to_sa(int* outlen, const struct ppr_sockaddr* input, int namelen) {
|
||||
struct sockaddr* out = NULL;
|
||||
|
||||
if(input->sa_family == PPR_AF_INET && namelen == sizeof(struct ppr_sockaddr_in)) {
|
||||
struct ppr_sockaddr_in* addr = (struct ppr_sockaddr_in*)input;
|
||||
struct sockaddr_in addr4;
|
||||
|
||||
addr4.sin_family = AF_INET;
|
||||
addr4.sin_addr.s_addr = addr->sin_addr.u.addr32[0];
|
||||
addr4.sin_port = addr->sin_port;
|
||||
|
||||
out = malloc(sizeof(addr4));
|
||||
memcpy(out, &addr4, sizeof(addr4));
|
||||
*outlen = sizeof(addr4);
|
||||
#if defined(PPR_HAS_IPV6)
|
||||
} else if(input->sa_family == PPR_AF_INET6 && namelen == sizeof(struct ppr_sockaddr_in6)) {
|
||||
struct ppr_sockaddr_in6* addr = (struct ppr_sockaddr_in6*)input;
|
||||
struct sockaddr_in6 addr6;
|
||||
|
||||
addr6.sin6_family = AF_INET6;
|
||||
memcpy(addr6.sin6_addr.s6_addr, &addr->sin6_addr.u.addr8, 16);
|
||||
addr6.sin6_port = addr->sin6_port;
|
||||
|
||||
out = malloc(sizeof(addr6));
|
||||
memcpy(out, &addr6, sizeof(addr6));
|
||||
*outlen = sizeof(addr6);
|
||||
#endif
|
||||
#if defined(PPR_HAS_UNIX_SOCKET)
|
||||
} else if(input->sa_family == PPR_AF_UNIX && namelen == sizeof(struct ppr_sockaddr_un)) {
|
||||
struct ppr_sockaddr_un* addr = (struct ppr_sockaddr_un*)input;
|
||||
struct sockaddr_un addru;
|
||||
|
||||
addru.sun_family = AF_UNIX;
|
||||
strcpy(addru.sun_path, addr->sun_path);
|
||||
|
||||
out = malloc(sizeof(addru));
|
||||
memcpy(out, &addru, sizeof(addru));
|
||||
*outlen = sizeof(addru);
|
||||
#endif
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int ppr_bind(int s, const struct ppr_sockaddr* name, int namelen) {
|
||||
int st = -1;
|
||||
int yes = 1;
|
||||
struct sockaddr* sa;
|
||||
int len;
|
||||
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes));
|
||||
if((sa = conv_to_sa(&len, name, namelen)) != NULL) {
|
||||
st = bind(s, sa, len);
|
||||
free(sa);
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
int ppr_connect(int s, const struct ppr_sockaddr* name, int namelen) {
|
||||
int st = -1;
|
||||
struct sockaddr* sa;
|
||||
int len;
|
||||
|
||||
if((sa = conv_to_sa(&len, name, namelen)) != NULL) {
|
||||
st = connect(s, sa, len);
|
||||
free(sa);
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
int ppr_listen(int s, int backlog) {
|
||||
return listen(s, backlog);
|
||||
}
|
||||
|
||||
int ppr_accept(int s, struct ppr_sockaddr* addr, int* addrlen) {
|
||||
unsigned char buffer[256];
|
||||
struct sockaddr* sa = (struct sockaddr*)buffer;
|
||||
int r;
|
||||
#if defined(PPR_USE_SOCKLEN_T)
|
||||
socklen_t l
|
||||
#else
|
||||
int l
|
||||
#endif
|
||||
= *addrlen;
|
||||
|
||||
r = accept(s, sa, &l);
|
||||
*addrlen = l;
|
||||
|
||||
#if defined(PPR_IS_WIN32)
|
||||
if(r == INVALID_SOCKET) r = -1;
|
||||
#endif
|
||||
|
||||
if(r < 0) return r;
|
||||
|
||||
if(sa->sa_family == AF_INET) {
|
||||
struct ppr_sockaddr_in* taddr = (struct ppr_sockaddr_in*)addr;
|
||||
struct sockaddr_in* addr4 = (struct sockaddr_in*)buffer;
|
||||
|
||||
taddr->sin_family = PPR_AF_INET;
|
||||
taddr->sin_addr.u.addr32[0] = addr4->sin_addr.s_addr;
|
||||
taddr->sin_port = addr4->sin_port;
|
||||
|
||||
*addrlen = sizeof(*taddr);
|
||||
#if defined(PPR_HAS_IPV6)
|
||||
} else if(sa->sa_family == AF_INET6) {
|
||||
struct ppr_sockaddr_in6* taddr = (struct ppr_sockaddr_in6*)addr;
|
||||
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)buffer;
|
||||
|
||||
taddr->sin6_family = PPR_AF_INET6;
|
||||
memcpy(taddr->sin6_addr.u.addr32, addr6->sin6_addr.s6_addr, 16);
|
||||
taddr->sin6_port = addr6->sin6_port;
|
||||
|
||||
*addrlen = sizeof(*taddr);
|
||||
#endif
|
||||
#if defined(PPR_HAS_UNIX_SOCKET)
|
||||
} else if(sa->sa_family == AF_UNIX) {
|
||||
struct ppr_sockaddr_un* taddr = (struct ppr_sockaddr_un*)addr;
|
||||
struct sockaddr_un* addru = (struct sockaddr_un*)buffer;
|
||||
|
||||
taddr->sun_family = PPR_AF_UNIX;
|
||||
strcpy(taddr->sun_path, addru->sun_path);
|
||||
|
||||
*addrlen = sizeof(*taddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void ppr_socket_close(int d) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
shutdown(d, SD_BOTH);
|
||||
closesocket(d);
|
||||
#elif defined(PPR_IS_UNIX)
|
||||
shutdown(d, SHUT_RD);
|
||||
close(d);
|
||||
#endif
|
||||
}
|
||||
|
||||
ppr_bool ppr_socket_has_ipv6(void) {
|
||||
#if defined(PPR_HAS_IPV6)
|
||||
#if defined(PPR_IS_WIN32)
|
||||
DWORD v = GetVersion();
|
||||
DWORD majorv, minorv;
|
||||
|
||||
majorv = LOBYTE(LOWORD(v));
|
||||
minorv = HIBYTE(LOWORD(v));
|
||||
|
||||
if(majorv > 5 && (majorv == 5 && minorv >= 1)) return ppr_true;
|
||||
|
||||
return ppr_false;
|
||||
#else
|
||||
return ppr_true;
|
||||
#endif
|
||||
#else
|
||||
return ppr_false;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct ppr_in_addr ppr_inaddr_any = {
|
||||
{{0, 0, 0, 0}}};
|
||||
|
||||
struct ppr_in6_addr ppr_in6addr_any = {
|
||||
{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}};
|
||||
48
src/base/stat.c
Normal file
48
src/base/stat.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
int ppr_stat(const char* path, struct ppr_stat* s) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
WIN32_FILE_ATTRIBUTE_DATA fad;
|
||||
ULARGE_INTEGER mtime;
|
||||
|
||||
if(!GetFileAttributesEx(path, GetFileExInfoStandard, &fad)) return -1;
|
||||
|
||||
memcpy(&mtime, &fad.ftLastWriteTime, sizeof(mtime));
|
||||
|
||||
s->st_size = 0;
|
||||
s->st_modtime = (mtime.QuadPart / 10000000) / 11644473600;
|
||||
s->st_mode = 0;
|
||||
|
||||
s->st_mode |= PPR_S_IFREG;
|
||||
if(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
s->st_mode &= ~PPR_S_IFREG;
|
||||
s->st_mode |= PPR_S_IFDIR;
|
||||
}
|
||||
|
||||
if(PPR_S_ISREG(s->st_mode)) {
|
||||
PPR_FILE* f = ppr_fopen(path, "r"); /* :))))))) */
|
||||
s->st_size = GetFileSize((HANDLE)f, NULL);
|
||||
ppr_fclose(f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#elif defined(PPR_IS_UNIX) || defined(PPR_IS_NETWARE)
|
||||
struct stat st;
|
||||
int sc;
|
||||
|
||||
sc = stat(path, &st);
|
||||
if(sc != 0) return sc;
|
||||
|
||||
s->st_size = st.st_size;
|
||||
s->st_modtime = st.st_mtime;
|
||||
s->st_mode = 0;
|
||||
|
||||
if(S_ISREG(st.st_mode)) s->st_mode |= PPR_S_IFREG;
|
||||
if(S_ISDIR(st.st_mode)) s->st_mode |= PPR_S_IFDIR;
|
||||
|
||||
return sc;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
73
src/base/string.c
Normal file
73
src/base/string.c
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
char* ppr_strdup(const char* str) {
|
||||
char* r = malloc(strlen(str) + 1);
|
||||
|
||||
strcpy(r, str);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char* ppr_strvacat(const char* a, ...) {
|
||||
int l = 1 + strlen(a);
|
||||
va_list va;
|
||||
char* s;
|
||||
char* r;
|
||||
|
||||
va_start(va, a);
|
||||
while((s = va_arg(va, char*)) != NULL) {
|
||||
l += strlen(s);
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
r = malloc(l);
|
||||
|
||||
strcpy(r, a);
|
||||
|
||||
va_start(va, a);
|
||||
while((s = va_arg(va, char*)) != NULL) {
|
||||
strcat(r, s);
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void ppr_strappend(char** dst, const char* src) {
|
||||
char* n = ppr_strvacat(*dst, src, NULL);
|
||||
|
||||
free(*dst);
|
||||
*dst = n;
|
||||
}
|
||||
|
||||
char* ppr_strsafehtml(const char* s) {
|
||||
char* r = malloc(strlen(s) * 5 + 1);
|
||||
int i;
|
||||
int n = 0;
|
||||
|
||||
for(i = 0; s[i] != 0; i++) {
|
||||
if(s[i] == '&') {
|
||||
r[n++] = '&';
|
||||
r[n++] = 'a';
|
||||
r[n++] = 'm';
|
||||
r[n++] = 'p';
|
||||
r[n++] = ';';
|
||||
} else if(s[i] == '<') {
|
||||
r[n++] = '&';
|
||||
r[n++] = 'l';
|
||||
r[n++] = 't';
|
||||
r[n++] = ';';
|
||||
} else if(s[i] == '>') {
|
||||
r[n++] = '&';
|
||||
r[n++] = 'g';
|
||||
r[n++] = 't';
|
||||
r[n++] = ';';
|
||||
} else {
|
||||
r[n++] = s[i];
|
||||
}
|
||||
}
|
||||
r[n] = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
227
src/base/thread.c
Normal file
227
src/base/thread.c
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
typedef struct arg {
|
||||
void (*entry)(void* param);
|
||||
void* param;
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
LONG waitsem;
|
||||
#endif
|
||||
} arg_t;
|
||||
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
typedef struct thread {
|
||||
int thread;
|
||||
LONG waitsem;
|
||||
} thread_t;
|
||||
|
||||
struct ppr_thread_usage {
|
||||
ppr_bool used;
|
||||
thread_t* thread;
|
||||
};
|
||||
|
||||
struct ppr_semaphore_usage ppr_semaphores[1024];
|
||||
struct ppr_thread_usage ppr_threads[1024];
|
||||
#endif
|
||||
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
long ppr_thread_open_semaphore(long initial) {
|
||||
long sem = OpenLocalSemaphore(initial);
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) {
|
||||
if(!ppr_semaphores[i].used) {
|
||||
ppr_semaphores[i].used = ppr_true;
|
||||
ppr_semaphores[i].sem = sem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
void ppr_thread_close_semaphore(long sem) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) {
|
||||
if(ppr_semaphores[i].used && ppr_semaphores[i].sem == sem) {
|
||||
ppr_semaphores[i].used = ppr_false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CloseLocalSemaphore(sem);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ppr_thread_init(void) {
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) {
|
||||
ppr_semaphores[i].used = ppr_false;
|
||||
}
|
||||
for(i = 0; i < sizeof(ppr_threads) / sizeof(ppr_threads[0]); i++) {
|
||||
ppr_threads[i].used = ppr_false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_thread_uninit(void) {
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(ppr_threads) / sizeof(ppr_threads[0]); i++) {
|
||||
if(ppr_threads[i].used) {
|
||||
ppr_thread_join(ppr_threads[i].thread);
|
||||
ppr_thread_destroy(ppr_threads[i].thread);
|
||||
}
|
||||
}
|
||||
for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) {
|
||||
if(ppr_semaphores[i].used) {
|
||||
ppr_thread_close_semaphore(ppr_semaphores[i].sem);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(PPR_IS_WIN32)
|
||||
#if defined(PPR_USE_CREATETHREAD)
|
||||
static DWORD WINAPI thread_entry(void* _param) {
|
||||
#else
|
||||
static unsigned int WINAPI thread_entry(void* _param) {
|
||||
#endif
|
||||
arg_t* arg = _param;
|
||||
void (*entry)(void* param) = arg->entry;
|
||||
void* param = arg->param;
|
||||
|
||||
free(arg);
|
||||
|
||||
entry(param);
|
||||
|
||||
#if defined(PPR_USE_CREATETHREAD)
|
||||
ExitThread(0);
|
||||
#else
|
||||
_endthreadex(0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
static void* thread_entry(void* _param) {
|
||||
arg_t* arg = _param;
|
||||
void (*entry)(void* param) = arg->entry;
|
||||
void* param = arg->param;
|
||||
|
||||
free(arg);
|
||||
|
||||
entry(param);
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
static void thread_entry(void* _param) {
|
||||
arg_t* arg = _param;
|
||||
void (*entry)(void* param) = arg->entry;
|
||||
void* param = arg->param;
|
||||
LONG waitsem = arg->waitsem;
|
||||
|
||||
free(arg);
|
||||
|
||||
entry(param);
|
||||
|
||||
SignalLocalSemaphore(waitsem);
|
||||
ExitThread(EXIT_THREAD, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void* ppr_thread_create(void (*entry)(void* param), void* param) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
arg_t* arg = malloc(sizeof(*arg));
|
||||
#if defined(PPR_USE_CREATETHREAD)
|
||||
DWORD id;
|
||||
#else
|
||||
unsigned int id;
|
||||
#endif
|
||||
|
||||
arg->entry = entry;
|
||||
arg->param = param;
|
||||
|
||||
return (void*)
|
||||
#if defined(PPR_USE_CREATETHREAD)
|
||||
CreateThread
|
||||
#else
|
||||
_beginthreadex
|
||||
#endif
|
||||
(NULL, 0, thread_entry, arg, 0, &id);
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
pthread_t* t = malloc(sizeof(*t));
|
||||
arg_t* arg = malloc(sizeof(*arg));
|
||||
|
||||
arg->entry = entry;
|
||||
arg->param = param;
|
||||
|
||||
pthread_create(t, NULL, thread_entry, arg);
|
||||
|
||||
return t;
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
thread_t* t = malloc(sizeof(*t));
|
||||
arg_t* arg = malloc(sizeof(*arg));
|
||||
|
||||
arg->entry = entry;
|
||||
arg->param = param;
|
||||
arg->waitsem = ppr_thread_open_semaphore(0);
|
||||
|
||||
t->waitsem = arg->waitsem;
|
||||
t->thread = BeginThread(thread_entry, NULL, 8192, arg);
|
||||
|
||||
return t;
|
||||
#else
|
||||
(void)entry;
|
||||
(void)param;
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_thread_join(void* handle) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
WaitForSingleObject(handle, INFINITE);
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
void* ret;
|
||||
|
||||
pthread_join(*(pthread_t*)handle, &ret);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
thread_t* t = handle;
|
||||
|
||||
WaitOnLocalSemaphore(t->waitsem);
|
||||
#else
|
||||
(void)handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_thread_destroy(void* handle) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
CloseHandle(handle);
|
||||
#elif defined(PPR_USE_PTHREAD)
|
||||
free(handle);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
thread_t* t = handle;
|
||||
int i;
|
||||
|
||||
ppr_thread_close_semaphore(t->waitsem);
|
||||
|
||||
for(i = 0; i < sizeof(ppr_threads) / sizeof(ppr_threads[0]); i++) {
|
||||
if(ppr_threads[i].used && ppr_threads[i].thread == handle) {
|
||||
ppr_threads[i].used = ppr_false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(handle);
|
||||
#else
|
||||
(void)handle;
|
||||
#endif
|
||||
}
|
||||
45
src/base/time.c
Normal file
45
src/base/time.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
void* ppr_gmtime_mutex;
|
||||
void* ppr_localtime_mutex;
|
||||
|
||||
ppr_time_t ppr_time(void) {
|
||||
time_t t = time(NULL);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void tm_to_ppr(struct ppr_tm* to, struct tm* from) {
|
||||
to->tm_sec = from->tm_sec;
|
||||
to->tm_min = from->tm_min;
|
||||
to->tm_hour = from->tm_hour;
|
||||
to->tm_mday = from->tm_mday;
|
||||
to->tm_mon = from->tm_mon;
|
||||
to->tm_year = from->tm_year;
|
||||
to->tm_wday = from->tm_wday;
|
||||
to->tm_yday = from->tm_yday;
|
||||
to->tm_isdst = from->tm_isdst;
|
||||
}
|
||||
|
||||
void ppr_gmtime(struct ppr_tm* tm, ppr_time_t t) {
|
||||
struct tm from_tm;
|
||||
time_t from = t;
|
||||
|
||||
ppr_mutex_lock(ppr_gmtime_mutex);
|
||||
from_tm = *gmtime(&from);
|
||||
ppr_mutex_unlock(ppr_gmtime_mutex);
|
||||
|
||||
tm_to_ppr(tm, &from_tm);
|
||||
}
|
||||
|
||||
void ppr_localtime(struct ppr_tm* tm, ppr_time_t t) {
|
||||
struct tm from_tm;
|
||||
time_t from = t;
|
||||
|
||||
ppr_mutex_lock(ppr_localtime_mutex);
|
||||
from_tm = *localtime(&from);
|
||||
ppr_mutex_unlock(ppr_localtime_mutex);
|
||||
|
||||
tm_to_ppr(tm, &from_tm);
|
||||
}
|
||||
33
src/base/unistd.c
Normal file
33
src/base/unistd.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
int ppr_gethostname(char* name, int namelen) {
|
||||
#if defined(PPR_IS_PS2)
|
||||
if(namelen < 4) return -1;
|
||||
|
||||
strcpy(name, "PS2");
|
||||
return 0;
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
if(namelen < 8) return -1;
|
||||
|
||||
strcpy(name, "netware");
|
||||
return 0;
|
||||
#else
|
||||
return gethostname(name, namelen);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ppr_msleep(int ms) {
|
||||
#if defined(PPR_IS_WIN32)
|
||||
Sleep(ms);
|
||||
#elif defined(PPR_IS_NETWARE)
|
||||
delay(ms);
|
||||
#else
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = ms / 1000;
|
||||
ts.tv_nsec = (ms % 1000) * 1000000;
|
||||
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
22
src/core.c
Normal file
22
src/core.c
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
void ppr_init(void) {
|
||||
ppr_socket_init();
|
||||
ppr_thread_init();
|
||||
|
||||
#if defined(PPR_IS_NETWARE)
|
||||
SetCurrentNameSpace(NW_NS_LONG);
|
||||
#endif
|
||||
|
||||
ppr_gmtime_mutex = ppr_mutex_create();
|
||||
ppr_localtime_mutex = ppr_mutex_create();
|
||||
}
|
||||
|
||||
void ppr_uninit(void) {
|
||||
ppr_mutex_destroy(ppr_localtime_mutex);
|
||||
ppr_mutex_destroy(ppr_gmtime_mutex);
|
||||
|
||||
ppr_thread_uninit();
|
||||
ppr_socket_uninit();
|
||||
}
|
||||
368
src/hash/blake2s.c
Normal file
368
src/hash/blake2s.c
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
|
||||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
#include "blake2s_int.h"
|
||||
|
||||
static const ppr_uint32_t ppr_blake2s_IV[8] =
|
||||
{
|
||||
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
|
||||
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL};
|
||||
|
||||
static const ppr_uint8_t ppr_blake2s_sigma[10][16] =
|
||||
{
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
||||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
||||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
||||
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
||||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
|
||||
};
|
||||
|
||||
static void ppr_blake2s_set_lastnode(ppr_blake2s_state* S) {
|
||||
S->f[1] = (ppr_uint32_t)-1;
|
||||
}
|
||||
|
||||
/* Some helper functions, not necessarily useful */
|
||||
static int ppr_blake2s_is_lastblock(const ppr_blake2s_state* S) {
|
||||
return S->f[0] != 0;
|
||||
}
|
||||
|
||||
static void ppr_blake2s_set_lastblock(ppr_blake2s_state* S) {
|
||||
if(S->last_node) ppr_blake2s_set_lastnode(S);
|
||||
|
||||
S->f[0] = (ppr_uint32_t)-1;
|
||||
}
|
||||
|
||||
static void ppr_blake2s_increment_counter(ppr_blake2s_state* S, const ppr_uint32_t inc) {
|
||||
S->t[0] += inc;
|
||||
S->t[1] += (S->t[0] < inc);
|
||||
}
|
||||
|
||||
static void ppr_blake2s_init0(ppr_blake2s_state* S) {
|
||||
ppr_size_t i;
|
||||
memset(S, 0, sizeof(ppr_blake2s_state));
|
||||
|
||||
for(i = 0; i < 8; ++i) S->h[i] = ppr_blake2s_IV[i];
|
||||
}
|
||||
|
||||
/* init2 xors IV with input parameter block */
|
||||
int ppr_blake2s_init_param(ppr_blake2s_state* S, const ppr_blake2s_param* P) {
|
||||
ppr_size_t i;
|
||||
#ifdef PPR_HAS_PACK
|
||||
unsigned char* p = (unsigned char*)P;
|
||||
#else
|
||||
unsigned char p[32];
|
||||
unsigned char* ptr = &p[0];
|
||||
#endif
|
||||
|
||||
ppr_blake2s_init0(S);
|
||||
|
||||
#ifndef PPR_HAS_PACK
|
||||
#define COPY(x) \
|
||||
{ \
|
||||
memcpy(ptr, &(x), sizeof((x))); \
|
||||
ptr += sizeof((x)); \
|
||||
}
|
||||
COPY(P->digest_length);
|
||||
COPY(P->key_length);
|
||||
COPY(P->fanout);
|
||||
COPY(P->depth);
|
||||
COPY(P->leaf_length);
|
||||
COPY(P->node_offset);
|
||||
COPY(P->xof_length);
|
||||
COPY(P->node_depth);
|
||||
COPY(P->inner_length);
|
||||
COPY(P->salt);
|
||||
COPY(P->personal);
|
||||
#undef COPY
|
||||
#endif
|
||||
|
||||
/* IV XOR ParamBlock */
|
||||
for(i = 0; i < 8; ++i)
|
||||
S->h[i] ^= load32(&p[i * 4]);
|
||||
|
||||
S->outlen = P->digest_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sequential ppr_blake2s initialization */
|
||||
int ppr_blake2s_init(ppr_blake2s_state* S, ppr_size_t outlen) {
|
||||
ppr_blake2s_param P[1];
|
||||
|
||||
/* Move interval verification here? */
|
||||
if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1;
|
||||
|
||||
P->digest_length = (ppr_uint8_t)outlen;
|
||||
P->key_length = 0;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32(&P->leaf_length, 0);
|
||||
store32(&P->node_offset, 0);
|
||||
store16(&P->xof_length, 0);
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
|
||||
memset(P->salt, 0, sizeof(P->salt));
|
||||
memset(P->personal, 0, sizeof(P->personal));
|
||||
return ppr_blake2s_init_param(S, P);
|
||||
}
|
||||
|
||||
int ppr_blake2s_init_key(ppr_blake2s_state* S, ppr_size_t outlen, const void* key, ppr_size_t keylen) {
|
||||
ppr_blake2s_param P[1];
|
||||
|
||||
if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1;
|
||||
|
||||
if(!key || !keylen || keylen > BLAKE2S_KEYBYTES) return -1;
|
||||
|
||||
P->digest_length = (ppr_uint8_t)outlen;
|
||||
P->key_length = (ppr_uint8_t)keylen;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32(&P->leaf_length, 0);
|
||||
store32(&P->node_offset, 0);
|
||||
store16(&P->xof_length, 0);
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
|
||||
memset(P->salt, 0, sizeof(P->salt));
|
||||
memset(P->personal, 0, sizeof(P->personal));
|
||||
|
||||
if(ppr_blake2s_init_param(S, P) < 0) return -1;
|
||||
|
||||
{
|
||||
ppr_uint8_t block[BLAKE2S_BLOCKBYTES];
|
||||
memset(block, 0, BLAKE2S_BLOCKBYTES);
|
||||
memcpy(block, key, keylen);
|
||||
ppr_blake2s_update(S, block, BLAKE2S_BLOCKBYTES);
|
||||
secure_zero_memory(block, BLAKE2S_BLOCKBYTES); /* Burn the key from stack */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define G(r, i, a, b, c, d) \
|
||||
do { \
|
||||
a = a + b + m[ppr_blake2s_sigma[r][2 * i + 0]]; \
|
||||
d = rotr32(d ^ a, 16); \
|
||||
c = c + d; \
|
||||
b = rotr32(b ^ c, 12); \
|
||||
a = a + b + m[ppr_blake2s_sigma[r][2 * i + 1]]; \
|
||||
d = rotr32(d ^ a, 8); \
|
||||
c = c + d; \
|
||||
b = rotr32(b ^ c, 7); \
|
||||
} while(0)
|
||||
|
||||
#define ROUND(r) \
|
||||
do { \
|
||||
G(r, 0, v[0], v[4], v[8], v[12]); \
|
||||
G(r, 1, v[1], v[5], v[9], v[13]); \
|
||||
G(r, 2, v[2], v[6], v[10], v[14]); \
|
||||
G(r, 3, v[3], v[7], v[11], v[15]); \
|
||||
G(r, 4, v[0], v[5], v[10], v[15]); \
|
||||
G(r, 5, v[1], v[6], v[11], v[12]); \
|
||||
G(r, 6, v[2], v[7], v[8], v[13]); \
|
||||
G(r, 7, v[3], v[4], v[9], v[14]); \
|
||||
} while(0)
|
||||
|
||||
static void ppr_blake2s_compress(ppr_blake2s_state* S, const ppr_uint8_t in[BLAKE2S_BLOCKBYTES]) {
|
||||
ppr_uint32_t m[16];
|
||||
ppr_uint32_t v[16];
|
||||
ppr_size_t i;
|
||||
|
||||
for(i = 0; i < 16; ++i) {
|
||||
m[i] = load32(in + i * sizeof(m[i]));
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
v[i] = S->h[i];
|
||||
}
|
||||
|
||||
v[8] = ppr_blake2s_IV[0];
|
||||
v[9] = ppr_blake2s_IV[1];
|
||||
v[10] = ppr_blake2s_IV[2];
|
||||
v[11] = ppr_blake2s_IV[3];
|
||||
v[12] = S->t[0] ^ ppr_blake2s_IV[4];
|
||||
v[13] = S->t[1] ^ ppr_blake2s_IV[5];
|
||||
v[14] = S->f[0] ^ ppr_blake2s_IV[6];
|
||||
v[15] = S->f[1] ^ ppr_blake2s_IV[7];
|
||||
|
||||
ROUND(0);
|
||||
ROUND(1);
|
||||
ROUND(2);
|
||||
ROUND(3);
|
||||
ROUND(4);
|
||||
ROUND(5);
|
||||
ROUND(6);
|
||||
ROUND(7);
|
||||
ROUND(8);
|
||||
ROUND(9);
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
|
||||
#undef G
|
||||
#undef ROUND
|
||||
|
||||
int ppr_blake2s_update(ppr_blake2s_state* S, const void* pin, ppr_size_t inlen) {
|
||||
const unsigned char* in = (const unsigned char*)pin;
|
||||
if(inlen > 0) {
|
||||
ppr_size_t left = S->buflen;
|
||||
ppr_size_t fill = BLAKE2S_BLOCKBYTES - left;
|
||||
if(inlen > fill) {
|
||||
S->buflen = 0;
|
||||
memcpy(S->buf + left, in, fill); /* Fill buffer */
|
||||
ppr_blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
|
||||
ppr_blake2s_compress(S, S->buf); /* Compress */
|
||||
in += fill;
|
||||
inlen -= fill;
|
||||
while(inlen > BLAKE2S_BLOCKBYTES) {
|
||||
ppr_blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
|
||||
ppr_blake2s_compress(S, in);
|
||||
in += BLAKE2S_BLOCKBYTES;
|
||||
inlen -= BLAKE2S_BLOCKBYTES;
|
||||
}
|
||||
}
|
||||
memcpy(S->buf + S->buflen, in, inlen);
|
||||
S->buflen += inlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ppr_blake2s_final(ppr_blake2s_state* S, void* out, ppr_size_t outlen) {
|
||||
ppr_uint8_t buffer[BLAKE2S_OUTBYTES] = {0};
|
||||
ppr_size_t i;
|
||||
|
||||
if(out == NULL || outlen < S->outlen)
|
||||
return -1;
|
||||
|
||||
if(ppr_blake2s_is_lastblock(S))
|
||||
return -1;
|
||||
|
||||
ppr_blake2s_increment_counter(S, (ppr_uint32_t)S->buflen);
|
||||
ppr_blake2s_set_lastblock(S);
|
||||
memset(S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen); /* Padding */
|
||||
ppr_blake2s_compress(S, S->buf);
|
||||
|
||||
for(i = 0; i < 8; ++i) /* Output full hash to temp buffer */
|
||||
store32(buffer + sizeof(S->h[i]) * i, S->h[i]);
|
||||
|
||||
memcpy(out, buffer, outlen);
|
||||
secure_zero_memory(buffer, sizeof(buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ppr_blake2s(void* out, ppr_size_t outlen, const void* in, ppr_size_t inlen, const void* key, ppr_size_t keylen) {
|
||||
ppr_blake2s_state S[1];
|
||||
|
||||
/* Verify parameters */
|
||||
if(NULL == in && inlen > 0) return -1;
|
||||
|
||||
if(NULL == out) return -1;
|
||||
|
||||
if(NULL == key && keylen > 0) return -1;
|
||||
|
||||
if(!outlen || outlen > BLAKE2S_OUTBYTES) return -1;
|
||||
|
||||
if(keylen > BLAKE2S_KEYBYTES) return -1;
|
||||
|
||||
if(keylen > 0) {
|
||||
if(ppr_blake2s_init_key(S, outlen, key, keylen) < 0) return -1;
|
||||
} else {
|
||||
if(ppr_blake2s_init(S, outlen) < 0) return -1;
|
||||
}
|
||||
|
||||
ppr_blake2s_update(S, (const ppr_uint8_t*)in, inlen);
|
||||
ppr_blake2s_final(S, out, outlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(SUPERCOP)
|
||||
int crypto_hash(unsigned char* out, unsigned char* in, unsigned long long inlen) {
|
||||
return ppr_blake2s(out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BLAKE2S_SELFTEST)
|
||||
#include <string.h>
|
||||
#include "blake2-kat.h"
|
||||
int main(void) {
|
||||
ppr_uint8_t key[BLAKE2S_KEYBYTES];
|
||||
ppr_uint8_t buf[BLAKE2_KAT_LENGTH];
|
||||
ppr_size_t i, step;
|
||||
|
||||
for(i = 0; i < BLAKE2S_KEYBYTES; ++i)
|
||||
key[i] = (ppr_uint8_t)i;
|
||||
|
||||
for(i = 0; i < BLAKE2_KAT_LENGTH; ++i)
|
||||
buf[i] = (ppr_uint8_t)i;
|
||||
|
||||
/* Test simple API */
|
||||
for(i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
|
||||
ppr_uint8_t hash[BLAKE2S_OUTBYTES];
|
||||
ppr_blake2s(hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES);
|
||||
|
||||
if(0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test streaming API */
|
||||
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
|
||||
for(i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
|
||||
ppr_uint8_t hash[BLAKE2S_OUTBYTES];
|
||||
ppr_blake2s_state S;
|
||||
ppr_uint8_t* p = buf;
|
||||
ppr_size_t mlen = i;
|
||||
int err = 0;
|
||||
|
||||
if((err = ppr_blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while(mlen >= step) {
|
||||
if((err = ppr_blake2s_update(&S, p, step)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
mlen -= step;
|
||||
p += step;
|
||||
}
|
||||
if((err = ppr_blake2s_update(&S, p, mlen)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
if((err = ppr_blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
puts("ok");
|
||||
return 0;
|
||||
fail:
|
||||
puts("error");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
73
src/hash/blake2s_int.h
Normal file
73
src/hash/blake2s_int.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
#ifndef BLAKE2S_INT_H
|
||||
#define BLAKE2S_INT_H
|
||||
|
||||
#include <ppr_machdep.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define BLAKE2S_INLINE static __inline
|
||||
|
||||
BLAKE2S_INLINE ppr_uint32_t load32(const void* src) {
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
ppr_uint32_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const ppr_uint8_t* p = (const ppr_uint8_t*)src;
|
||||
return ((ppr_uint32_t)(p[0]) << 0) |
|
||||
((ppr_uint32_t)(p[1]) << 8) |
|
||||
((ppr_uint32_t)(p[2]) << 16) |
|
||||
((ppr_uint32_t)(p[3]) << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
BLAKE2S_INLINE void store16(void* dst, ppr_uint16_t w) {
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
ppr_uint8_t* p = (ppr_uint8_t*)dst;
|
||||
*p++ = (ppr_uint8_t)w;
|
||||
w >>= 8;
|
||||
*p++ = (ppr_uint8_t)w;
|
||||
#endif
|
||||
}
|
||||
|
||||
BLAKE2S_INLINE void store32(void* dst, ppr_uint32_t w) {
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
ppr_uint8_t* p = (ppr_uint8_t*)dst;
|
||||
p[0] = (ppr_uint8_t)(w >> 0);
|
||||
p[1] = (ppr_uint8_t)(w >> 8);
|
||||
p[2] = (ppr_uint8_t)(w >> 16);
|
||||
p[3] = (ppr_uint8_t)(w >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
BLAKE2S_INLINE ppr_uint32_t rotr32(const ppr_uint32_t w, const unsigned c) {
|
||||
return (w >> c) | (w << (32 - c));
|
||||
}
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* prevents compiler optimizing out memset() */
|
||||
BLAKE2S_INLINE void secure_zero_memory(void* v, ppr_size_t n) {
|
||||
static void* (*const volatile memset_v)(void*, int, size_t) = &memset;
|
||||
memset_v(v, 0, n);
|
||||
}
|
||||
|
||||
#endif
|
||||
254
src/hash/md5.c
Normal file
254
src/hash/md5.c
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
|
||||
** **
|
||||
** License to copy and use this software is granted provided that **
|
||||
** it is identified as the "RSA Data Security, Inc. MD5 Message **
|
||||
** Digest Algorithm" in all material mentioning or referencing this **
|
||||
** software or this function. **
|
||||
** **
|
||||
** License is also granted to make and use derivative works **
|
||||
** provided that such works are identified as "derived from the RSA **
|
||||
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
|
||||
** material mentioning or referencing the derived work. **
|
||||
** **
|
||||
** RSA Data Security, Inc. makes no representations concerning **
|
||||
** either the merchantability of this software or the suitability **
|
||||
** of this software for any particular purpose. It is provided "as **
|
||||
** is" without express or implied warranty of any kind. **
|
||||
** **
|
||||
** These notices must be retained in any copies of any part of this **
|
||||
** documentation and/or software. **
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/* forward declaration */
|
||||
static void Transform(ppr_uint32_t* buf, ppr_uint32_t* in);
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
/* F, G and H are basic MD5 functions: selection, majority, parity */
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits */
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
|
||||
/* Rotation is separate from addition to prevent recomputation */
|
||||
#define FF(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += F((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += G((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += H((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += I((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
void ppr_md5_init(ppr_md5_context_t* mdContext) {
|
||||
mdContext->i[0] = mdContext->i[1] = (ppr_uint32_t)0;
|
||||
|
||||
/* Load magic initialization constants.
|
||||
*/
|
||||
mdContext->buf[0] = (ppr_uint32_t)0x67452301;
|
||||
mdContext->buf[1] = (ppr_uint32_t)0xefcdab89;
|
||||
mdContext->buf[2] = (ppr_uint32_t)0x98badcfe;
|
||||
mdContext->buf[3] = (ppr_uint32_t)0x10325476;
|
||||
}
|
||||
|
||||
void ppr_md5_update(ppr_md5_context_t* mdContext, const void* inBuf, unsigned int inLen) {
|
||||
ppr_uint32_t in[16];
|
||||
int mdi;
|
||||
unsigned int i, ii;
|
||||
const unsigned char* buf = inBuf;
|
||||
|
||||
/* compute number of bytes mod 64 */
|
||||
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
|
||||
|
||||
/* update number of bits */
|
||||
if((mdContext->i[0] + ((ppr_uint32_t)inLen << 3)) < mdContext->i[0])
|
||||
mdContext->i[1]++;
|
||||
mdContext->i[0] += ((ppr_uint32_t)inLen << 3);
|
||||
mdContext->i[1] += ((ppr_uint32_t)inLen >> 29);
|
||||
|
||||
while(inLen--) {
|
||||
/* add new character to buffer, increment mdi */
|
||||
mdContext->in[mdi++] = *buf++;
|
||||
|
||||
/* transform if necessary */
|
||||
if(mdi == 0x40) {
|
||||
for(i = 0, ii = 0; i < 16; i++, ii += 4)
|
||||
in[i] = (((ppr_uint32_t)mdContext->in[ii + 3]) << 24) |
|
||||
(((ppr_uint32_t)mdContext->in[ii + 2]) << 16) |
|
||||
(((ppr_uint32_t)mdContext->in[ii + 1]) << 8) |
|
||||
((ppr_uint32_t)mdContext->in[ii]);
|
||||
Transform(mdContext->buf, in);
|
||||
mdi = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppr_md5_final(ppr_md5_context_t* mdContext) {
|
||||
ppr_uint32_t in[16];
|
||||
int mdi;
|
||||
unsigned int i, ii;
|
||||
unsigned int padLen;
|
||||
|
||||
/* save number of bits */
|
||||
in[14] = mdContext->i[0];
|
||||
in[15] = mdContext->i[1];
|
||||
|
||||
/* compute number of bytes mod 64 */
|
||||
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
|
||||
|
||||
/* pad out to 56 mod 64 */
|
||||
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
|
||||
ppr_md5_update(mdContext, PADDING, padLen);
|
||||
|
||||
/* append length in bits and transform */
|
||||
for(i = 0, ii = 0; i < 14; i++, ii += 4)
|
||||
in[i] = (((ppr_uint32_t)mdContext->in[ii + 3]) << 24) |
|
||||
(((ppr_uint32_t)mdContext->in[ii + 2]) << 16) |
|
||||
(((ppr_uint32_t)mdContext->in[ii + 1]) << 8) |
|
||||
((ppr_uint32_t)mdContext->in[ii]);
|
||||
Transform(mdContext->buf, in);
|
||||
|
||||
/* store buffer in digest */
|
||||
for(i = 0, ii = 0; i < 4; i++, ii += 4) {
|
||||
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
|
||||
mdContext->digest[ii + 1] =
|
||||
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
|
||||
mdContext->digest[ii + 2] =
|
||||
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
|
||||
mdContext->digest[ii + 3] =
|
||||
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic MD5 step. Transform buf based on in.
|
||||
*/
|
||||
static void Transform(ppr_uint32_t* buf, ppr_uint32_t* in) {
|
||||
ppr_uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
|
||||
|
||||
/* Round 1 */
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
FF(a, b, c, d, in[0], S11, 3614090360); /* 1 */
|
||||
FF(d, a, b, c, in[1], S12, 3905402710); /* 2 */
|
||||
FF(c, d, a, b, in[2], S13, 606105819); /* 3 */
|
||||
FF(b, c, d, a, in[3], S14, 3250441966); /* 4 */
|
||||
FF(a, b, c, d, in[4], S11, 4118548399); /* 5 */
|
||||
FF(d, a, b, c, in[5], S12, 1200080426); /* 6 */
|
||||
FF(c, d, a, b, in[6], S13, 2821735955); /* 7 */
|
||||
FF(b, c, d, a, in[7], S14, 4249261313); /* 8 */
|
||||
FF(a, b, c, d, in[8], S11, 1770035416); /* 9 */
|
||||
FF(d, a, b, c, in[9], S12, 2336552879); /* 10 */
|
||||
FF(c, d, a, b, in[10], S13, 4294925233); /* 11 */
|
||||
FF(b, c, d, a, in[11], S14, 2304563134); /* 12 */
|
||||
FF(a, b, c, d, in[12], S11, 1804603682); /* 13 */
|
||||
FF(d, a, b, c, in[13], S12, 4254626195); /* 14 */
|
||||
FF(c, d, a, b, in[14], S13, 2792965006); /* 15 */
|
||||
FF(b, c, d, a, in[15], S14, 1236535329); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
GG(a, b, c, d, in[1], S21, 4129170786); /* 17 */
|
||||
GG(d, a, b, c, in[6], S22, 3225465664); /* 18 */
|
||||
GG(c, d, a, b, in[11], S23, 643717713); /* 19 */
|
||||
GG(b, c, d, a, in[0], S24, 3921069994); /* 20 */
|
||||
GG(a, b, c, d, in[5], S21, 3593408605); /* 21 */
|
||||
GG(d, a, b, c, in[10], S22, 38016083); /* 22 */
|
||||
GG(c, d, a, b, in[15], S23, 3634488961); /* 23 */
|
||||
GG(b, c, d, a, in[4], S24, 3889429448); /* 24 */
|
||||
GG(a, b, c, d, in[9], S21, 568446438); /* 25 */
|
||||
GG(d, a, b, c, in[14], S22, 3275163606); /* 26 */
|
||||
GG(c, d, a, b, in[3], S23, 4107603335); /* 27 */
|
||||
GG(b, c, d, a, in[8], S24, 1163531501); /* 28 */
|
||||
GG(a, b, c, d, in[13], S21, 2850285829); /* 29 */
|
||||
GG(d, a, b, c, in[2], S22, 4243563512); /* 30 */
|
||||
GG(c, d, a, b, in[7], S23, 1735328473); /* 31 */
|
||||
GG(b, c, d, a, in[12], S24, 2368359562); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
HH(a, b, c, d, in[5], S31, 4294588738); /* 33 */
|
||||
HH(d, a, b, c, in[8], S32, 2272392833); /* 34 */
|
||||
HH(c, d, a, b, in[11], S33, 1839030562); /* 35 */
|
||||
HH(b, c, d, a, in[14], S34, 4259657740); /* 36 */
|
||||
HH(a, b, c, d, in[1], S31, 2763975236); /* 37 */
|
||||
HH(d, a, b, c, in[4], S32, 1272893353); /* 38 */
|
||||
HH(c, d, a, b, in[7], S33, 4139469664); /* 39 */
|
||||
HH(b, c, d, a, in[10], S34, 3200236656); /* 40 */
|
||||
HH(a, b, c, d, in[13], S31, 681279174); /* 41 */
|
||||
HH(d, a, b, c, in[0], S32, 3936430074); /* 42 */
|
||||
HH(c, d, a, b, in[3], S33, 3572445317); /* 43 */
|
||||
HH(b, c, d, a, in[6], S34, 76029189); /* 44 */
|
||||
HH(a, b, c, d, in[9], S31, 3654602809); /* 45 */
|
||||
HH(d, a, b, c, in[12], S32, 3873151461); /* 46 */
|
||||
HH(c, d, a, b, in[15], S33, 530742520); /* 47 */
|
||||
HH(b, c, d, a, in[2], S34, 3299628645); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
II(a, b, c, d, in[0], S41, 4096336452); /* 49 */
|
||||
II(d, a, b, c, in[7], S42, 1126891415); /* 50 */
|
||||
II(c, d, a, b, in[14], S43, 2878612391); /* 51 */
|
||||
II(b, c, d, a, in[5], S44, 4237533241); /* 52 */
|
||||
II(a, b, c, d, in[12], S41, 1700485571); /* 53 */
|
||||
II(d, a, b, c, in[3], S42, 2399980690); /* 54 */
|
||||
II(c, d, a, b, in[10], S43, 4293915773); /* 55 */
|
||||
II(b, c, d, a, in[1], S44, 2240044497); /* 56 */
|
||||
II(a, b, c, d, in[8], S41, 1873313359); /* 57 */
|
||||
II(d, a, b, c, in[15], S42, 4264355552); /* 58 */
|
||||
II(c, d, a, b, in[6], S43, 2734768916); /* 59 */
|
||||
II(b, c, d, a, in[13], S44, 1309151649); /* 60 */
|
||||
II(a, b, c, d, in[4], S41, 4149444226); /* 61 */
|
||||
II(d, a, b, c, in[11], S42, 3174756917); /* 62 */
|
||||
II(c, d, a, b, in[2], S43, 718787259); /* 63 */
|
||||
II(b, c, d, a, in[9], S44, 3951481745); /* 64 */
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
121
src/hash/sha256.c
Normal file
121
src/hash/sha256.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
const ppr_uint32_t sha256_initial_h[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
|
||||
|
||||
const ppr_uint32_t sha256_round_k[64] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
|
||||
|
||||
static ppr_uint32_t sha256_endian_read32(ppr_uint8_t* input) {
|
||||
ppr_uint32_t output = 0;
|
||||
output |= (input[0] << 24);
|
||||
output |= (input[1] << 16);
|
||||
output |= (input[2] << 8);
|
||||
output |= (input[3] << 0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static ppr_uint32_t sha256_ror(ppr_uint32_t input, ppr_uint32_t by) {
|
||||
return (input >> by) | (((input & ((1 << by) - 1))) << (32 - by));
|
||||
}
|
||||
|
||||
void ppr_sha256(void* output, const void* data, ppr_size_t len) {
|
||||
ppr_uint8_t padding[80];
|
||||
ppr_size_t current = (len + 1) % 64;
|
||||
/* want to be == 56 % 64. */
|
||||
ppr_size_t needed = (64 + 56 - current) % 64;
|
||||
ppr_size_t extra = needed + 9;
|
||||
ppr_size_t total = len + extra;
|
||||
int i, j;
|
||||
ppr_size_t cursor;
|
||||
ppr_uint32_t v[8];
|
||||
ppr_size_t l;
|
||||
|
||||
for(i = 1; i < 80; i++)
|
||||
padding[i] = 0;
|
||||
padding[0] = 0x80;
|
||||
|
||||
l = len * 8;
|
||||
for(i = 7; i >= 0; i--) {
|
||||
padding[total - len - 8 + i] = l & 0xff;
|
||||
l = l >> 8;
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
v[i] = sha256_initial_h[i];
|
||||
|
||||
for(cursor = 0; cursor * 64 < total; cursor++) {
|
||||
ppr_uint32_t t[8];
|
||||
ppr_uint32_t w[64];
|
||||
for(i = 0; i < 8; i++)
|
||||
t[i] = v[i];
|
||||
|
||||
if(cursor * 64 + 64 <= len) {
|
||||
for(j = 0; j < 16; j++) {
|
||||
w[j] = sha256_endian_read32(
|
||||
(ppr_uint8_t*)data + cursor * 64 + j * 4);
|
||||
}
|
||||
} else {
|
||||
if(cursor * 64 < len) {
|
||||
ppr_size_t size = len - cursor * 64;
|
||||
if(size > 0) memcpy(w, (ppr_uint8_t*)data + cursor * 64, size);
|
||||
memcpy((ppr_uint8_t*)w + size, padding, 64 - size);
|
||||
} else {
|
||||
ppr_size_t off = (cursor * 64 - len) % 64;
|
||||
memcpy((ppr_uint8_t*)w, padding + off, 64);
|
||||
}
|
||||
|
||||
for(j = 0; j < 16; j++) {
|
||||
w[j] = sha256_endian_read32((ppr_uint8_t*)&w[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 16; j < 64; j++) {
|
||||
ppr_uint32_t s1 = sha256_ror(w[j - 2], 17) ^ sha256_ror(w[j - 2], 19) ^ (w[j - 2] >> 10);
|
||||
ppr_uint32_t s0 = sha256_ror(w[j - 15], 7) ^ sha256_ror(w[j - 15], 18) ^ (w[j - 15] >> 3);
|
||||
w[j] = s1 + w[j - 7] + s0 + w[j - 16];
|
||||
}
|
||||
|
||||
for(j = 0; j < 64; j++) {
|
||||
ppr_uint32_t ch = (t[4] & t[5]) ^ (~t[4] & t[6]);
|
||||
ppr_uint32_t maj = (t[0] & t[1]) ^ (t[0] & t[2]) ^ (t[1] & t[2]);
|
||||
ppr_uint32_t S0 = sha256_ror(t[0], 2) ^ sha256_ror(t[0], 13) ^ sha256_ror(t[0], 22);
|
||||
ppr_uint32_t S1 = sha256_ror(t[4], 6) ^ sha256_ror(t[4], 11) ^ sha256_ror(t[4], 25);
|
||||
|
||||
ppr_uint32_t t1 = t[7] + S1 + ch + sha256_round_k[j] + w[j];
|
||||
ppr_uint32_t t2 = S0 + maj;
|
||||
|
||||
t[7] = t[6];
|
||||
t[6] = t[5];
|
||||
t[5] = t[4];
|
||||
t[4] = t[3] + t1;
|
||||
t[3] = t[2];
|
||||
t[2] = t[1];
|
||||
t[1] = t[0];
|
||||
t[0] = t1 + t2;
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++) v[i] += t[i];
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
ppr_uint8_t* out = (ppr_uint8_t*)output + i * 4;
|
||||
ppr_uint32_t val = v[i];
|
||||
|
||||
for(j = 3; j >= 0; j--) {
|
||||
out[j] = val & 0xff;
|
||||
val = val >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
218
src/misc/url.c
Normal file
218
src/misc/url.c
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
static int hex(const char in) {
|
||||
if('0' <= in && in <= '9') return in - '0';
|
||||
if('a' <= in && in <= 'f') return in - 'a' + 10;
|
||||
if('A' <= in && in <= 'F') return in - 'A' + 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ppr_bool ppr_url_decode(char* out, const char* input, int len) {
|
||||
int i;
|
||||
|
||||
for(i = 0; input[i] != 0; i++) {
|
||||
if((int)strlen(out) == len) {
|
||||
return ppr_false;
|
||||
} else if(input[i] == '%') {
|
||||
if(strlen(input + i) >= 3) {
|
||||
int n = strlen(out);
|
||||
out[n] = (hex(input[i + 1]) << 4) | (hex(input[i + 2]));
|
||||
out[n + 1] = 0;
|
||||
|
||||
i += 2;
|
||||
}
|
||||
} else {
|
||||
int n = strlen(out);
|
||||
out[n] = input[i];
|
||||
out[n + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ppr_true;
|
||||
}
|
||||
|
||||
ppr_bool ppr_url_encode(char* out, const char* input, int len) {
|
||||
int i;
|
||||
|
||||
for(i = 0; input[i] != 0; i++) {
|
||||
if(strlen(out) == len) {
|
||||
return ppr_false;
|
||||
} else if(input[i] == '%') {
|
||||
if(strlen(input + i) >= 3 && strlen(out) <= (len - 3)) {
|
||||
int n = strlen(out);
|
||||
|
||||
out[n] = '%';
|
||||
out[n + 1] = '2';
|
||||
out[n + 2] = '5';
|
||||
out[n + 3] = 0;
|
||||
}
|
||||
} else {
|
||||
int n = strlen(out);
|
||||
out[n] = input[i];
|
||||
out[n + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ppr_true;
|
||||
}
|
||||
|
||||
void ppr_url_init(ppr_url_t* url) {
|
||||
memset(url, 0, sizeof(*url));
|
||||
}
|
||||
|
||||
enum STATE {
|
||||
USERINFO = 0,
|
||||
HOST,
|
||||
PORT,
|
||||
PATH,
|
||||
QUERY,
|
||||
FRAGMENT
|
||||
};
|
||||
|
||||
ppr_bool ppr_url_parse(ppr_url_t* url, const char* str) {
|
||||
const char* st; /* tmp */
|
||||
const char* sp; /* pointer */
|
||||
ppr_bool has_userinfo = ppr_false;
|
||||
int state = 0;
|
||||
ppr_bool br = ppr_false;
|
||||
|
||||
if((st = strstr(str, "://")) == NULL) return ppr_false;
|
||||
|
||||
for(sp = str; sp != st; sp++) {
|
||||
char c = *sp;
|
||||
|
||||
if('A' <= c && c <= 'Z') continue;
|
||||
if('a' <= c && c <= 'z') continue;
|
||||
if(sp == str) {
|
||||
ppr_url_deinit(url);
|
||||
return ppr_false;
|
||||
}
|
||||
|
||||
if('0' <= c && c <= '9') continue;
|
||||
if(c == '+' || c == '-' || c == '.') continue;
|
||||
|
||||
ppr_url_deinit(url);
|
||||
return ppr_false;
|
||||
}
|
||||
|
||||
url->scheme = malloc(sp - str + 1);
|
||||
memcpy(url->scheme, str, sp - str);
|
||||
url->scheme[sp - str] = 0;
|
||||
|
||||
str = st + 3;
|
||||
|
||||
if((st = strchr(str, '/')) == NULL) st = str + strlen(str);
|
||||
|
||||
for(sp = str; sp != st; sp++) {
|
||||
if((*sp) == '@') {
|
||||
has_userinfo = ppr_true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(has_userinfo) {
|
||||
state = USERINFO;
|
||||
} else {
|
||||
state = HOST;
|
||||
}
|
||||
|
||||
for(sp = str;; sp++) {
|
||||
char c = *sp;
|
||||
|
||||
if(state == USERINFO && c == '@') {
|
||||
url->userinfo = malloc(sp - str + 1);
|
||||
memcpy(url->userinfo, str, sp - str);
|
||||
url->userinfo[sp - str] = 0;
|
||||
|
||||
str = sp + 1;
|
||||
|
||||
state = HOST;
|
||||
} else if(state == HOST && !br && c == '[') {
|
||||
br = ppr_true;
|
||||
} else if(state == HOST && br && c == ']') {
|
||||
br = ppr_false;
|
||||
} else if(state == HOST && !br && (c == 0 || c == ':' || c == '/')) {
|
||||
url->host = malloc(sp - str + 1);
|
||||
memcpy(url->host, str, sp - str);
|
||||
url->host[sp - str] = 0;
|
||||
|
||||
if(c == 0) {
|
||||
break;
|
||||
} else if(c == ':') {
|
||||
str = sp + 1;
|
||||
|
||||
state = PORT;
|
||||
} else {
|
||||
str = sp;
|
||||
|
||||
state = PATH;
|
||||
}
|
||||
} else if(state == PORT && (c == 0 || c == '/')) {
|
||||
char* p = malloc(sp - str + 1);
|
||||
memcpy(p, str, sp - str);
|
||||
p[sp - str] = 0;
|
||||
|
||||
url->port = atoi(p);
|
||||
|
||||
free(p);
|
||||
|
||||
if(c == 0) {
|
||||
break;
|
||||
} else {
|
||||
str = sp; /* intended */
|
||||
|
||||
state = PATH;
|
||||
}
|
||||
} else if(state == PATH && (c == 0 || c == '?' || c == '#')) {
|
||||
url->path = malloc(sp - str + 1);
|
||||
memcpy(url->path, str, sp - str);
|
||||
url->path[sp - str] = 0;
|
||||
|
||||
str = sp + 1;
|
||||
|
||||
if(c == 0) {
|
||||
break;
|
||||
} else if(c == '?') {
|
||||
state = QUERY;
|
||||
} else {
|
||||
state = FRAGMENT;
|
||||
}
|
||||
} else if(state == QUERY && (c == 0 || c == '#')) {
|
||||
url->query = malloc(sp - str + 1);
|
||||
memcpy(url->query, str, sp - str);
|
||||
url->query[sp - str] = 0;
|
||||
|
||||
str = sp + 1;
|
||||
|
||||
if(c == 0) {
|
||||
break;
|
||||
} else {
|
||||
state = FRAGMENT;
|
||||
}
|
||||
} else if(state == FRAGMENT && c == 0) {
|
||||
url->fragment = malloc(sp - str + 1);
|
||||
memcpy(url->fragment, str, sp - str);
|
||||
url->fragment[sp - str] = 0;
|
||||
|
||||
break;
|
||||
} else if(c == 0) {
|
||||
ppr_url_deinit(url);
|
||||
return ppr_false;
|
||||
}
|
||||
}
|
||||
|
||||
return ppr_true;
|
||||
}
|
||||
|
||||
void ppr_url_deinit(ppr_url_t* url) {
|
||||
if(url->scheme != NULL) free(url->scheme);
|
||||
if(url->userinfo != NULL) free(url->userinfo);
|
||||
if(url->host != NULL) free(url->host);
|
||||
if(url->path != NULL) free(url->path);
|
||||
if(url->query != NULL) free(url->query);
|
||||
if(url->fragment != NULL) free(url->fragment);
|
||||
|
||||
memset(url, 0, sizeof(*url));
|
||||
}
|
||||
23
src/misc/wildcard.c
Normal file
23
src/misc/wildcard.c
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include <ppr.h>
|
||||
#include <ppr_int.h>
|
||||
|
||||
ppr_bool ppr_wildcard(const char* wildcard, const char* target) {
|
||||
const char *pw = wildcard, *pt = target;
|
||||
|
||||
while(1) {
|
||||
if(*pt == 0) {
|
||||
while(*pw == '*') pw++;
|
||||
return *pw == 0;
|
||||
} else if(*pw == 0) {
|
||||
return 0;
|
||||
} else if(*pw == '*') {
|
||||
return *(pw + 1) == 0 || ppr_wildcard(pw, pt + 1) || ppr_wildcard(pw + 1, pt);
|
||||
} else if(*pw == '?' || (tolower((int)*pw) == tolower((int)*pt))) {
|
||||
pw++;
|
||||
pt++;
|
||||
continue;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue