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
|
||||
*.a
|
||||
nntpd
|
||||
nntpchan-tool
|
||||
test
|
||||
|
@ -17,18 +17,21 @@ LD_FLAGS := $(shell pkg-config --libs $(PKGS))
|
||||
INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I $(REPO)/src
|
||||
CXXFLAGS := -std=c++11 -Wall -Wextra $(INC_FLAGS) -g
|
||||
|
||||
|
||||
LIB = libnntpchan.a
|
||||
|
||||
all: $(EXE) $(TOOL)
|
||||
|
||||
$(EXE): $(OBJECTS)
|
||||
$(CXX) -o $(EXE) $(OBJECTS) $(CXXFLAGS) nntpd.cpp $(LD_FLAGS)
|
||||
$(LIB): $(OBJECTS)
|
||||
$(AR) -q $(LIB) $(OBJECTS)
|
||||
|
||||
$(TOOL): $(OBJECTS)
|
||||
$(CXX) -o $(TOOL) $(OBJECTS) $(CXXFLAGS) tool.cpp $(LD_FLAGS)
|
||||
$(EXE): $(LIB)
|
||||
$(CXX) -o $(EXE) $(CXXFLAGS) nntpd.cpp $(LIB) $(LD_FLAGS)
|
||||
|
||||
build-test: $(OBJECTS)
|
||||
$(CXX) -o test $(OBJECTS) $(CXXFLAGS) test.cpp $(LD_FLAGS)
|
||||
$(TOOL): $(LIB)
|
||||
$(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
|
||||
@ -37,4 +40,4 @@ test: build-test
|
||||
$(CXX) $(CXXFLAGS) -c -o $@
|
||||
|
||||
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 {
|
||||
|
||||
LineReader::LineReader(size_t limit) : m_close(false), lineLimit(limit) {}
|
||||
|
||||
void LineReader::OnData(const char * d, ssize_t l)
|
||||
{
|
||||
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;
|
||||
ssize_t begin = l;
|
||||
const char * data = current.c_str();
|
||||
while(l-- > 0) {
|
||||
char c = d[idx++];
|
||||
char c = data[idx++];
|
||||
if(c == '\n') {
|
||||
OnLine(d, idx-1);
|
||||
d += idx;
|
||||
} else if (c == '\r' && d[idx] == '\n') {
|
||||
OnLine(d, idx-1);
|
||||
d += idx + 1;
|
||||
OnLine(data, idx-1);
|
||||
data += idx;
|
||||
} else if (c == '\r' && data[idx] == '\n') {
|
||||
OnLine(data, 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)
|
||||
@ -25,20 +40,8 @@ namespace nntpchan {
|
||||
HandleLine(line);
|
||||
}
|
||||
|
||||
bool LineReader::HasNextLine()
|
||||
bool LineReader::ShouldClose()
|
||||
{
|
||||
return m_sendlines.size() > 0;
|
||||
}
|
||||
|
||||
std::string LineReader::GetNextLine()
|
||||
{
|
||||
std::string line = m_sendlines[0];
|
||||
m_sendlines.pop_front();
|
||||
return line;
|
||||
}
|
||||
|
||||
void LineReader::QueueLine(const std::string & line)
|
||||
{
|
||||
m_sendlines.push_back(line);
|
||||
return m_close;
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,33 @@
|
||||
#ifndef NNTPCHAN_LINE_HPP
|
||||
#define NNTPCHAN_LINE_HPP
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include "server.hpp"
|
||||
#include <stdint.h>
|
||||
namespace nntpchan
|
||||
{
|
||||
|
||||
/** @brief a buffered line reader */
|
||||
class LineReader
|
||||
class LineReader : public IConnHandler
|
||||
{
|
||||
public:
|
||||
|
||||
LineReader(size_t lineLimit);
|
||||
|
||||
/** @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? */
|
||||
bool HasNextLine();
|
||||
/** @brief get the next line to send to the client, does not check if it exists */
|
||||
std::string GetNextLine();
|
||||
/** implements IConnHandler */
|
||||
virtual bool ShouldClose();
|
||||
|
||||
protected:
|
||||
/** @brief handle a line from the client */
|
||||
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:
|
||||
void OnLine(const char * d, const size_t l);
|
||||
// lines to send
|
||||
std::deque<std::string> m_sendlines;
|
||||
std::string m_leftovers;
|
||||
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
|
||||
{
|
||||
HashedCredDB::HashedCredDB() : LineReader(1024) {}
|
||||
|
||||
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_access);
|
||||
@ -95,4 +97,3 @@ namespace nntpchan
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ namespace nntpchan
|
||||
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
||||
{
|
||||
public:
|
||||
HashedCredDB();
|
||||
bool CheckLogin(const std::string & user, const std::string & passwd);
|
||||
protected:
|
||||
void SetStream(std::istream * i);
|
||||
|
@ -8,6 +8,7 @@
|
||||
namespace nntpchan
|
||||
{
|
||||
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
||||
LineReader(1024),
|
||||
m_auth(nullptr),
|
||||
m_store(storage),
|
||||
m_authed(false),
|
||||
|
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