mirror of https://github.com/basinserver/basin/
Added Avuna Skeleton
This commit is contained in:
parent
a6c635affe
commit
29f318c5e4
|
@ -4,3 +4,4 @@
|
|||
|
||||
/Debug/basin
|
||||
/Debug/src/
|
||||
/Debug/
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* accept.c
|
||||
*
|
||||
* Created on: Nov 18, 2015
|
||||
* Author: root
|
||||
*/
|
||||
#include "accept.h"
|
||||
#include "util.h"
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "xstring.h"
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <poll.h>
|
||||
#include "work.h"
|
||||
#include <unistd.h>
|
||||
|
||||
void run_accept(struct accept_param* param) {
|
||||
static int one = 1;
|
||||
static unsigned char onec = 1;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 60;
|
||||
timeout.tv_usec = 0;
|
||||
struct pollfd spfd;
|
||||
spfd.events = POLLIN;
|
||||
spfd.revents = 0;
|
||||
spfd.fd = param->server_fd;
|
||||
while (1) {
|
||||
struct conn* c = xmalloc(sizeof(struct conn));
|
||||
memset(&c->addr, 0, sizeof(struct sockaddr_in6));
|
||||
c->addrlen = sizeof(struct sockaddr_in6);
|
||||
c->readBuffer = NULL;
|
||||
c->readBuffer_size = 0;
|
||||
c->readBuffer_checked = 0;
|
||||
c->writeBuffer = NULL;
|
||||
c->writeBuffer_size = 0;
|
||||
if (poll(&spfd, 1, -1) < 0) {
|
||||
printf("Error while polling server: %s\n", strerror(errno));
|
||||
xfree(c);
|
||||
continue;
|
||||
}
|
||||
if ((spfd.revents ^ POLLIN) != 0) {
|
||||
printf("Error after polling server: %i (poll revents), closing server!\n", spfd.revents);
|
||||
xfree(c);
|
||||
close(param->server_fd);
|
||||
break;
|
||||
}
|
||||
spfd.revents = 0;
|
||||
int cfd = accept(param->server_fd, (struct sockaddr*) &c->addr, &c->addrlen);
|
||||
if (cfd < 0) {
|
||||
if (errno == EAGAIN) continue;
|
||||
printf("Error while accepting client: %s\n", strerror(errno));
|
||||
xfree(c);
|
||||
continue;
|
||||
}
|
||||
c->fd = cfd;
|
||||
if (setsockopt(cfd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout))) printf("Setting recv timeout failed! %s\n", strerror(errno));
|
||||
if (setsockopt(cfd, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout))) printf("Setting send timeout failed! %s\n", strerror(errno));
|
||||
if (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, (void *) &one, sizeof(one))) printf("Setting TCP_NODELAY failed! %s\n", strerror(errno));
|
||||
if (fcntl(cfd, F_SETFL, fcntl(cfd, F_GETFL) | O_NONBLOCK) < 0) {
|
||||
printf("Setting O_NONBLOCK failed! %s, this error cannot be recovered, closing client.\n", strerror(errno));
|
||||
close(cfd);
|
||||
continue;
|
||||
}
|
||||
struct work_param* work = param->works[rand() % param->works_count];
|
||||
if (add_collection(work->conns, c)) { // TODO: send to lowest load, not random
|
||||
if (errno == EINVAL) {
|
||||
printf("Too many open connections! Closing client.\n");
|
||||
} else {
|
||||
printf("Collection failure! Closing client. %s\n", strerror(errno));
|
||||
}
|
||||
close(cfd);
|
||||
continue;
|
||||
}
|
||||
if (write(work->pipes[1], &onec, 1) < 1) {
|
||||
printf("Failed to write to wakeup pipe! Things may slow down. %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* accept.h
|
||||
*
|
||||
* Created on: Nov 18, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef ACCEPT_H_
|
||||
#define ACCEPT_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "collection.h"
|
||||
#include <sys/socket.h>
|
||||
#include "work.h"
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
struct accept_param {
|
||||
int server_fd;
|
||||
int port;
|
||||
struct cnode* config;
|
||||
int works_count;
|
||||
struct work_param** works;
|
||||
struct logsess* logsess;
|
||||
};
|
||||
|
||||
struct conn {
|
||||
int fd;
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t addrlen;
|
||||
unsigned char* readBuffer;
|
||||
size_t readBuffer_size;
|
||||
size_t readBuffer_checked;
|
||||
unsigned char* writeBuffer;
|
||||
size_t writeBuffer_size;
|
||||
};
|
||||
|
||||
void run_accept(struct accept_param* param);
|
||||
|
||||
#endif /* ACCEPT_H_ */
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* queue.c
|
||||
*
|
||||
* Created on: Nov 19, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include "collection.h"
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include "xstring.h"
|
||||
#include "util.h"
|
||||
|
||||
struct collection* new_collection(size_t capacity, size_t data_size) {
|
||||
struct collection* coll = xmalloc(sizeof(struct collection));
|
||||
coll->capacity = capacity;
|
||||
coll->data = xmalloc((capacity == 0 ? 1 : capacity) * data_size);
|
||||
coll->rc = capacity == 0 ? 1 : 0;
|
||||
coll->dsize = data_size;
|
||||
coll->size = 0;
|
||||
coll->count = 0;
|
||||
if (pthread_rwlock_init(&coll->data_mutex, NULL)) {
|
||||
xfree(coll->data);
|
||||
coll->data = NULL;
|
||||
xfree(coll);
|
||||
return NULL;
|
||||
}
|
||||
return coll;
|
||||
}
|
||||
|
||||
int del_collection(struct collection* coll) {
|
||||
if (coll == NULL || coll->data == NULL) return -1;
|
||||
if (pthread_rwlock_destroy(&coll->data_mutex)) return -1;
|
||||
xfree(coll->data);
|
||||
coll->data = NULL;
|
||||
xfree(coll);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_collection(struct collection* coll, void* data) {
|
||||
pthread_rwlock_wrlock(&coll->data_mutex);
|
||||
for (int i = 0; i < coll->size; i++) {
|
||||
if (coll->data[i] == NULL) {
|
||||
coll->count++;
|
||||
coll->data[i] = data;
|
||||
pthread_rwlock_unlock(&coll->data_mutex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (coll->size == coll->rc && coll->capacity == 0) {
|
||||
coll->rc++;
|
||||
coll->data = xrealloc(coll->data, coll->rc * sizeof(void*));
|
||||
} else if (coll->capacity > 0 && coll->size == coll->capacity) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
coll->data[coll->size++] = data;
|
||||
coll->count++;
|
||||
pthread_rwlock_unlock(&coll->data_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rem_collection(struct collection* coll, void* data) {
|
||||
pthread_rwlock_wrlock(&coll->data_mutex);
|
||||
for (int i = 0; i < coll->size; i++) {
|
||||
if (coll->data[i] == data) {
|
||||
coll->data[i] = NULL;
|
||||
coll->count--;
|
||||
pthread_rwlock_unlock(&coll->data_mutex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(&coll->data_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* queue.h
|
||||
*
|
||||
* Created on: Nov 19, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef COLLECTION_H_
|
||||
#define COLLECTION_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct collection {
|
||||
size_t size;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
size_t dsize;
|
||||
size_t rc;
|
||||
void** data;
|
||||
pthread_rwlock_t data_mutex;
|
||||
};
|
||||
|
||||
struct collection* new_collection(size_t capacity, size_t data_size);
|
||||
|
||||
int del_collection(struct collection* coll);
|
||||
|
||||
int add_collection(struct collection* coll, void* data);
|
||||
|
||||
int rem_collection(struct collection* coll, void* data);
|
||||
|
||||
#endif /* COLLECTION_H_ */
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* config.c
|
||||
*
|
||||
* Created on: Nov 17, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
#include "streams.h"
|
||||
#include "xstring.h"
|
||||
|
||||
struct config* loadConfig(const char* file) {
|
||||
if (file == NULL) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if (access(file, F_OK)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (access(file, R_OK)) {
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
int fd = open(file, O_RDONLY);
|
||||
if (fd < 0) return NULL;
|
||||
struct config* ret = xmalloc(sizeof(struct config));
|
||||
ret->node_count = 0;
|
||||
ret->nodes = NULL;
|
||||
char line[1024];
|
||||
int l = 0;
|
||||
struct cnode* cat = NULL;
|
||||
while (1) {
|
||||
l = readLine(fd, line, 1024);
|
||||
if (l < 0) break;
|
||||
char* wl = trim(line);
|
||||
if (wl[0] == 0) continue;
|
||||
char* comment = strchr(line, '#');
|
||||
if (comment != NULL) {
|
||||
comment[0] = 0;
|
||||
wl = trim(line);
|
||||
if (wl[0] == 0) continue;
|
||||
}
|
||||
l = strlen(wl);
|
||||
if (l > 5 && wl[0] == '[' && wl[l - 1] == ']') {
|
||||
wl[--l] = 0;
|
||||
wl++;
|
||||
char* id = strchr(wl, ' ');
|
||||
if (id != NULL) {
|
||||
id[0] = 0;
|
||||
id++;
|
||||
id = trim(id);
|
||||
}
|
||||
wl = trim(wl);
|
||||
cat = xmalloc(sizeof(struct cnode));
|
||||
if (ret->node_count == 0) {
|
||||
ret->nodes = xmalloc(sizeof(struct cnode*));
|
||||
ret->node_count = 1;
|
||||
} else {
|
||||
ret->node_count++;
|
||||
ret->nodes = xrealloc(ret->nodes, sizeof(struct cnode*) * ret->node_count);
|
||||
}
|
||||
ret->nodes[ret->node_count - 1] = cat;
|
||||
cat->keys = NULL;
|
||||
cat->values = NULL;
|
||||
cat->entries = 0;
|
||||
if (streq_nocase(wl, "server")) {
|
||||
cat->cat = CAT_SERVER;
|
||||
} else if (streq_nocase(wl, "daemon")) {
|
||||
cat->cat = CAT_DAEMON;
|
||||
} else {
|
||||
cat->cat = CAT_UNKNOWN;
|
||||
}
|
||||
if (id == NULL) {
|
||||
cat->id = NULL;
|
||||
} else {
|
||||
int idl = strlen(id) + 1;
|
||||
cat->id = xmalloc(idl);
|
||||
memcpy(cat->id, id, idl);
|
||||
}
|
||||
} else {
|
||||
char* value = strchr(wl, '=');
|
||||
if (value == NULL) continue;
|
||||
value[0] = 0;
|
||||
value++;
|
||||
value = trim(value);
|
||||
wl = trim(wl);
|
||||
int wll = strlen(wl);
|
||||
int vl = strlen(value);
|
||||
if (cat->entries == 0) {
|
||||
cat->keys = xmalloc(sizeof(char*));
|
||||
cat->values = xmalloc(sizeof(char*));
|
||||
cat->entries = 1;
|
||||
} else {
|
||||
cat->keys = xrealloc(cat->keys, ++cat->entries * sizeof(char*));
|
||||
cat->values = xrealloc(cat->values, cat->entries * sizeof(char*));
|
||||
}
|
||||
cat->keys[cat->entries - 1] = xmalloc(wll + 1);
|
||||
cat->values[cat->entries - 1] = xmalloc(vl + 1);
|
||||
memcpy(cat->keys[cat->entries - 1], wl, wll + 1);
|
||||
memcpy(cat->values[cat->entries - 1], value, vl + 1);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* getConfigValue(const struct cnode* cat, const char* name) {
|
||||
if (cat == NULL || name == NULL || cat->entries == 0) return NULL;
|
||||
for (int i = 0; i < cat->entries; i++) {
|
||||
if (streq_nocase(cat->keys[i], name)) {
|
||||
return cat->values[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hasConfigKey(const struct cnode* cat, const char* name) {
|
||||
if (cat == NULL || name == NULL || cat->entries == 0) return NULL;
|
||||
for (int i = 0; i < cat->entries; i++) {
|
||||
if (streq_nocase(cat->keys[i], name)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cnode* getCatByID(const struct config* cfg, const char* id) {
|
||||
if (cfg == NULL || id == NULL || cfg->node_count == 0) return NULL;
|
||||
for (int i = 0; i < cfg->node_count; i++) {
|
||||
if (streq_nocase(cfg->nodes[i]->id, id)) {
|
||||
return cfg->nodes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cnode** getCatsByCat(const struct config* cfg, int cat, int* count) {
|
||||
if (cfg == NULL || cat < CAT_UNKNOWN || cfg->node_count == 0) return NULL;
|
||||
if (cat == CAT_UNKNOWN) return cfg->nodes;
|
||||
int rs = 0;
|
||||
struct cnode** ret = NULL;
|
||||
for (int i = 0; i < cfg->node_count; i++) {
|
||||
if (cfg->nodes[i]->cat == cat) {
|
||||
if (rs == 0) {
|
||||
rs = 1;
|
||||
ret = xmalloc(sizeof(struct cnode**));
|
||||
} else {
|
||||
rs++;
|
||||
ret = xrealloc(ret, sizeof(struct cnode**) * rs);
|
||||
}
|
||||
ret[rs - 1] = cfg->nodes[i];
|
||||
}
|
||||
}
|
||||
*count = rs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct cnode* getUniqueByCat(const struct config* cfg, int cat) {
|
||||
if (cfg == NULL || cat <= CAT_UNKNOWN || cfg->node_count == 0) return NULL;
|
||||
for (int i = 0; i < cfg->node_count; i++) {
|
||||
if (cfg->nodes[i]->cat == cat && cfg->nodes[i]->id == NULL) {
|
||||
return cfg->nodes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* config.h
|
||||
*
|
||||
* Created on: Nov 17, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
#define CAT_UNKNOWN -1
|
||||
#define CAT_SERVER 0
|
||||
#define CAT_DAEMON 1
|
||||
|
||||
struct cnode {
|
||||
int cat;
|
||||
char* id;
|
||||
int entries;
|
||||
char** keys;
|
||||
char** values;
|
||||
};
|
||||
|
||||
struct config {
|
||||
int node_count;
|
||||
struct cnode** nodes;
|
||||
};
|
||||
|
||||
struct config* loadConfig(const char* file);
|
||||
|
||||
const char* getConfigValue(const struct cnode* cat, const char* name);
|
||||
|
||||
int hasConfigKey(const struct cnode* cat, const char* name);
|
||||
|
||||
struct cnode* getCatByID(const struct config* cfg, const char* name);
|
||||
|
||||
struct cnode** getCatsByCat(const struct config* cfg, int cat, int* count);
|
||||
|
||||
struct cnode* getUniqueByCat(const struct config* cfg, int cat);
|
||||
|
||||
#endif /* CONFIG_H_ */
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* globals.h
|
||||
*
|
||||
* Created on: Nov 19, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef GLOBALS_H_
|
||||
#define GLOBALS_H_
|
||||
|
||||
struct config* cfg;
|
||||
struct logsess* delog;
|
||||
#endif /* GLOBALS_H_ */
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* log.c
|
||||
*
|
||||
* Created on: Nov 22, 2015
|
||||
* Author: root
|
||||
*/
|
||||
#include "log.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include "xstring.h"
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void acclog(struct logsess* logsess, char* template, ...) {
|
||||
if (!logsess->pi) {
|
||||
if (pthread_mutex_init(&logsess->lmutex, NULL) == -1) {
|
||||
printf("Failed to create logging mutex! %s\n", strerror(errno));
|
||||
logsess->pi = -1;
|
||||
} else {
|
||||
logsess->pi = 1;
|
||||
}
|
||||
}
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
if (logsess->pi == 1) pthread_mutex_lock(&logsess->lmutex);
|
||||
struct tm *ctm = localtime(&tv.tv_sec);
|
||||
char ct[32]; // the above uses a static buffer, so problems could ensue, but it would be the same time being overwritten...
|
||||
strftime(ct, 31, "%Y-%m-%d %H:%M:%S", ctm);
|
||||
va_list arg;
|
||||
va_start(arg, template);
|
||||
size_t ctl = strlen(ct);
|
||||
size_t tl = strlen(template);
|
||||
char tp[ctl + 5 + tl];
|
||||
tp[0] = '[';
|
||||
memcpy(tp + 1, ct, ctl);
|
||||
tp[1 + ctl] = ']';
|
||||
tp[2 + ctl] = ' ';
|
||||
memcpy(tp + 3 + ctl, template, tl);
|
||||
tp[3 + ctl + tl] = '\n';
|
||||
tp[4 + ctl + tl] = 0;
|
||||
if (vfprintf(stdout, tp, arg) < 0) {
|
||||
errlog(logsess, "Failed writing to stdout!");
|
||||
}
|
||||
va_end(arg);
|
||||
va_start(arg, template);
|
||||
if (logsess->access_fd != NULL) {
|
||||
if (vfprintf(logsess->access_fd, tp, arg) < 0) {
|
||||
errlog(logsess, "Failed writing to accesslog!");
|
||||
}
|
||||
}
|
||||
va_end(arg);
|
||||
if (logsess->pi == 1) pthread_mutex_unlock(&logsess->lmutex);
|
||||
}
|
||||
|
||||
void errlog(struct logsess* logsess, char* template, ...) {
|
||||
if (!logsess->pi) {
|
||||
if (pthread_mutex_init(&logsess->lmutex, NULL) == -1) {
|
||||
printf("Failed to create logging mutex! %s\n", strerror(errno));
|
||||
logsess->pi = -1;
|
||||
} else {
|
||||
logsess->pi = 1;
|
||||
}
|
||||
}
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
if (logsess->pi == 1) pthread_mutex_lock(&logsess->lmutex);
|
||||
struct tm *ctm = localtime(&tv.tv_sec);
|
||||
char ct[32]; // the above uses a static buffer, so problems could ensue, but it would be the same time being overwritten...
|
||||
strftime(ct, 31, "%Y-%m-%d %H:%M:%S", ctm);
|
||||
va_list arg;
|
||||
va_start(arg, template);
|
||||
size_t ctl = strlen(ct);
|
||||
size_t
|
||||
tl = strlen(template);
|
||||
char tp[ctl + 5 + tl];
|
||||
tp[0] = '[';
|
||||
memcpy(tp + 1, ct, ctl);
|
||||
tp[1 + ctl] = ']';
|
||||
tp[2 + ctl] = ' ';
|
||||
memcpy(tp + 3 + ctl, template, tl);
|
||||
tp[3 + ctl + tl] = '\n';
|
||||
tp[4 + ctl + tl] = 0;
|
||||
if (vfprintf(stdout, tp, arg) < 0) {
|
||||
//TODO: we can't write to stdout, nothing we can do!
|
||||
}
|
||||
va_end(arg);
|
||||
va_start(arg, template);
|
||||
if (logsess->error_fd != NULL) {
|
||||
if (vfprintf(logsess->error_fd, tp, arg) < 0) {
|
||||
//its in the console
|
||||
}
|
||||
}
|
||||
va_end(arg);
|
||||
if (logsess->pi == 1) pthread_mutex_unlock(&logsess->lmutex);
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* log.h
|
||||
*
|
||||
* Created on: Nov 22, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef LOG_H_
|
||||
#define LOG_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct logsess {
|
||||
pthread_mutex_t lmutex;
|
||||
int pi;
|
||||
FILE* access_fd;
|
||||
FILE* error_fd;
|
||||
};
|
||||
|
||||
void acclog(struct logsess* logsess, char* template, ...);
|
||||
|
||||
void errlog(struct logsess* logsess, char* template, ...);
|
||||
|
||||
#endif /* LOG_H_ */
|
292
basin/src/main.c
292
basin/src/main.c
|
@ -1,15 +1,301 @@
|
|||
/*
|
||||
* main.c
|
||||
*
|
||||
* Created on: Jun 23, 2016
|
||||
* Created on: Nov 17, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include "xstring.h"
|
||||
#include "version.h"
|
||||
#include "util.h"
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include "streams.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include "accept.h"
|
||||
#include "globals.h"
|
||||
#include "collection.h"
|
||||
#include "work.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (getuid() != 0 || getgid() != 0) {
|
||||
printf("Must run as root!\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Loading %s %s\n", DAEMON_NAME, VERSION);
|
||||
#ifdef DEBUG
|
||||
printf("Running in Debug mode!\n");
|
||||
#endif
|
||||
char ncwd[strlen(argv[0]) + 1];
|
||||
memcpy(ncwd, argv[0], strlen(argv[0]) + 1);
|
||||
char* ecwd = strrchr(ncwd, '/');
|
||||
ecwd++;
|
||||
ecwd[0] = 0;
|
||||
chdir(ncwd);
|
||||
cfg = loadConfig("main.cfg");
|
||||
if (cfg == NULL) {
|
||||
printf("Error loading Config<%s>: %s\n", "main.cfg", errno == EINVAL ? "File doesn't exist!" : strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
struct cnode* dm = getUniqueByCat(cfg, CAT_DAEMON);
|
||||
if (dm == NULL) {
|
||||
printf("[daemon] block does not exist in <%s>!\n", "main.cfg");
|
||||
return 1;
|
||||
}
|
||||
#ifndef DEBUG
|
||||
if (runn) {
|
||||
printf("Already running! PID = %i\n", pid);
|
||||
exit(0);
|
||||
} else {
|
||||
|
||||
pid_t f = fork();
|
||||
if (f == 0) {
|
||||
printf("Now running as daemon!\n");
|
||||
exit(0);
|
||||
} else {
|
||||
printf("Daemonized! PID = %i\n", f);
|
||||
if (setsid() < 0) {
|
||||
printf("Failed to exit process tree: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if (freopen("/dev/null", "r", stdin) < 0) {
|
||||
printf("reopening of STDIN to /dev/null failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if (freopen("/dev/null", "w", stderr) < 0) {
|
||||
printf("reopening of STDERR to /dev/null failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if (freopen("/dev/null", "w", stdout) < 0) {
|
||||
printf("reopening of STDOUT to /dev/null failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
printf("Daemonized! PID = %i\n", getpid());
|
||||
#endif
|
||||
delog = xmalloc(sizeof(struct logsess));
|
||||
delog->pi = 0;
|
||||
delog->access_fd = NULL;
|
||||
const char* el = getConfigValue(dm, "error-log");
|
||||
delog->error_fd = el == NULL ? NULL : fopen(el, "a"); // fopen will return NULL on error, which works.
|
||||
//TODO: chown group to de-escalated
|
||||
int servsl;
|
||||
struct cnode** servs = getCatsByCat(cfg, CAT_SERVER, &servsl);
|
||||
int sr = 0;
|
||||
struct accept_param* aps[servsl];
|
||||
for (int i = 0; i < servsl; i++) {
|
||||
struct cnode* serv = servs[i];
|
||||
const char* bind_mode = getConfigValue(serv, "bind-mode");
|
||||
const char* bind_ip = NULL;
|
||||
int port = -1;
|
||||
const char* bind_file = NULL;
|
||||
int namespace = -1;
|
||||
int ba = 0;
|
||||
int ip6 = 0;
|
||||
if (streq(bind_mode, "tcp")) {
|
||||
bind_ip = getConfigValue(serv, "bind-ip");
|
||||
if (streq(bind_ip, "0.0.0.0")) {
|
||||
ba = 1;
|
||||
}
|
||||
ip6 = ba || contains(bind_ip, ":");
|
||||
const char* bind_port = getConfigValue(serv, "bind-port");
|
||||
if (!strisunum(bind_port)) {
|
||||
if (serv->id != NULL) errlog(delog, "Invalid bind-port for server: %s", serv->id);
|
||||
else errlog(delog, "Invalid bind-port for server.");
|
||||
continue;
|
||||
}
|
||||
port = atoi(bind_port);
|
||||
namespace = ip6 ? PF_INET6 : PF_INET;;
|
||||
} else if (streq(bind_mode, "unix")) {
|
||||
bind_file = getConfigValue(serv, "bind-file");
|
||||
namespace = PF_LOCAL;
|
||||
} else {
|
||||
if (serv->id != NULL) errlog(delog, "Invalid bind-mode for server: %s", serv->id);
|
||||
else errlog(delog, "Invalid bind-mode for server.");
|
||||
continue;
|
||||
}
|
||||
const char* tcc = getConfigValue(serv, "threads");
|
||||
if (!strisunum(tcc)) {
|
||||
if (serv->id != NULL) errlog(delog, "Invalid threads for server: %s", serv->id);
|
||||
else errlog(delog, "Invalid threads for server.");
|
||||
continue;
|
||||
}
|
||||
int tc = atoi(tcc);
|
||||
if (tc < 1) {
|
||||
if (serv->id != NULL) errlog(delog, "Invalid threads for server: %s, must be greater than 1.", serv->id);
|
||||
else errlog(delog, "Invalid threads for server, must be greater than 1.");
|
||||
continue;
|
||||
}
|
||||
const char* mcc = getConfigValue(serv, "max-conn");
|
||||
if (!strisunum(mcc)) {
|
||||
if (serv->id != NULL) errlog(delog, "Invalid max-conn for server: %s", serv->id);
|
||||
else errlog(delog, "Invalid max-conn for server.");
|
||||
continue;
|
||||
}
|
||||
int mc = atoi(mcc);
|
||||
sock: ;
|
||||
int sfd = socket(namespace, SOCK_STREAM, 0);
|
||||
if (sfd < 0) {
|
||||
if (serv->id != NULL) errlog(delog, "Error creating socket for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error creating socket for server, %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
int one = 1;
|
||||
int zero = 0;
|
||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one)) == -1) {
|
||||
if (serv->id != NULL) errlog(delog, "Error setting SO_REUSEADDR for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error setting SO_REUSEADDR for server, %s", strerror(errno));
|
||||
close (sfd);
|
||||
continue;
|
||||
}
|
||||
if (namespace == PF_INET || namespace == PF_INET6) {
|
||||
if (ip6) {
|
||||
if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &zero, sizeof(zero)) == -1) {
|
||||
if (serv->id != NULL) errlog(delog, "Error unsetting IPV6_V6ONLY for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error unsetting IPV6_V6ONLY for server, %s", strerror(errno));
|
||||
close (sfd);
|
||||
continue;
|
||||
}
|
||||
struct sockaddr_in6 bip;
|
||||
bip.sin6_flowinfo = 0;
|
||||
bip.sin6_scope_id = 0;
|
||||
bip.sin6_family = AF_INET6;
|
||||
if (ba) bip.sin6_addr = in6addr_any;
|
||||
else if (!inet_pton(AF_INET6, bind_ip, &(bip.sin6_addr))) {
|
||||
close (sfd);
|
||||
if (serv->id != NULL) errlog(delog, "Error binding socket for server: %s, invalid bind-ip", serv->id);
|
||||
else errlog(delog, "Error binding socket for server, invalid bind-ip");
|
||||
continue;
|
||||
}
|
||||
bip.sin6_port = htons(port);
|
||||
if (bind(sfd, (struct sockaddr*) &bip, sizeof(bip))) {
|
||||
close (sfd);
|
||||
if (ba) {
|
||||
namespace = PF_INET;
|
||||
ip6 = 0;
|
||||
goto sock;
|
||||
}
|
||||
if (serv->id != NULL) errlog(delog, "Error binding socket for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error binding socket for server, %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
struct sockaddr_in bip;
|
||||
bip.sin_family = AF_INET;
|
||||
if (!inet_aton(bind_ip, &(bip.sin_addr))) {
|
||||
close (sfd);
|
||||
if (serv->id != NULL) errlog(delog, "Error binding socket for server: %s, invalid bind-ip", serv->id);
|
||||
else errlog(delog, "Error binding socket for server, invalid bind-ip");
|
||||
continue;
|
||||
}
|
||||
bip.sin_port = htons(port);
|
||||
if (bind(sfd, (struct sockaddr*) &bip, sizeof(bip))) {
|
||||
if (serv->id != NULL) errlog(delog, "Error binding socket for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error binding socket for server, %s\n", strerror(errno));
|
||||
close (sfd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (namespace == PF_LOCAL) {
|
||||
struct sockaddr_un uip;
|
||||
strncpy(uip.sun_path, bind_file, 108);
|
||||
if (bind(sfd, (struct sockaddr*) &uip, sizeof(uip))) {
|
||||
if (serv->id != NULL) errlog(delog, "Error binding socket for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error binding socket for server, %s\n", strerror(errno));
|
||||
close (sfd);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (serv->id != NULL) errlog(delog, "Invalid family for server: %s", serv->id);
|
||||
else errlog(delog, "Invalid family for server\n");
|
||||
close (sfd);
|
||||
continue;
|
||||
}
|
||||
if (listen(sfd, 50)) {
|
||||
if (serv->id != NULL) errlog(delog, "Error listening on socket for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error listening on socket for server, %s", strerror(errno));
|
||||
close (sfd);
|
||||
continue;
|
||||
}
|
||||
if (fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL) | O_NONBLOCK) < 0) {
|
||||
if (serv->id != NULL) errlog(delog, "Error setting non-blocking for server: %s, %s", serv->id, strerror(errno));
|
||||
else errlog(delog, "Error setting non-blocking for server, %s", strerror(errno));
|
||||
close (sfd);
|
||||
continue;
|
||||
}
|
||||
struct logsess* slog = xmalloc(sizeof(struct logsess));
|
||||
slog->pi = 0;
|
||||
const char* lal = getConfigValue(serv, "access-log");
|
||||
slog->access_fd = lal == NULL ? NULL : fopen(lal, "a");
|
||||
const char* lel = getConfigValue(serv, "error-log");
|
||||
slog->error_fd = lel == NULL ? NULL : fopen(lel, "a");
|
||||
if (serv->id != NULL) acclog(slog, "Server %s listening for connections!", serv->id);
|
||||
else acclog(slog, "Server listening for connections!");
|
||||
struct accept_param* ap = xmalloc(sizeof(struct accept_param));
|
||||
ap->port = port;
|
||||
ap->server_fd = sfd;
|
||||
ap->config = serv;
|
||||
ap->works_count = tc;
|
||||
ap->works = xmalloc(sizeof(struct work_param*) * tc);
|
||||
ap->logsess = slog;
|
||||
for (int x = 0; x < tc; x++) {
|
||||
struct work_param* wp = xmalloc(sizeof(struct work_param));
|
||||
wp->conns = new_collection(mc < 1 ? 0 : mc / tc, sizeof(struct conn*));
|
||||
wp->logsess = slog;
|
||||
wp->i = x;
|
||||
wp->sport = port;
|
||||
ap->works[x] = wp;
|
||||
}
|
||||
aps[i] = ap;
|
||||
sr++;
|
||||
}
|
||||
const char* uids = getConfigValue(dm, "uid");
|
||||
const char* gids = getConfigValue(dm, "gid");
|
||||
uid_t uid = uids == NULL ? 0 : atol(uids);
|
||||
uid_t gid = gids == NULL ? 0 : atol(gids);
|
||||
if (gid > 0) {
|
||||
if (setgid(gid) != 0) {
|
||||
errlog(delog, "Failed to setgid! %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
if (uid > 0) {
|
||||
if (setuid(uid) != 0) {
|
||||
errlog(delog, "Failed to setuid! %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
acclog(delog, "Running as UID = %u, GID = %u, starting workers.", getuid(), getgid());
|
||||
for (int i = 0; i < servsl; i++) {
|
||||
pthread_t pt;
|
||||
for (int x = 0; x < aps[i]->works_count; x++) {
|
||||
int c = pthread_create(&pt, NULL, (void *) run_work, aps[i]->works[x]);
|
||||
if (c != 0) {
|
||||
if (servs[i]->id != NULL) errlog(delog, "Error creating thread: pthread errno = %i, this will cause occasional connection hanging @ %s server.", c, servs[i]->id);
|
||||
else errlog(delog, "Error creating thread: pthread errno = %i, this will cause occasional connection hanging.", c);
|
||||
}
|
||||
}
|
||||
int c = pthread_create(&pt, NULL, (void *) run_accept, aps[i]);
|
||||
if (c != 0) {
|
||||
if (servs[i]->id != NULL) errlog(delog, "Error creating thread: pthread errno = %i, server %s is shutting down.", c, servs[i]->id);
|
||||
else errlog(delog, "Error creating thread: pthread errno = %i, server is shutting down.", c);
|
||||
close(aps[i]->server_fd);
|
||||
}
|
||||
}
|
||||
while (sr > 0)
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* queue.c
|
||||
*
|
||||
* Created on: Nov 19, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include "queue.h"
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include "xstring.h"
|
||||
#include "util.h"
|
||||
|
||||
struct queue* new_queue(size_t capacity, size_t data_size) {
|
||||
struct queue* queue = xmalloc(sizeof(struct queue));
|
||||
queue->capacity = capacity;
|
||||
queue->data = xmalloc((capacity == 0 ? 1 : capacity) * data_size);
|
||||
queue->rc = capacity == 0 ? 1 : 0;
|
||||
queue->dsize = data_size;
|
||||
queue->start = 0;
|
||||
queue->end = 0;
|
||||
queue->size = 0;
|
||||
if (pthread_mutex_init(&queue->data_mutex, NULL)) {
|
||||
xfree(queue->data);
|
||||
queue->data = NULL;
|
||||
xfree(queue);
|
||||
return NULL;
|
||||
}
|
||||
if (pthread_mutex_init(&queue->out_mutex, NULL)) {
|
||||
xfree(queue->data);
|
||||
queue->data = NULL;
|
||||
xfree(queue);
|
||||
pthread_mutex_destroy(&queue->data_mutex);
|
||||
return NULL;
|
||||
}
|
||||
if (pthread_mutex_init(&queue->in_mutex, NULL)) {
|
||||
xfree(queue->data);
|
||||
queue->data = NULL;
|
||||
xfree(queue);
|
||||
pthread_mutex_destroy(&queue->data_mutex);
|
||||
pthread_mutex_destroy(&queue->out_mutex);
|
||||
return NULL;
|
||||
}
|
||||
if (pthread_cond_init(&queue->out_cond, NULL)) {
|
||||
xfree(queue->data);
|
||||
queue->data = NULL;
|
||||
xfree(queue);
|
||||
pthread_mutex_destroy(&queue->data_mutex);
|
||||
pthread_mutex_destroy(&queue->out_mutex);
|
||||
pthread_mutex_destroy(&queue->in_mutex);
|
||||
return NULL;
|
||||
}
|
||||
if (pthread_cond_init(&queue->in_cond, NULL)) {
|
||||
xfree(queue->data);
|
||||
queue->data = NULL;
|
||||
xfree(queue);
|
||||
pthread_mutex_destroy(&queue->data_mutex);
|
||||
pthread_mutex_destroy(&queue->out_mutex);
|
||||
pthread_mutex_destroy(&queue->in_mutex);
|
||||
pthread_cond_destroy(&queue->out_cond);
|
||||
return NULL;
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
int del_queue(struct queue* queue) {
|
||||
if (queue == NULL || queue->data == NULL) return -1;
|
||||
if (pthread_mutex_destroy(&queue->data_mutex)) return -1;
|
||||
if (pthread_mutex_destroy(&queue->out_mutex)) return -1;
|
||||
if (pthread_cond_destroy(&queue->out_cond)) return -1;
|
||||
if (pthread_mutex_destroy(&queue->in_mutex)) return -1;
|
||||
if (pthread_cond_destroy(&queue->in_cond)) return -1;
|
||||
xfree(queue->data);
|
||||
queue->data = NULL;
|
||||
xfree(queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_queue(struct queue* queue, void* data) {
|
||||
pthread_mutex_lock(&queue->data_mutex);
|
||||
if (queue->size == queue->rc && queue->capacity == 0) {
|
||||
queue->rc++;
|
||||
queue->data = xrealloc(queue->data, queue->rc * queue->dsize);
|
||||
pthread_mutex_unlock(&queue->data_mutex);
|
||||
} else {
|
||||
pthread_mutex_unlock(&queue->data_mutex);
|
||||
pthread_mutex_lock(&queue->in_mutex);
|
||||
while (queue->size == queue->capacity) {
|
||||
pthread_cond_wait(&queue->in_cond, &queue->in_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&queue->in_mutex);
|
||||
}
|
||||
pthread_mutex_lock(&queue->data_mutex);
|
||||
void* nl = queue->data;
|
||||
int ix = queue->end;
|
||||
nl += ix * queue->dsize;
|
||||
memcpy(nl, data, queue->dsize);
|
||||
queue->end++;
|
||||
if (queue->end >= queue->capacity) {
|
||||
queue->end -= queue->capacity;
|
||||
}
|
||||
queue->size++;
|
||||
pthread_mutex_unlock(&queue->data_mutex);
|
||||
pthread_cond_signal(&queue->out_cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pop_queue(struct queue* queue, void* data) {
|
||||
pthread_mutex_lock(&queue->out_mutex);
|
||||
while (queue->size == 0) {
|
||||
pthread_cond_wait(&queue->out_cond, &queue->out_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&queue->out_mutex);
|
||||
pthread_mutex_lock(&queue->data_mutex);
|
||||
void* nl = queue->data;
|
||||
nl += queue->start * queue->dsize;
|
||||
memcpy(data, nl, queue->dsize);
|
||||
queue->start++;
|
||||
if (queue->start >= queue->capacity) {
|
||||
queue->start -= queue->capacity;
|
||||
}
|
||||
queue->size--;
|
||||
pthread_mutex_unlock(&queue->data_mutex);
|
||||
pthread_cond_signal(&queue->in_cond);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* queue.h
|
||||
*
|
||||
* Created on: Nov 19, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_H_
|
||||
#define QUEUE_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct queue {
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
size_t start;
|
||||
size_t end;
|
||||
size_t dsize;
|
||||
size_t rc;
|
||||
void* data;
|
||||
pthread_mutex_t data_mutex;
|
||||
pthread_mutex_t in_mutex;
|
||||
pthread_cond_t in_cond;
|
||||
pthread_mutex_t out_mutex;
|
||||
pthread_cond_t out_cond;
|
||||
};
|
||||
|
||||
struct queue* new_queue(size_t capacity, size_t data_size);
|
||||
|
||||
int del_queue(struct queue* queue);
|
||||
|
||||
int add_queue(struct queue* queue, void* data);
|
||||
|
||||
int pop_queue(struct queue* queue, void* data);
|
||||
|
||||
#endif /* QUEUE_H_ */
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* streams.c
|
||||
*
|
||||
* Created on: Nov 17, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
ssize_t readLine(int fd, char* line, size_t len) {
|
||||
if (len >= 1) line[0] = 0;
|
||||
char b = 0;
|
||||
int s = 0;
|
||||
int i = 0;
|
||||
do {
|
||||
s = read(fd, &b, 1);
|
||||
if ((s == 0 && i == 0) || s < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (s == 0) {
|
||||
break;
|
||||
}
|
||||
if (s > 0 && b != 13 && b != 10) {
|
||||
line[i++] = b;
|
||||
}
|
||||
} while (b > -1 && s > 0 && b != 10 && i < len - 1);
|
||||
line[i] = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
ssize_t writeLine(int fd, char* line, size_t len) {
|
||||
static char nl[2] = { 0x0A, 0x0D };
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
int x = write(fd, line + i, len - i);
|
||||
if (x < 0) return -1;
|
||||
i += x;
|
||||
}
|
||||
int i2 = 0;
|
||||
while (i2 < 2) {
|
||||
int y = write(fd, nl + i2, 2 - i2);
|
||||
if (y < 0) return -1;
|
||||
i2 += y;
|
||||
}
|
||||
return i;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* streams.h
|
||||
*
|
||||
* Created on: Nov 17, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef STREAMS_H_
|
||||
#define STREAMS_H_
|
||||
|
||||
size_t readLine(int fd, char* line, size_t len);
|
||||
|
||||
size_t writeLine(int fd, char* line, size_t len);
|
||||
|
||||
#endif /* STREAMS_H_ */
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* util.c
|
||||
*
|
||||
* Created on: Nov 17, 2015
|
||||
* Author: root
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "xstring.h"
|
||||
#include <linux/limits.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void* xmalloc(size_t size) {
|
||||
if (size > 10485760) {
|
||||
printf("Big malloc %u!\n", size);
|
||||
}
|
||||
void* m = malloc(size);
|
||||
if (m == NULL) {
|
||||
printf("Out of Memory! @ malloc size %u\n", size);
|
||||
exit(1);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void xfree(void* ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void* xcalloc(size_t size) {
|
||||
if (size > 10485760) {
|
||||
printf("Big calloc %u!\n", size);
|
||||
}
|
||||
void* m = calloc(1, size);
|
||||
if (m == NULL) {
|
||||
printf("Out of Memory! @ calloc size %u\n", size);
|
||||
exit(1);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void* xrealloc(void* ptr, size_t size) {
|
||||
if (size == 0) {
|
||||
xfree(ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (size > 10485760) {
|
||||
printf("Big realloc %u!\n", size);
|
||||
}
|
||||
void* m = realloc(ptr, size);
|
||||
if (m == NULL) {
|
||||
printf("Out of Memory! @ realloc size %u\n", size);
|
||||
exit(1);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void* xcopy(const void* ptr, size_t size, size_t expand) {
|
||||
void* alloc = xmalloc(size + expand);
|
||||
memcpy(alloc, ptr, size);
|
||||
return alloc;
|
||||
}
|
||||
|
||||
char* xstrdup(const char* str, size_t expand) {
|
||||
return xcopy(str, strlen(str) + 1, expand);
|
||||
}
|
||||
|
||||
int recur_mkdir(const char* path, mode_t mode) {
|
||||
char rp[PATH_MAX];
|
||||
realpath(path, rp);
|
||||
size_t pl = strlen(rp);
|
||||
char* pp[16];
|
||||
int ppi = 0;
|
||||
for (int i = 0; i < pl; i++) {
|
||||
if (rp[i] == '/') {
|
||||
if (ppi == 16) break;
|
||||
pp[ppi++] = &rp[i] + 1;
|
||||
rp[i] = 0;
|
||||
}
|
||||
}
|
||||
if (strlen(pp[ppi - 1]) == 0) ppi--;
|
||||
char vp[pl + 1];
|
||||
vp[pl] = 0;
|
||||
vp[0] = 0;
|
||||
for (int i = 0; i < ppi; i++) {
|
||||
strcat(vp, "/");
|
||||
strcat(vp, pp[i]);
|
||||
int r = mkdir(vp, mode);
|
||||
if (r == -1 && errno != EEXIST) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int memeq(const unsigned char* mem1, size_t mem1_size, const unsigned char* mem2, size_t mem2_size) {
|
||||
if (mem1 == NULL || mem2 == NULL) return 0;
|
||||
if (mem1 == mem2 && mem1_size == mem2_size) return 1;
|
||||
if (mem1_size != mem2_size) return 0;
|
||||
for (int i = 0; i < mem1_size; i++) {
|
||||
if (mem1[i] != mem2[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int memseq(const unsigned char* mem, size_t mem_size, const unsigned char c) {
|
||||
if (mem == NULL) return 0;
|
||||
for (int i = 0; i < mem_size; i++) {
|
||||
if (mem[i] != c) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* util.h
|
||||
*
|
||||
* Created on: Nov 17, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef UTIL_H_
|
||||
#define UTIL_H_
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void* xmalloc(size_t size);
|
||||
|
||||
void xfree(void* ptr);
|
||||
|
||||
void* xcalloc(size_t size);
|
||||
|
||||
void* xrealloc(void* ptr, size_t size);
|
||||
|
||||
void* xcopy(void* ptr, size_t size, size_t expand);
|
||||
|
||||
char* xstrdup(const char* str, size_t expand);
|
||||
|
||||
int recur_mkdir(const char* path, mode_t mode);
|
||||
|
||||
int memeq(const unsigned char* mem1, size_t mem1_size, const unsigned char* mem2, size_t mem2_size);
|
||||
|
||||
int memseq(const unsigned char* mem, size_t mem_size, const unsigned char c);
|
||||
|
||||
#endif /* UTIL_H_ */
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* version.h
|
||||
*
|
||||
* Created on: Nov 18, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef VERSION_H_
|
||||
#define VERSION_H_
|
||||
|
||||
#define VERSION "1.0.0"
|
||||
#define DAEMON_NAME "basin"
|
||||
#define DEBUG
|
||||
|
||||
#endif /* VERSION_H_ */
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* work.c
|
||||
*
|
||||
* Created on: Nov 18, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include "work.h"
|
||||
#include "accept.h"
|
||||
#include "xstring.h"
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include "collection.h"
|
||||
#include "util.h"
|
||||
#include "streams.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
void closeConn(struct work_param* param, struct conn* conn) {
|
||||
close(conn->fd);
|
||||
if (rem_collection(param->conns, conn)) {
|
||||
errlog(param->logsess, "Failed to delete connection properly! This is bad!");
|
||||
}
|
||||
if (conn->readBuffer != NULL) xfree(conn->readBuffer);
|
||||
if (conn->writeBuffer != NULL) xfree(conn->writeBuffer);
|
||||
xfree(conn);
|
||||
}
|
||||
|
||||
int handleRead(struct conn* conn, struct work_param* param, int fd) {
|
||||
if (conn->readBuffer != NULL && conn->readBuffer_size > 0) {
|
||||
if (conn->writeBuffer == NULL) {
|
||||
conn->writeBuffer = xmalloc(conn->readBuffer_size);
|
||||
conn->writeBuffer_size = 0;
|
||||
} else {
|
||||
conn->writeBuffer = xrealloc(conn->writeBuffer, conn->writeBuffer_size + conn->readBuffer_size);
|
||||
}
|
||||
memcpy(conn->writeBuffer + conn->writeBuffer_size, conn->readBuffer, conn->readBuffer_size);
|
||||
conn->writeBuffer_size += conn->readBuffer_size;
|
||||
xfree(conn->readBuffer);
|
||||
conn->readBuffer = NULL;
|
||||
conn->readBuffer_size = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_work(struct work_param* param) {
|
||||
if (pipe(param->pipes) != 0) {
|
||||
printf("Failed to create pipe! %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
unsigned char wb;
|
||||
unsigned char* mbuf = xmalloc(1024);
|
||||
while (1) {
|
||||
pthread_rwlock_rdlock(¶m->conns->data_mutex);
|
||||
size_t cc = param->conns->count;
|
||||
struct pollfd fds[cc + 1];
|
||||
struct conn* conns[cc];
|
||||
int fdi = 0;
|
||||
for (int i = 0; i < param->conns->size; i++) {
|
||||
if (param->conns->data[i * param->conns->dsize] != NULL) {
|
||||
conns[fdi] = (param->conns->data[i * param->conns->dsize]);
|
||||
struct conn* conn = conns[fdi];
|
||||
fds[fdi].fd = conns[fdi]->fd;
|
||||
fds[fdi].events = POLLIN | (conn->writeBuffer_size > 0 ? POLLOUT : 0);
|
||||
fds[fdi++].revents = 0;
|
||||
if (fdi == cc) break;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(¶m->conns->data_mutex);
|
||||
fds[cc].fd = param->pipes[0];
|
||||
fds[cc].events = POLLIN;
|
||||
fds[cc].revents = 0;
|
||||
int cp = poll(fds, cc + 1, -1);
|
||||
if (cp < 0) {
|
||||
printf("Poll error in worker thread! %s\n", strerror(errno));
|
||||
} else if (cp == 0) continue;
|
||||
else if ((fds[cc].revents & POLLIN) == POLLIN) {
|
||||
if (read(param->pipes[0], &wb, 1) < 1) printf("Error reading from pipe, infinite loop COULD happen here.\n");
|
||||
if (cp-- == 1) continue;
|
||||
}
|
||||
for (int i = 0; i < cc; i++) {
|
||||
int re = fds[i].revents;
|
||||
struct conn* conn = conns[i];
|
||||
if ((re & POLLERR) == POLLERR) {
|
||||
//printf("POLLERR in worker poll! This is bad!\n");
|
||||
goto cont;
|
||||
}
|
||||
if ((re & POLLHUP) == POLLHUP) {
|
||||
closeConn(param, conn);
|
||||
goto cont;
|
||||
}
|
||||
if ((re & POLLNVAL) == POLLNVAL) {
|
||||
printf("Invalid FD in worker poll! This is bad!\n");
|
||||
closeConn(param, conn);
|
||||
goto cont;
|
||||
}
|
||||
if ((re & POLLIN) == POLLIN) {
|
||||
size_t tr = 0;
|
||||
ioctl(fds[i].fd, FIONREAD, &tr);
|
||||
unsigned char* loc;
|
||||
if (conn->readBuffer == NULL) {
|
||||
conn->readBuffer = xmalloc(tr); // TODO: max upload?
|
||||
conn->readBuffer_size = tr;
|
||||
loc = conn->readBuffer;
|
||||
} else {
|
||||
conn->readBuffer_size += tr;
|
||||
conn->readBuffer = xrealloc(conn->readBuffer, conn->readBuffer_size);
|
||||
loc = conn->readBuffer + conn->readBuffer_size - tr;
|
||||
}
|
||||
ssize_t r = 0;
|
||||
if (r == 0 && tr == 0) { // nothing to read, but wont block.
|
||||
ssize_t x = read(fds[i].fd, loc + r, tr - r);
|
||||
if (x <= 0) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
r += x;
|
||||
}
|
||||
while (r < tr) {
|
||||
ssize_t x = read(fds[i].fd, loc + r, tr - r);
|
||||
if (x <= 0) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
r += x;
|
||||
}
|
||||
int p = 0;
|
||||
p = handleRead(conn, param, fds[i].fd);
|
||||
if (p == 1) {
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
if ((re & POLLOUT) == POLLOUT && conn != NULL) {
|
||||
ssize_t mtr = write(fds[i].fd, conn->writeBuffer, conn->writeBuffer_size);
|
||||
if (mtr < 0 && errno != EAGAIN) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
} else if (mtr < 0) {
|
||||
goto cont;
|
||||
} else if (mtr < conn->writeBuffer_size) {
|
||||
memmove(conn->writeBuffer, conn->writeBuffer + mtr, conn->writeBuffer_size - mtr);
|
||||
conn->writeBuffer_size -= mtr;
|
||||
conn->writeBuffer = xrealloc(conn->writeBuffer, conn->writeBuffer_size);
|
||||
} else {
|
||||
conn->writeBuffer_size = 0;
|
||||
xfree(conn->writeBuffer);
|
||||
conn->writeBuffer = NULL;
|
||||
}
|
||||
}
|
||||
cont: ;
|
||||
if (--cp == 0) break;
|
||||
}
|
||||
}
|
||||
xfree(mbuf);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* work.h
|
||||
*
|
||||
* Created on: Nov 18, 2015
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef WORK_H_
|
||||
#define WORK_H_
|
||||
|
||||
#include "collection.h"
|
||||
#include "accept.h"
|
||||
#include "log.h"
|
||||
|
||||
struct work_param {
|
||||
struct collection* conns;
|
||||
int pipes[2];
|
||||
struct logsess* logsess;
|
||||
int i;
|
||||
int sport;
|
||||
};
|
||||
|
||||
void run_work(struct work_param* param);
|
||||
|
||||
#endif /* WORK_H_ */
|
|
@ -91,8 +91,8 @@ int endsWith(const char* str, const char* with) {
|
|||
size_t l1 = strlen(str);
|
||||
size_t l2 = strlen(with);
|
||||
if (l1 < l2) return 0;
|
||||
for (int i = 0; i < l2; i++) {
|
||||
if (str[l1 - 1 - (l2 - 1 - i)] != with[i]) {
|
||||
for (int i = l2 - 1; i >= 0; i--) {
|
||||
if (str[i] != with[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -105,8 +105,8 @@ int endsWith_nocase(const char* str, const char* with) {
|
|||
size_t l1 = strlen(str);
|
||||
size_t l2 = strlen(with);
|
||||
if (l1 < l2) return 0;
|
||||
for (int i = 0; i < l2; i++) {
|
||||
char s1 = str[l1 - 1 - (l2 - 1 - i)];
|
||||
for (int i = l2 - 1; i >= 0; i--) {
|
||||
char s1 = str[i];
|
||||
if (s1 >= 'A' && s1 <= 'Z') s1 += ' ';
|
||||
char s2 = with[i];
|
||||
if (s2 >= 'A' && s2 <= 'Z') s2 += ' ';
|
||||
|
|
Loading…
Reference in New Issue