Commit 02f96193 authored by Daniel Salzman's avatar Daniel Salzman

Adapt utils for new rrset

refs #2137
parent 723bc27a
ACLOCAL_AMFLAGS = -I ../m4
libexec_PROGRAMS = unittests unittests-xfr unittests-zscanner unittests-libknot
libexec_PROGRAMS = unittests unittests-xfr unittests-zscanner unittests-libknot kdig khost knsupdate
sbin_PROGRAMS = knotc knotd
dist_man_MANS = knot.conf.5 knotc.8 knotd.8
......@@ -24,6 +24,65 @@ CLEANFILES = \
knotc_SOURCES = \
knot/ctl/knotc_main.c
kdig_SOURCES = \
utils/common/msg.h \
utils/common/msg.c \
utils/common/exec.c \
utils/common/exec.h \
utils/common/params.c \
utils/common/params.h \
utils/common/resolv.c \
utils/common/resolv.h \
utils/common/netio.c \
utils/common/netio.h \
utils/common/token.c \
utils/common/token.h \
utils/dig/dig_main.c \
utils/dig/dig_params.c \
utils/dig/dig_params.h \
utils/dig/dig_exec.c \
utils/dig/dig_exec.h
khost_SOURCES = \
utils/common/msg.h \
utils/common/msg.c \
utils/common/exec.c \
utils/common/exec.h \
utils/common/params.c \
utils/common/params.h \
utils/common/resolv.c \
utils/common/resolv.h \
utils/common/netio.c \
utils/common/netio.h \
utils/common/token.c \
utils/common/token.h \
utils/host/host_main.c \
utils/dig/dig_params.c \
utils/dig/dig_params.h \
utils/host/host_params.c \
utils/host/host_params.h \
utils/dig/dig_exec.c \
utils/dig/dig_exec.h
knsupdate_SOURCES = \
utils/common/msg.h \
utils/common/msg.c \
utils/common/params.c \
utils/common/params.h \
utils/common/resolv.c \
utils/common/resolv.h \
utils/common/netio.c \
utils/common/netio.h \
utils/common/token.c \
utils/common/token.h \
utils/common/exec.c \
utils/common/exec.h \
utils/nsupdate/nsupdate_main.c \
utils/nsupdate/nsupdate_params.c \
utils/nsupdate/nsupdate_params.h \
utils/nsupdate/nsupdate_exec.c \
utils/nsupdate/nsupdate_exec.h
unittests_SOURCES = \
tests/common/acl_tests.c \
tests/common/acl_tests.h \
......@@ -181,6 +240,8 @@ libknots_la_SOURCES = \
common/fdset_kqueue.c \
common/fdset_epoll.h \
common/fdset_epoll.c \
common/getline_wrap.h \
common/getline_wrap.c \
common/log.c \
common/log.h \
common/hattrie/ahtable.c \
......@@ -257,6 +318,9 @@ libknots_la_LIBADD = libzscanner.la @LIBOBJS@
libzscanner_la_LIBADD = @LIBOBJS@
knotd_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
knotc_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
kdig_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
khost_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
knsupdate_LDADD = libknotd.la libknot.la libknots.la libzscanner.la @LIBOBJS@
unittests_LDADD = libknotd.la libknots.la @LIBOBJS@
unittests_libknot_LDADD = libknotd.la libknot.la @LIBOBJS@
unittests_xfr_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
......
......@@ -34,6 +34,8 @@
#include "zone/node.h"
#include "nsec3.h"
#include "util/wire.h"
#include "packet/packet.h"
#include "packet/query.h"
#include "packet/response.h"
#include "rrset.h"
#include "rrset-dump.h"
......
......@@ -19,15 +19,13 @@
#include <stdlib.h> // free
#include <time.h> // localtime_r
#include "libknot/libknot.h"
#include "common/lists.h" // list
#include "common/errcode.h" // KNOT_EOK
#include "libknot/consts.h" // KNOT_RCODE_NOERROR
#include "libknot/util/wire.h" // knot_wire_set_rd
#include "libknot/packet/query.h" // knot_query_init
#include "common/descriptor_new.h" // KNOT_RRTYPE_
#include "utils/common/msg.h" // WARN
#include "utils/common/params.h" // params_t
#include "utils/common/netio.h" // send_msg
#include "utils/common/rr-serialize.h" // rrset_write_mem
knot_lookup_table_t opcodes[] = {
{ KNOT_OPCODE_QUERY, "QUERY" },
......@@ -195,7 +193,7 @@ static void print_section_question(const knot_dname_t *owner,
knot_rrset_t *question = knot_rrset_new((knot_dname_t *)owner, qtype,
qclass, 0);
if (rrset_header_write_mem(buf, buflen, question, true, false) < 0) {
if (knot_rrset_txt_dump_header(question, buf, buflen) < 0) {
WARN("can't dump whole question section\n");
}
......@@ -212,7 +210,7 @@ static void print_section_verbose(const knot_rrset_t **rrsets,
char *buf = malloc(buflen);
for (uint16_t i = 0; i < count; i++) {
while (rrset_write_mem(buf, buflen, rrsets[i]) < 0) {
while (knot_rrset_txt_dump(rrsets[i], buf, buflen) < 0) {
buflen += 4096;
buf = realloc(buf, buflen);
......@@ -234,12 +232,11 @@ static void print_section_dig(const knot_rrset_t **rrsets,
size_t buflen = 8192;
char *buf = malloc(buflen);
for (uint16_t i = 0; i < count; i++) {
for (size_t i = 0; i < count; i++) {
const knot_rrset_t *rrset = rrsets[i];
knot_rdata_t *tmp = rrset->rdata;
do {
while (rdata_write_mem(buf, buflen, tmp, rrset->type)
for (size_t j = 0; j < rrset->rdata_count; j++) {
while (knot_rrset_txt_dump_data(rrset, j, buf, buflen)
< 0) {
buflen += 4096;
buf = realloc(buf, buflen);
......@@ -251,9 +248,7 @@ static void print_section_dig(const knot_rrset_t **rrsets,
}
}
printf("%s\n", buf);
tmp = tmp->next;
} while (tmp != rrset->rdata);
}
}
free(buf);
......@@ -267,7 +262,6 @@ static void print_section_host(const knot_rrset_t **rrsets,
for (uint16_t i = 0; i < count; i++) {
const knot_rrset_t *rrset = rrsets[i];
knot_rdata_t *tmp = rrset->rdata;
knot_lookup_table_t *descr;
char type[32] = "NULL";
char *owner;
......@@ -275,8 +269,8 @@ static void print_section_host(const knot_rrset_t **rrsets,
owner = knot_dname_to_str(rrset->owner);
descr = knot_lookup_by_id(rtypes, rrset->type);
do {
while (rdata_write_mem(buf, buflen, tmp, rrset->type)
for (size_t j = 0; j < rrset->rdata_count; j++) {
while (knot_rrset_txt_dump_data(rrset, j, buf, buflen)
< 0) {
buflen += 4096;
buf = realloc(buf, buflen);
......@@ -292,13 +286,11 @@ static void print_section_host(const knot_rrset_t **rrsets,
printf("%s %s %s\n", owner, descr->name, buf);
} else {
knot_rrtype_to_string(rrset->type, type,
sizeof(type));
sizeof(type));
printf("%s has %s record %s\n",
owner, type, buf);
}
tmp = tmp->next;
} while (tmp != rrset->rdata);
}
free(owner);
}
......@@ -327,7 +319,7 @@ static void print_error_host(const uint8_t code,
free(owner);
}
void print_header_xfr(const style_t *style, const knot_rr_type_t type)
void print_header_xfr(const style_t *style, const uint16_t type)
{
if (style == NULL) {
DBG_NULL;
......
......@@ -37,7 +37,7 @@ extern knot_lookup_table_t rtypes[];
knot_packet_t* create_empty_packet(knot_packet_prealloc_type_t t, int max_size);
void print_header_xfr(const style_t *style, const knot_rr_type_t type);
void print_header_xfr(const style_t *style, const uint16_t type);
void print_data_xfr(const style_t *style,
const knot_packet_t *packet);
......
......@@ -26,7 +26,7 @@
#include <unistd.h> // close
#include "utils/common/msg.h" // WARN
#include "libknot/util/descriptor.h" // KNOT_CLASS_IN
#include "common/descriptor_new.h" // KNOT_CLASS_IN
#include "common/errcode.h" // KNOT_E
server_t* server_create(const char *name, const char *service)
......
......@@ -27,10 +27,10 @@
#include <arpa/inet.h> // inet_pton
#include <sys/socket.h> // AF_INET (BSD)
#include "libknot/libknot.h"
#include "common/errcode.h" // KNOT_EOK
#include "common/mempattern.h" // strcdup
#include "libknot/dname.h" // knot_dname_t
#include "libknot/util/descriptor.h" // KNOT_RRTYPE
#include "common/descriptor_new.h" // KNOT_RRTYPE_
#include "utils/common/msg.h" // WARN
#include "utils/common/resolv.h" // parse_nameserver
#include "utils/common/token.h" // token
......
......@@ -28,6 +28,7 @@
#define _UTILS__PARAMS_H_
#include <stdint.h> // uint16_t
#include <stdbool.h> // bool
#include "common/lists.h" // list
#include "libknot/tsig.h" // knot_key_t
......
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdbool.h>
#include "utils/common/msg.h"
#include "utils/common/rr-serialize.h"
#include "knot/zone/zone-dump-text.h"
#include "libknot/libknot.h"
int rdata_write_mem(char* dst, size_t maxlen, const knot_rdata_t *rdata,
uint16_t type)
{
if (dst == NULL || rdata == NULL) {
DBG_NULL;
return KNOT_EINVAL;
}
int ret = 0;
int wb = 0;
knot_rrtype_descriptor_t *desc = NULL;
desc = knot_rrtype_descriptor_by_type(type);
char *item_str = NULL;
assert(rdata->count <= desc->length);
/* Workaround for IPSec gateway. */
if (type == KNOT_RRTYPE_IPSECKEY) {
ret = snprintf(dst+wb, maxlen-wb, "NOT YET IMPLEMENTED");
if (ret < 0 || ret >= maxlen-wb) return KNOT_ESPACE;
wb += ret;
return wb;
}
/*! \todo Implement for TSIG. */
if (type == KNOT_RRTYPE_TSIG) {
ret = snprintf(dst+wb, maxlen-wb, "TSIG NOT YET IMPLEMENTED");
if (ret < 0 || ret >= maxlen-wb) return KNOT_ESPACE;
wb += ret;
return wb;
}
for (int i = 0; i < rdata->count; i++) {
item_str = rdata_item_to_string(desc->zoneformat[i],
rdata->items[i]);
if (item_str == NULL) {
item_str = rdata_item_to_string(KNOT_RDATA_ZF_UNKNOWN,
rdata->items[i]);
}
if (item_str == NULL) {
return KNOT_ERROR;
}
if (i != rdata->count - 1) {
ret = snprintf(dst+wb, maxlen-wb, "%s ", item_str);
} else {
ret = snprintf(dst+wb, maxlen-wb, "%s", item_str);
}
free(item_str);
if (ret < 0 || ret >= maxlen-wb) return KNOT_ESPACE;
wb += ret;
}
return wb;
}
int rrset_header_write_mem(char *dst, size_t maxlen,
const knot_rrset_t *rrset,
const bool p_class, const bool p_ttl)
{
if (dst == NULL || rrset == NULL) {
DBG_NULL;
return KNOT_EINVAL;
}
char buf[32];
int ret = 0;
int wb = 0;
char *name = knot_dname_to_str(rrset->owner);
ret = snprintf(dst+wb, maxlen-wb, "%-20s\t", name);
free(name);
if (ret < 0 || ret >= maxlen-wb) return KNOT_ESPACE;
wb += ret;
if (p_ttl) {
ret = snprintf(dst+wb, maxlen-wb, "%6u\t", rrset->ttl);
} else {
ret = snprintf(dst+wb, maxlen-wb, " \t");
}
if (ret < 0 || ret >= maxlen-wb) return KNOT_ESPACE;
wb += ret;
if (p_class) {
if (knot_rrclass_to_string(rrset->rclass, buf, sizeof(buf)) < 0) {
return KNOT_ERROR;
}
ret = snprintf(dst+wb, maxlen-wb, "%-2s\t", buf);
} else {
ret = snprintf(dst+wb, maxlen-wb, " \t");
}
if (ret < 0 || ret >= maxlen-wb) return KNOT_ESPACE;
wb += ret;
if (knot_rrtype_to_string(rrset->type, buf, sizeof(buf)) < 0) {
return KNOT_ERROR;
}
ret = snprintf(dst+wb, maxlen-wb, "%-5s\t", buf);
if (ret < 0 || ret >= maxlen-wb) return KNOT_ESPACE;
wb += ret;
return wb;
}
static int rrsig_write_mem(char *dst, size_t maxlen, knot_rrset_t *rrsig)
{
int wb = 0;
int ret = rrset_header_write_mem(dst, maxlen, rrsig, true, true);
if (ret < 0) return KNOT_ESPACE;
wb += ret;
knot_rdata_t *tmp = rrsig->rdata;
while (tmp->next != rrsig->rdata) {
int ret = rdata_write_mem(dst+wb, maxlen-wb, tmp,
KNOT_RRTYPE_RRSIG);
if (ret < 0) return ret;
wb += ret;
ret = rrset_header_write_mem(dst+wb, maxlen-wb, rrsig, true, true);
tmp = tmp->next;
if (ret < 0) return ret;
wb += ret;
}
ret = rdata_write_mem(dst+wb, maxlen-wb, tmp, KNOT_RRTYPE_RRSIG);
if (ret < 0) return ret;
wb += ret;
return KNOT_EOK;
}
int rrset_write_mem(char *dst, size_t maxlen, const knot_rrset_t *rrset)
{
if (dst == NULL || rrset == NULL) {
DBG_NULL;
return KNOT_EINVAL;
}
int ret = 0;
int wb = 0;
knot_rdata_t *tmp = rrset->rdata;
do {
ret = rrset_header_write_mem(dst+wb, maxlen-wb, rrset, true, true);
if (ret < 0) return ret;
wb += ret;
ret = rdata_write_mem(dst+wb, maxlen-wb, tmp, rrset->type);
if (ret < 0) return ret;
wb += ret;
ret = snprintf(dst+wb, maxlen-wb, "\n");
if (ret < 0 || ret >= maxlen-wb) return ret;
wb += ret;
tmp = tmp->next;
} while (tmp != rrset->rdata);
knot_rrset_t *rrsig_set = rrset->rrsigs;
if (rrsig_set != NULL) {
ret = rrsig_write_mem(dst+wb, maxlen-wb, rrsig_set);
if (ret < 0) return ret;
wb += ret;
}
return wb;
}
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file rr-serialize.h
*
* \author Marek Vavrusa <marek.vavrusa@nic.cz>
*
* \brief Temporary RR serialization/deserialization functions.
*
* \note Valid until the new libknot API is finished.
*
* \addtogroup knot_utils
* @{
*/
#ifndef _UTILS__RR_SERIALIZE_H_
#define _UTILS__RR_SERIALIZE_H_
#include "libknot/libknot.h"
/*!
* \brief Serialize RRset to memory.
* \param dst Pointer to memory block.
* \param maxlen Remaining size of the memory block.
* \param rrset Serialized RRset.
*
* Function may write something to dst even if it fails somewhere during that,
* it is up to caller to clear it if neccessary.
*
* \retval number of written bytes on success
* \retval KNOT_ERROR
* \retval KNOT_ESPACE
*/
int rrset_write_mem(char *dst, size_t maxlen, const knot_rrset_t *rrset);
int rrset_header_write_mem(char *dst, size_t maxlen,
const knot_rrset_t *rrset,
const bool p_class, const bool p_ttl);
int rdata_write_mem(char* dst, size_t maxlen, const knot_rdata_t *rdata,
uint16_t type);
#endif // _UTILS__RR_SERIALIZE_H_
/*! @} */
......@@ -21,12 +21,10 @@
#include <sys/socket.h> // AF_INET
#include <netinet/in.h> // sockaddr_in (BSD)
#include "libknot/libknot.h"
#include "common/lists.h" // list
#include "common/errcode.h" // KNOT_EOK
#include "libknot/consts.h" // KNOT_RCODE_NOERROR
#include "libknot/util/wire.h" // knot_wire_set_rd
#include "libknot/packet/query.h" // knot_query_init
#include "libknot/packet/response.h" // knot_response_add_opt
#include "common/descriptor_new.h" // KNOT_RRTYPE_
#include "utils/common/msg.h" // WARN
#include "utils/common/netio.h" // get_socktype
#include "utils/common/exec.h" // print_packet
......@@ -102,51 +100,38 @@ static knot_packet_t* create_query_packet(const query_t *query,
// For IXFR query add authority section.
if (query->type_num == KNOT_RRTYPE_IXFR) {
int ret;
size_t pos = 0;
// SOA rdata in wireformat.
uint8_t wire[22] = { 0x0 };
// Set SOA serial.
uint32_t serial = htonl(query->xfr_serial);
memcpy(wire + 2, &serial, sizeof(serial));
// Create SOA rdata.
knot_rdata_t *soa_data = knot_rdata_new();
ret = knot_rdata_from_wire(soa_data,
wire,
&pos,
sizeof(wire),
sizeof(wire),
knot_rrtype_descriptor_by_type(
KNOT_RRTYPE_SOA));
if (ret != KNOT_EOK) {
free(soa_data);
knot_dname_release(q.qname);
knot_packet_free(&packet);
return NULL;
}
size_t pos = 0;
int ret;
// Create rrset with SOA record.
knot_rrset_t *soa = knot_rrset_new(q.qname,
KNOT_RRTYPE_SOA,
query->class_num,
0);
ret = knot_rrset_add_rdata(soa, soa_data);
if (soa == NULL) {
knot_dname_release(q.qname);
knot_packet_free(&packet);
return NULL;
}
// Fill in blank SOA rdata to rrset.
ret = knot_rrset_rdata_from_wire_one(soa, wire, &pos,
sizeof(wire), sizeof(wire));
if (ret != KNOT_EOK) {
free(soa_data);
free(soa);
knot_dname_release(q.qname);
knot_packet_free(&packet);
return NULL;
}
// Set SOA serial.
knot_rrset_rdata_soa_serial_set(soa, query->xfr_serial);
// Add authority section.
ret = knot_query_add_rrset_authority(packet, soa);
if (ret != KNOT_EOK) {
free(soa_data);
free(soa);
knot_dname_release(q.qname);
knot_packet_free(&packet);
......@@ -248,7 +233,7 @@ static int64_t first_serial_check(const knot_packet_t *reply)
if (first->type != KNOT_RRTYPE_SOA) {
return -1;
} else {
return knot_rdata_soa_serial(first->rdata);
return knot_rrset_rdata_soa_serial(first);
}
}
......@@ -263,7 +248,7 @@ static bool last_serial_check(const uint32_t serial, const knot_packet_t *reply)
if (last->type != KNOT_RRTYPE_SOA) {
return false;
} else {
int64_t last_serial = knot_rdata_soa_serial(last->rdata);
int64_t last_serial = knot_rrset_rdata_soa_serial(last);
if (last_serial == serial) {
return true;
......
......@@ -23,7 +23,7 @@
#include "common/lists.h" // list
#include "common/errcode.h" // KNOT_EOK
#include "libknot/util/descriptor.h" // KNOT_CLASS_IN
#include "common/descriptor_new.h" // KNOT_CLASS_IN
#include "utils/common/msg.h" // WARN
#include "utils/common/params.h" // parse_class
#include "utils/common/resolv.h" // get_nameservers
......
......@@ -23,7 +23,7 @@
#include "common/lists.h" // list
#include "common/errcode.h" // KNOT_EOK
#include "libknot/util/descriptor.h" // KNOT_CLASS_IN
#include "common/descriptor_new.h" // KNOT_CLASS_IN
#include "utils/common/msg.h" // WARN
#include "utils/dig/dig_params.h" // dig_params_t
#include "utils/common/resolv.h" // get_nameservers
......
......@@ -30,13 +30,8 @@
#include "utils/common/token.h"
#include "common/errcode.h"
#include "common/mempattern.h"
#include "libknot/dname.h"
#include "libknot/util/descriptor.h"
#include "libknot/packet/response.h"
#include "libknot/util/debug.h"
#include "libknot/consts.h"
#include "libknot/packet/query.h"
#include "libknot/tsig-op.h"
#include "common/descriptor_new.h"
#include "libknot/libknot.h"
/* Declarations of cmd parse functions. */
typedef int (*cmd_handle_f)(const char *lp, nsupdate_params_t *params);
......@@ -320,43 +315,29 @@ static int pkt_append(nsupdate_params_t *p, int sect)
tsig_wire_maxsize(&p->key));
}
}
/* Create RDATA (not for NXRRSET prereq). */
knot_rdata_t *rd = knot_rdata_new();
const knot_rrtype_descriptor_t *rdesc = NULL;
rdesc = knot_rrtype_descriptor_by_type(s->r_type);
if (s->r_data_length > 0 && sect != PQ_NXRRSET) {
size_t pos = 0;
ret = knot_rdata_from_wire(rd, s->r_data, &pos,
s->r_data_length, s->r_data_length,
rdesc);
if (ret != KNOT_EOK) {
DBG("%s: failed to created rd from wire - %s\n",
__func__, knot_strerror(ret));
knot_rdata_free(&rd);
return ret;
}
}
/* Form a rrset. */
knot_dname_t *o = knot_dname_new_from_wire(s->r_owner, s->r_owner_length, NULL);
knot_rrset_t *rr = knot_rrset_new(o, s->r_type, s->r_class, s->r_ttl);
if (!rr) {
DBG("%s: failed to create rrset - %s\n",
__func__, knot_strerror(ret));
knot_rdata_free(&rd);
return KNOT_ENOMEM;
}
knot_dname_release(o);
/* Append rdata. */
ret = knot_rrset_add_rdata(rr, rd);
if (ret != KNOT_EOK) {
DBG("%s: failed to add rdata - %s\n",
__func__, knot_strerror(ret));
knot_rdata_free(&rd);
knot_rrset_free(&rr);
return ret;
/* Create RDATA (not for NXRRSET prereq). */
if (s->r_data_length > 0 && sect != PQ_NXRRSET) {
size_t pos = 0;
ret = knot_rrset_rdata_from_wire_one(rr, s->r_data, &pos,
s->r_data_length,
s->r_data_length);
if (ret != KNOT_EOK) {
DBG("%s: failed to set rrset from wire - %s\n",
__func__, knot_strerror(ret));
knot_rrset_free(&rr);
return ret;
}
}
/* Add to correct section.
......
......@@ -24,8 +24,8 @@
#include "utils/common/msg.h"
#include "utils/common/netio.h"
#include "common/errcode.h"
#include "libknot/packet/packet.h"
#include "libknot/util/descriptor.h"
#include "common/descriptor_new.h"
#include "libknot/libknot.h"
#define DEFAULT_RETRIES_NSUPDATE 3
#define DEFAULT_TIMEOUT_NSUPDATE 1
......
......@@ -29,8 +29,8 @@
#include <stdint.h>
#include "libknot/libknot.h"
#include "common/lists.h" // list
#include "libknot/packet/packet.h" // knot_packet_t
#include "zscanner/scanner.h" // scanner_t
#include "utils/common/netio.h" // server_t
#include "utils/common/params.h" // protocol_t
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment