more
This commit is contained in:
parent
942294317a
commit
2f122529b0
1
contrib/backends/nntpchan-daemon/.gitignore
vendored
1
contrib/backends/nntpchan-daemon/.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
*.o
|
*.o
|
||||||
|
*.a
|
||||||
nntpd
|
nntpd
|
||||||
nntpchan-tool
|
nntpchan-tool
|
||||||
test
|
test
|
||||||
|
@ -17,18 +17,21 @@ LD_FLAGS := $(shell pkg-config --libs $(PKGS))
|
|||||||
INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I $(REPO)/src
|
INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I $(REPO)/src
|
||||||
CXXFLAGS := -std=c++11 -Wall -Wextra $(INC_FLAGS) -g
|
CXXFLAGS := -std=c++11 -Wall -Wextra $(INC_FLAGS) -g
|
||||||
|
|
||||||
|
LIB = libnntpchan.a
|
||||||
|
|
||||||
all: $(EXE) $(TOOL)
|
all: $(EXE) $(TOOL)
|
||||||
|
|
||||||
$(EXE): $(OBJECTS)
|
$(LIB): $(OBJECTS)
|
||||||
$(CXX) -o $(EXE) $(OBJECTS) $(CXXFLAGS) nntpd.cpp $(LD_FLAGS)
|
$(AR) -q $(LIB) $(OBJECTS)
|
||||||
|
|
||||||
$(TOOL): $(OBJECTS)
|
$(EXE): $(LIB)
|
||||||
$(CXX) -o $(TOOL) $(OBJECTS) $(CXXFLAGS) tool.cpp $(LD_FLAGS)
|
$(CXX) -o $(EXE) $(CXXFLAGS) nntpd.cpp $(LIB) $(LD_FLAGS)
|
||||||
|
|
||||||
build-test: $(OBJECTS)
|
$(TOOL): $(LIB)
|
||||||
$(CXX) -o test $(OBJECTS) $(CXXFLAGS) test.cpp $(LD_FLAGS)
|
$(CXX) -o $(TOOL) $(CXXFLAGS) tool.cpp $(LIB) $(LD_FLAGS)
|
||||||
|
|
||||||
|
build-test: $(LIB)
|
||||||
|
$(CXX) -o test $(CXXFLAGS) test.cpp $(LIB) $(LD_FLAGS)
|
||||||
|
|
||||||
test: build-test
|
test: build-test
|
||||||
./test
|
./test
|
||||||
@ -37,4 +40,4 @@ test: build-test
|
|||||||
$(CXX) $(CXXFLAGS) -c -o $@
|
$(CXX) $(CXXFLAGS) -c -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJECTS) $(EXE) $(TOOL) test
|
rm -f $(OBJECTS) $(LIB) $(EXE) $(TOOL) test
|
||||||
|
6
contrib/backends/nntpchan-daemon/src/http.hpp
Normal file
6
contrib/backends/nntpchan-daemon/src/http.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef NNTPCHAN_HTTP_HPP
|
||||||
|
#define NNTPCHAN_HTTP_HPP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
5
contrib/backends/nntpchan-daemon/src/http_client.hpp
Normal file
5
contrib/backends/nntpchan-daemon/src/http_client.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#ifndef NNTPCHAN_HTTP_CLIENT_HPP
|
||||||
|
#define NNTPCHAN_HTTP_CLIENT_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
6
contrib/backends/nntpchan-daemon/src/http_server.hpp
Normal file
6
contrib/backends/nntpchan-daemon/src/http_server.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef NNTPCHAN_HTTP_SERVER_HPP
|
||||||
|
#define NNTPCHAN_HTTP_SERVER_HPP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -3,20 +3,35 @@
|
|||||||
|
|
||||||
namespace nntpchan {
|
namespace nntpchan {
|
||||||
|
|
||||||
|
LineReader::LineReader(size_t limit) : m_close(false), lineLimit(limit) {}
|
||||||
|
|
||||||
void LineReader::OnData(const char * d, ssize_t l)
|
void LineReader::OnData(const char * d, ssize_t l)
|
||||||
{
|
{
|
||||||
if(l <= 0) return;
|
if(l <= 0) return;
|
||||||
|
// process leftovers
|
||||||
|
std::string current = m_leftovers + std::string(d, l);
|
||||||
|
if(current.size() > lineLimit) {
|
||||||
|
m_close = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::size_t idx = 0;
|
std::size_t idx = 0;
|
||||||
|
ssize_t begin = l;
|
||||||
|
const char * data = current.c_str();
|
||||||
while(l-- > 0) {
|
while(l-- > 0) {
|
||||||
char c = d[idx++];
|
char c = data[idx++];
|
||||||
if(c == '\n') {
|
if(c == '\n') {
|
||||||
OnLine(d, idx-1);
|
OnLine(data, idx-1);
|
||||||
d += idx;
|
data += idx;
|
||||||
} else if (c == '\r' && d[idx] == '\n') {
|
} else if (c == '\r' && data[idx] == '\n') {
|
||||||
OnLine(d, idx-1);
|
OnLine(data, idx-1);
|
||||||
d += idx + 1;
|
data += idx + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (idx < begin)
|
||||||
|
{
|
||||||
|
// leftovers
|
||||||
|
m_leftovers = std::string(data, begin-idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineReader::OnLine(const char *d, const size_t l)
|
void LineReader::OnLine(const char *d, const size_t l)
|
||||||
@ -24,21 +39,9 @@ namespace nntpchan {
|
|||||||
std::string line(d, l);
|
std::string line(d, l);
|
||||||
HandleLine(line);
|
HandleLine(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineReader::HasNextLine()
|
|
||||||
{
|
|
||||||
return m_sendlines.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LineReader::GetNextLine()
|
bool LineReader::ShouldClose()
|
||||||
{
|
{
|
||||||
std::string line = m_sendlines[0];
|
return m_close;
|
||||||
m_sendlines.pop_front();
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LineReader::QueueLine(const std::string & line)
|
|
||||||
{
|
|
||||||
m_sendlines.push_back(line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,33 @@
|
|||||||
#ifndef NNTPCHAN_LINE_HPP
|
#ifndef NNTPCHAN_LINE_HPP
|
||||||
#define NNTPCHAN_LINE_HPP
|
#define NNTPCHAN_LINE_HPP
|
||||||
#include <string>
|
#include "server.hpp"
|
||||||
#include <deque>
|
#include <stdint.h>
|
||||||
namespace nntpchan
|
namespace nntpchan
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @brief a buffered line reader */
|
/** @brief a buffered line reader */
|
||||||
class LineReader
|
class LineReader : public IConnHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
LineReader(size_t lineLimit);
|
||||||
|
|
||||||
/** @brief queue inbound data from connection */
|
/** @brief queue inbound data from connection */
|
||||||
void OnData(const char * data, ssize_t s);
|
virtual void OnData(const char * data, ssize_t s);
|
||||||
|
|
||||||
/** @brief do we have line to send to the client? */
|
/** implements IConnHandler */
|
||||||
bool HasNextLine();
|
virtual bool ShouldClose();
|
||||||
/** @brief get the next line to send to the client, does not check if it exists */
|
|
||||||
std::string GetNextLine();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** @brief handle a line from the client */
|
/** @brief handle a line from the client */
|
||||||
virtual void HandleLine(const std::string & line) = 0;
|
virtual void HandleLine(const std::string & line) = 0;
|
||||||
/** @brief queue the next line to send to the client */
|
|
||||||
void QueueLine(const std::string & line);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnLine(const char * d, const size_t l);
|
void OnLine(const char * d, const size_t l);
|
||||||
// lines to send
|
std::string m_leftovers;
|
||||||
std::deque<std::string> m_sendlines;
|
bool m_close;
|
||||||
|
const size_t lineLimit;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
257
contrib/backends/nntpchan-daemon/src/mustach.c
Normal file
257
contrib/backends/nntpchan-daemon/src/mustach.c
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
Author: José Bollo <jobol@nonadev.net>
|
||||||
|
Author: José Bollo <jose.bollo@iot.bzh>
|
||||||
|
|
||||||
|
https://gitlab.com/jobol/mustach
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "mustach.h"
|
||||||
|
|
||||||
|
#define NAME_LENGTH_MAX 1024
|
||||||
|
#define DEPTH_MAX 256
|
||||||
|
|
||||||
|
static int getpartial(struct mustach_itf *itf, void *closure, const char *name, char **result)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
FILE *file;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
file = open_memstream(result, &size);
|
||||||
|
if (file == NULL)
|
||||||
|
rc = MUSTACH_ERROR_SYSTEM;
|
||||||
|
else {
|
||||||
|
rc = itf->put(closure, name, 0, file);
|
||||||
|
if (rc == 0)
|
||||||
|
/* adds terminating null */
|
||||||
|
rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
|
||||||
|
fclose(file);
|
||||||
|
if (rc < 0) {
|
||||||
|
free(*result);
|
||||||
|
*result = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int process(const char *template, struct mustach_itf *itf, void *closure, FILE *file, const char *opstr, const char *clstr)
|
||||||
|
{
|
||||||
|
char name[NAME_LENGTH_MAX + 1], *partial, c;
|
||||||
|
const char *beg, *term;
|
||||||
|
struct { const char *name, *again; size_t length; int emit, entered; } stack[DEPTH_MAX];
|
||||||
|
size_t oplen, cllen, len, l;
|
||||||
|
int depth, rc, emit;
|
||||||
|
|
||||||
|
emit = 1;
|
||||||
|
oplen = strlen(opstr);
|
||||||
|
cllen = strlen(clstr);
|
||||||
|
depth = 0;
|
||||||
|
for(;;) {
|
||||||
|
beg = strstr(template, opstr);
|
||||||
|
if (beg == NULL) {
|
||||||
|
/* no more mustach */
|
||||||
|
if (emit)
|
||||||
|
fwrite(template, strlen(template), 1, file);
|
||||||
|
return depth ? MUSTACH_ERROR_UNEXPECTED_END : 0;
|
||||||
|
}
|
||||||
|
if (emit)
|
||||||
|
fwrite(template, (size_t)(beg - template), 1, file);
|
||||||
|
beg += oplen;
|
||||||
|
term = strstr(beg, clstr);
|
||||||
|
if (term == NULL)
|
||||||
|
return MUSTACH_ERROR_UNEXPECTED_END;
|
||||||
|
template = term + cllen;
|
||||||
|
len = (size_t)(term - beg);
|
||||||
|
c = *beg;
|
||||||
|
switch(c) {
|
||||||
|
case '!':
|
||||||
|
case '=':
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
for (l = 0 ; clstr[l] == '}' ; l++);
|
||||||
|
if (clstr[l]) {
|
||||||
|
if (!len || beg[len-1] != '}')
|
||||||
|
return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
|
||||||
|
len--;
|
||||||
|
} else {
|
||||||
|
if (term[l] != '}')
|
||||||
|
return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
|
||||||
|
template++;
|
||||||
|
}
|
||||||
|
c = '&';
|
||||||
|
case '^':
|
||||||
|
case '#':
|
||||||
|
case '/':
|
||||||
|
case '&':
|
||||||
|
case '>':
|
||||||
|
#if !defined(NO_EXTENSION_FOR_MUSTACH) && !defined(NO_COLON_EXTENSION_FOR_MUSTACH)
|
||||||
|
case ':':
|
||||||
|
#endif
|
||||||
|
beg++; len--;
|
||||||
|
default:
|
||||||
|
while (len && isspace(beg[0])) { beg++; len--; }
|
||||||
|
while (len && isspace(beg[len-1])) len--;
|
||||||
|
if (len == 0)
|
||||||
|
return MUSTACH_ERROR_EMPTY_TAG;
|
||||||
|
if (len > NAME_LENGTH_MAX)
|
||||||
|
return MUSTACH_ERROR_TAG_TOO_LONG;
|
||||||
|
memcpy(name, beg, len);
|
||||||
|
name[len] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch(c) {
|
||||||
|
case '!':
|
||||||
|
/* comment */
|
||||||
|
/* nothing to do */
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
/* defines separators */
|
||||||
|
if (len < 5 || beg[len - 1] != '=')
|
||||||
|
return MUSTACH_ERROR_BAD_SEPARATORS;
|
||||||
|
beg++;
|
||||||
|
len -= 2;
|
||||||
|
for (l = 0; l < len && !isspace(beg[l]) ; l++);
|
||||||
|
if (l == len)
|
||||||
|
return MUSTACH_ERROR_BAD_SEPARATORS;
|
||||||
|
opstr = strndupa(beg, l);
|
||||||
|
while (l < len && isspace(beg[l])) l++;
|
||||||
|
if (l == len)
|
||||||
|
return MUSTACH_ERROR_BAD_SEPARATORS;
|
||||||
|
clstr = strndupa(beg + l, len - l);
|
||||||
|
oplen = strlen(opstr);
|
||||||
|
cllen = strlen(clstr);
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
case '#':
|
||||||
|
/* begin section */
|
||||||
|
if (depth == DEPTH_MAX)
|
||||||
|
return MUSTACH_ERROR_TOO_DEPTH;
|
||||||
|
rc = emit;
|
||||||
|
if (rc) {
|
||||||
|
rc = itf->enter(closure, name);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
stack[depth].name = beg;
|
||||||
|
stack[depth].again = template;
|
||||||
|
stack[depth].length = len;
|
||||||
|
stack[depth].emit = emit;
|
||||||
|
stack[depth].entered = rc;
|
||||||
|
if ((c == '#') == (rc == 0))
|
||||||
|
emit = 0;
|
||||||
|
depth++;
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
/* end section */
|
||||||
|
if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len))
|
||||||
|
return MUSTACH_ERROR_CLOSING;
|
||||||
|
rc = emit && stack[depth].entered ? itf->next(closure) : 0;
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
if (rc) {
|
||||||
|
template = stack[depth++].again;
|
||||||
|
} else {
|
||||||
|
emit = stack[depth].emit;
|
||||||
|
if (emit && stack[depth].entered)
|
||||||
|
itf->leave(closure);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
/* partials */
|
||||||
|
if (emit) {
|
||||||
|
rc = getpartial(itf, closure, name, &partial);
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = process(partial, itf, closure, file, opstr, clstr);
|
||||||
|
free(partial);
|
||||||
|
}
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* replacement */
|
||||||
|
if (emit) {
|
||||||
|
rc = itf->put(closure, name, c != '&', file);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fmustach(const char *template, struct mustach_itf *itf, void *closure, FILE *file)
|
||||||
|
{
|
||||||
|
int rc = itf->start ? itf->start(closure) : 0;
|
||||||
|
if (rc == 0)
|
||||||
|
rc = process(template, itf, closure, file, "{{", "}}");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdmustach(const char *template, struct mustach_itf *itf, void *closure, int fd)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
file = fdopen(fd, "w");
|
||||||
|
if (file == NULL) {
|
||||||
|
rc = MUSTACH_ERROR_SYSTEM;
|
||||||
|
errno = ENOMEM;
|
||||||
|
} else {
|
||||||
|
rc = fmustach(template, itf, closure, file);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mustach(const char *template, struct mustach_itf *itf, void *closure, char **result, size_t *size)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
FILE *file;
|
||||||
|
size_t s;
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
if (size == NULL)
|
||||||
|
size = &s;
|
||||||
|
file = open_memstream(result, size);
|
||||||
|
if (file == NULL) {
|
||||||
|
rc = MUSTACH_ERROR_SYSTEM;
|
||||||
|
errno = ENOMEM;
|
||||||
|
} else {
|
||||||
|
rc = fmustach(template, itf, closure, file);
|
||||||
|
if (rc == 0)
|
||||||
|
/* adds terminating null */
|
||||||
|
rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
|
||||||
|
fclose(file);
|
||||||
|
if (rc >= 0)
|
||||||
|
/* removes terminating null of the length */
|
||||||
|
(*size)--;
|
||||||
|
else {
|
||||||
|
free(*result);
|
||||||
|
*result = NULL;
|
||||||
|
*size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
112
contrib/backends/nntpchan-daemon/src/mustach.h
Normal file
112
contrib/backends/nntpchan-daemon/src/mustach.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
Author: José Bollo <jobol@nonadev.net>
|
||||||
|
Author: José Bollo <jose.bollo@iot.bzh>
|
||||||
|
|
||||||
|
https://gitlab.com/jobol/mustach
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _mustach_h_included_
|
||||||
|
#define _mustach_h_included_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mustach_itf - interface for callbacks
|
||||||
|
*
|
||||||
|
* All of this function should return a negative value to stop
|
||||||
|
* the mustache processing. The returned negative value will be
|
||||||
|
* then returned to the caller of mustach as is.
|
||||||
|
*
|
||||||
|
* The functions enter and next should return 0 or 1.
|
||||||
|
*
|
||||||
|
* All other functions should normally return 0.
|
||||||
|
*
|
||||||
|
* @start: Starts the mustach processing of the closure
|
||||||
|
* 'start' is optional (can be NULL)
|
||||||
|
*
|
||||||
|
* @put: Writes the value of 'name' to 'file' with 'escape' or not
|
||||||
|
*
|
||||||
|
* @enter: Enters the section of 'name' if possible.
|
||||||
|
* Musts return 1 if entered or 0 if not entered.
|
||||||
|
* When 1 is returned, the function 'leave' will always be called.
|
||||||
|
* Conversely 'leave' is never called when enter returns 0 or
|
||||||
|
* a negative value.
|
||||||
|
* When 1 is returned, the function must activate the first
|
||||||
|
* item of the section.
|
||||||
|
*
|
||||||
|
* @next: Activates the next item of the section if it exists.
|
||||||
|
* Musts return 1 when the next item is activated.
|
||||||
|
* Musts return 0 when there is no item to activate.
|
||||||
|
*
|
||||||
|
* @leave: Leaves the last entered section
|
||||||
|
*/
|
||||||
|
struct mustach_itf {
|
||||||
|
int (*start)(void *closure);
|
||||||
|
int (*put)(void *closure, const char *name, int escape, FILE *file);
|
||||||
|
int (*enter)(void *closure, const char *name);
|
||||||
|
int (*next)(void *closure);
|
||||||
|
int (*leave)(void *closure);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MUSTACH_OK 0
|
||||||
|
#define MUSTACH_ERROR_SYSTEM -1
|
||||||
|
#define MUSTACH_ERROR_UNEXPECTED_END -2
|
||||||
|
#define MUSTACH_ERROR_EMPTY_TAG -3
|
||||||
|
#define MUSTACH_ERROR_TAG_TOO_LONG -4
|
||||||
|
#define MUSTACH_ERROR_BAD_SEPARATORS -5
|
||||||
|
#define MUSTACH_ERROR_TOO_DEPTH -6
|
||||||
|
#define MUSTACH_ERROR_CLOSING -7
|
||||||
|
#define MUSTACH_ERROR_BAD_UNESCAPE_TAG -8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fmustach - Renders the mustache 'template' in 'file' for 'itf' and 'closure'.
|
||||||
|
*
|
||||||
|
* @template: the template string to instanciate
|
||||||
|
* @itf: the interface to the functions that mustach calls
|
||||||
|
* @closure: the closure to pass to functions called
|
||||||
|
* @file: the file where to write the result
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success, -1 with errno set in case of system error
|
||||||
|
* a other negative value in case of error.
|
||||||
|
*/
|
||||||
|
extern int fmustach(const char *template, struct mustach_itf *itf, void *closure, FILE *file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fmustach - Renders the mustache 'template' in 'fd' for 'itf' and 'closure'.
|
||||||
|
*
|
||||||
|
* @template: the template string to instanciate
|
||||||
|
* @itf: the interface to the functions that mustach calls
|
||||||
|
* @closure: the closure to pass to functions called
|
||||||
|
* @fd: the file descriptor number where to write the result
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success, -1 with errno set in case of system error
|
||||||
|
* a other negative value in case of error.
|
||||||
|
*/
|
||||||
|
extern int fdmustach(const char *template, struct mustach_itf *itf, void *closure, int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fmustach - Renders the mustache 'template' in 'result' for 'itf' and 'closure'.
|
||||||
|
*
|
||||||
|
* @template: the template string to instanciate
|
||||||
|
* @itf: the interface to the functions that mustach calls
|
||||||
|
* @closure: the closure to pass to functions called
|
||||||
|
* @result: the pointer receiving the result when 0 is returned
|
||||||
|
* @size: the size of the returned result
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success, -1 with errno set in case of system error
|
||||||
|
* a other negative value in case of error.
|
||||||
|
*/
|
||||||
|
extern int mustach(const char *template, struct mustach_itf *itf, void *closure, char **result, size_t *size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
namespace nntpchan
|
namespace nntpchan
|
||||||
{
|
{
|
||||||
|
HashedCredDB::HashedCredDB() : LineReader(1024) {}
|
||||||
|
|
||||||
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_access);
|
std::unique_lock<std::mutex> lock(m_access);
|
||||||
@ -58,7 +60,7 @@ namespace nntpchan
|
|||||||
{
|
{
|
||||||
m_instream = s;
|
m_instream = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
|
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
|
||||||
{
|
{
|
||||||
SHA512Digest h;
|
SHA512Digest h;
|
||||||
@ -71,7 +73,7 @@ namespace nntpchan
|
|||||||
m_fname(fname),
|
m_fname(fname),
|
||||||
f(nullptr)
|
f(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HashedFileDB::~HashedFileDB()
|
HashedFileDB::~HashedFileDB()
|
||||||
@ -95,4 +97,3 @@ namespace nntpchan
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,20 +20,21 @@ namespace nntpchan
|
|||||||
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
|
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
|
||||||
virtual ~NNTPCredentialDB() {}
|
virtual ~NNTPCredentialDB() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief nntp credential db using hashed+salted passwords */
|
/** @brief nntp credential db using hashed+salted passwords */
|
||||||
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
HashedCredDB();
|
||||||
bool CheckLogin(const std::string & user, const std::string & passwd);
|
bool CheckLogin(const std::string & user, const std::string & passwd);
|
||||||
protected:
|
protected:
|
||||||
void SetStream(std::istream * i);
|
void SetStream(std::istream * i);
|
||||||
|
|
||||||
std::string Hash(const std::string & data, const std::string & salt);
|
std::string Hash(const std::string & data, const std::string & salt);
|
||||||
void HandleLine(const std::string & line);
|
void HandleLine(const std::string & line);
|
||||||
private:
|
private:
|
||||||
bool ProcessLine(const std::string & line);
|
bool ProcessLine(const std::string & line);
|
||||||
|
|
||||||
std::mutex m_access;
|
std::mutex m_access;
|
||||||
std::string m_user, m_passwd;
|
std::string m_user, m_passwd;
|
||||||
bool m_found;
|
bool m_found;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
namespace nntpchan
|
namespace nntpchan
|
||||||
{
|
{
|
||||||
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
||||||
|
LineReader(1024),
|
||||||
m_auth(nullptr),
|
m_auth(nullptr),
|
||||||
m_store(storage),
|
m_store(storage),
|
||||||
m_authed(false),
|
m_authed(false),
|
||||||
|
@ -38,7 +38,7 @@ namespace nntpchan
|
|||||||
NNTPServer * self = (NNTPServer *) s->data;
|
NNTPServer * self = (NNTPServer *) s->data;
|
||||||
self->OnAccept(s, status);
|
self->OnAccept(s, status);
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(uv_listen(*this, 5, cb) == 0);
|
assert(uv_listen(*this, 5, cb) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ namespace nntpchan
|
|||||||
std::ifstream i;
|
std::ifstream i;
|
||||||
i.open(m_logindbpath);
|
i.open(m_logindbpath);
|
||||||
if(i.is_open()) creds = new HashedFileDB(m_logindbpath);
|
if(i.is_open()) creds = new HashedFileDB(m_logindbpath);
|
||||||
|
|
||||||
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath, creds);
|
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath, creds);
|
||||||
conn->Greet();
|
conn->Greet();
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ namespace nntpchan
|
|||||||
{
|
{
|
||||||
m_logindbpath = path;
|
m_logindbpath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NNTPServer::SetStoragePath(const std::string & path)
|
void NNTPServer::SetStoragePath(const std::string & path)
|
||||||
{
|
{
|
||||||
@ -75,7 +75,7 @@ namespace nntpchan
|
|||||||
if(m_frontend) delete m_frontend;
|
if(m_frontend) delete m_frontend;
|
||||||
m_frontend = f;
|
m_frontend = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) :
|
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) :
|
||||||
m_handler(storage)
|
m_handler(storage)
|
||||||
{
|
{
|
||||||
@ -110,7 +110,7 @@ namespace nntpchan
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void NNTPServerConn::SendNextReply()
|
void NNTPServerConn::SendNextReply()
|
||||||
{
|
{
|
||||||
if(m_handler.HasNextLine()) {
|
if(m_handler.HasNextLine()) {
|
||||||
@ -125,7 +125,7 @@ namespace nntpchan
|
|||||||
m_handler.Greet();
|
m_handler.Greet();
|
||||||
SendNextReply();
|
SendNextReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NNTPServerConn::SendString(const std::string & str)
|
void NNTPServerConn::SendString(const std::string & str)
|
||||||
{
|
{
|
||||||
WriteBuffer * b = new WriteBuffer(str);
|
WriteBuffer * b = new WriteBuffer(str);
|
||||||
@ -145,5 +145,5 @@ namespace nntpchan
|
|||||||
delete self;
|
delete self;
|
||||||
s->data = nullptr;
|
s->data = nullptr;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
contrib/backends/nntpchan-daemon/src/server.cpp
Normal file
61
contrib/backends/nntpchan-daemon/src/server.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "server.hpp"
|
||||||
|
#include "net.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
Server::Server(uv_loop_t * loop)
|
||||||
|
{
|
||||||
|
m_loop = loop;
|
||||||
|
uv_tcp_init(m_loop, &m_server);
|
||||||
|
m_server.data = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::Close()
|
||||||
|
{
|
||||||
|
uv_close((uv_handle_t*)&m_server, [](uv_handle_t * s) {
|
||||||
|
Server * self = (Server*)s->data;
|
||||||
|
if (self) delete self;
|
||||||
|
s->data = nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::Bind(const std::string & addr)
|
||||||
|
{
|
||||||
|
auto saddr = ParseAddr(addr);
|
||||||
|
assert(uv_tcp_bind(*this, saddr, 0) == 0);
|
||||||
|
auto cb = [] (uv_stream_t * s, int status) {
|
||||||
|
Server * self = (Server *) s->data;
|
||||||
|
self->OnAccept(s, status);
|
||||||
|
};
|
||||||
|
assert(uv_listen(*this, 5, cb) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::OnAccept(uv_stream_t * s, int status)
|
||||||
|
{
|
||||||
|
if(status < 0) {
|
||||||
|
OnAcceptError(status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IServerConn * conn = CreateConn(s);
|
||||||
|
assert(conn);
|
||||||
|
conn->Greet();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IConnHandler::QueueLine(const std::string & line)
|
||||||
|
{
|
||||||
|
m_sendlines.push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IConnHandler::HasNextLine()
|
||||||
|
{
|
||||||
|
return m_sendlines.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IConnHandler::GetNextLine()
|
||||||
|
{
|
||||||
|
std::string line = m_sendlines[0];
|
||||||
|
m_sendlines.pop_front();
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
}
|
93
contrib/backends/nntpchan-daemon/src/server.hpp
Normal file
93
contrib/backends/nntpchan-daemon/src/server.hpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#ifndef NNTPCHAN_SERVER_HPP
|
||||||
|
#define NNTPCHAN_SERVER_HPP
|
||||||
|
#include <uv.h>
|
||||||
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
|
||||||
|
|
||||||
|
struct IConnHandler
|
||||||
|
{
|
||||||
|
/** got inbound data */
|
||||||
|
virtual void OnData(const char * data, ssize_t s) = 0;
|
||||||
|
|
||||||
|
/** get next line of data to send */
|
||||||
|
std::string GetNextLine();
|
||||||
|
|
||||||
|
/** return true if we have a line to send */
|
||||||
|
bool HasNextLine();
|
||||||
|
|
||||||
|
/** return true if we should close this connection otherwise return false */
|
||||||
|
virtual bool ShouldClose() = 0;
|
||||||
|
|
||||||
|
/** queue a data send */
|
||||||
|
void QueueLine(const std::string & line);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::deque<std::string> m_sendlines;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** server connection handler interface */
|
||||||
|
struct IServerConn
|
||||||
|
{
|
||||||
|
IServerConn(uv_loop_t * l, uv_stream_t * s, Server * parent, IConnHandler * h);
|
||||||
|
virtual ~IServerConn() = 0;
|
||||||
|
virtual void Close() = 0;
|
||||||
|
virtual void Greet() = 0;
|
||||||
|
virtual void SendNextReply() = 0;
|
||||||
|
virtual bool IsTimedOut() = 0;
|
||||||
|
Server * Parent() { return m_parent; };
|
||||||
|
IConnHandler * GetHandler() { return m_handler; };
|
||||||
|
operator uv_stream_t * () { return m_stream; };
|
||||||
|
uv_loop_t * GetLoop() { return m_loop; };
|
||||||
|
private:
|
||||||
|
uv_stream_t * m_stream;
|
||||||
|
uv_loop_t * m_loop;
|
||||||
|
Server * m_parent;
|
||||||
|
IConnHandler * m_handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Server(uv_loop_t * loop);
|
||||||
|
/** called after socket close, NEVER call directly */
|
||||||
|
virtual ~Server() {}
|
||||||
|
/** create connection handler from open stream */
|
||||||
|
virtual IServerConn * CreateConn(uv_stream_t * s) = 0;
|
||||||
|
/** close all sockets and stop */
|
||||||
|
void Close();
|
||||||
|
/** bind to address */
|
||||||
|
void Bind(const std::string & addr);
|
||||||
|
|
||||||
|
typedef std::function<void(IServerConn *)> ConnVisitor;
|
||||||
|
|
||||||
|
/** visit all open connections */
|
||||||
|
void VisitConns(ConnVisitor v);
|
||||||
|
|
||||||
|
/** remove connection from server, called after proper close */
|
||||||
|
void RemoveConn(IServerConn * conn);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uv_loop_t * GetLoop() { return m_loop; }
|
||||||
|
virtual void OnAcceptError(int status) = 0;
|
||||||
|
private:
|
||||||
|
operator uv_handle_t * () { return (uv_handle_t*) &m_server; }
|
||||||
|
operator uv_tcp_t * () { return &m_server; }
|
||||||
|
operator uv_stream_t * () { return (uv_stream_t *) &m_server; }
|
||||||
|
|
||||||
|
void OnAccept(uv_stream_t * s, int status);
|
||||||
|
std::vector<IServerConn *> m_conns;
|
||||||
|
uv_tcp_t m_server;
|
||||||
|
uv_loop_t * m_loop;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user