initial commit

main
pantonshire 2 months ago
commit 12f4496883

@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
struct client_conf {
uint16_t port;
};
int client(const struct client_conf *conf);

@ -0,0 +1,3 @@
#pragma once
#define DEFAULT_PORT 11333

@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
struct server_conf {
uint16_t port;
};
int server(const struct server_conf *conf);

@ -0,0 +1,26 @@
#pragma once
#include <stdbool.h>
#include <string.h>
#define SV_LIT(S) (S "LITERAL_CHECK", (str_view_t) { S, sizeof(S) - 1 })
#define SV_NULL ((str_view_t) { NULL, 0 })
typedef struct {
const char *ptr;
size_t len;
} str_view_t;
static inline str_view_t sv_from_parts(const char *ptr, size_t len) {
return (str_view_t) { ptr, len };
}
static inline str_view_t sv_from_cstr(const char *ptr, size_t maxlen) {
size_t len = strnlen(ptr, maxlen);
return sv_from_parts(ptr, len);
}
static inline str_view_t sv_from_cstr_unbounded(const char *ptr) {
size_t len = strlen(ptr);
return sv_from_parts(ptr, len);
}

@ -0,0 +1,14 @@
#pragma once
#include <stdio.h>
#define LOG_ERR(FMT_STR, ...) do { \
fprintf(stderr, FMT_STR "\n" __VA_OPT__(,) __VA_ARGS__); \
} while (0)
#define FAIL_WITH(RET, FMT_STR, ...) do { \
LOG_ERR(FMT_STR, __VA_ARGS__); \
return (RET); \
} while (0)
#define FAIL(FMT_STR, ...) FAIL_WITH(-1, FMT_STR, __VA_ARGS__)

@ -0,0 +1,24 @@
project(
'owdtest',
'c',
default_options : ['c_std=c17']
)
sources = [
'src/main.c',
'src/server.c',
'src/client.c',
]
includes = include_directories('include')
args = [
'-Wall'
]
executable(
meson.project_name(),
sources,
include_directories: includes,
c_args: args
)

@ -0,0 +1,5 @@
#include "client.h"
int client(const struct client_conf *conf) {
return 0;
}

@ -0,0 +1,31 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "server.h"
#include "client.h"
#include "defaults.h"
// #define DEFAULT_PORT 34802
int main(int argc, char **argv) {
union {
struct server_conf server;
struct client_conf client;
} conf;
if (argc < 2)
return 1;
if (!strcmp(argv[1], "server")) {
conf.server.port = DEFAULT_PORT;
return !!server(&conf.server);
}
if (!strcmp(argv[1], "client")) {
conf.client.port = DEFAULT_PORT;
return !!client(&conf.client);
}
return 1;
}

@ -0,0 +1,179 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include "server.h"
#include "util.h"
#include "protocol.h"
struct server_ctx {
int fd;
};
struct rx_info {
const void *name;
socklen_t namelen;
struct timeval tv;
uint8_t tv_set : 1;
};
static int server_init(const struct server_conf *conf, struct server_ctx *ctx) {
struct sockaddr_in server_addr = { 0 };
int sock_fd;
int sockopt_int_yes = 1;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(conf->port);
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
FAIL("failed to create socket: %s", strerror(errno));
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt_int_yes, sizeof(sockopt_int_yes)))
FAIL("failed to set SO_REUSEADDR: %s", strerror(errno));
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMP, &sockopt_int_yes, sizeof(sockopt_int_yes)))
FAIL("failed to set SO_TIMESTAMP: %s", strerror(errno));
if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)))
FAIL("failed to bind: %s", strerror(errno));
ctx->fd = sock_fd;
return 0;
}
static int send_to_client(
struct server_ctx *ctx,
const struct rx_info *rx,
void *msg,
size_t len)
{
ssize_t send_res;
do {
send_res = sendto(
ctx->fd, msg, len, 0, (const struct sockaddr *)rx->name, rx->namelen);
} while ((send_res < 0) && (errno == EINTR));
if (send_res < 0)
FAIL("failed to send message: %s", strerror(errno));
return 0;
}
static void send_error_msg(
struct server_ctx *ctx,
const struct rx_info *rx,
enum owd_error_code err)
{
struct owd_msg_err msg;
owd_hdr_populate(&msg.hdr, OWD_MSG_ERR, OWD_DATA_LEN(msg));
msg.err = (uint8_t)err;
if (send_to_client(ctx, rx, &msg, OWD_DATA_LEN(msg)))
LOG_ERR("failed to send error message");
}
static int handle_sync_request(struct server_ctx *ctx, const struct rx_info *rx) {
if (!rx->tv_set)
FAIL("no rx timestamp available");
return 0;
}
static int handle_msg(struct server_ctx *ctx, char *buf, ssize_t buf_len, struct msghdr *msg_hdr) {
struct cmsghdr *cmsg;
struct owdhdr *hdr;
struct timeval tv;
struct rx_info rx;
rx.tv_set = false;
rx.name = msg_hdr->msg_name;
rx.namelen = msg_hdr->msg_namelen;
for (cmsg = CMSG_FIRSTHDR(msg_hdr); cmsg; cmsg = CMSG_NXTHDR(msg_hdr, cmsg)) {
switch (cmsg->cmsg_type) {
case SCM_TIMESTAMP:
if (cmsg->cmsg_len >= (sizeof(struct cmsghdr) + sizeof(struct timeval))) {
memcpy(&rx.tv, CMSG_DATA(cmsg), sizeof(tv));
rx.tv_set = true;
}
break;
default:
break;
}
}
if (rx.tv_set) {
printf(" tv_sec=%lld tv_usec=%lld\n", (long long)rx.tv.tv_sec, (long long)rx.tv.tv_usec);
}
if (buf_len < sizeof(struct owdhdr)) {
send_error_msg(ctx, &rx, OWD_ERR_BAD_HEADER);
FAIL("invalid packet: too short");
}
hdr = (struct owdhdr *)buf;
switch (hdr->msg_type) {
case OWD_MSG_SYNC_REQUEST:
return handle_sync_request(ctx, &rx);
default:
send_error_msg(ctx, &rx, OWD_ERR_BAD_TYPE);
FAIL("invalid packet: bad type");
}
}
static int server_loop(struct server_ctx *ctx) {
struct msghdr msg_hdr;
ssize_t recv_res;
struct iovec iov[1];
char client_addr_buf[64] __attribute__((aligned));
char msg_buf[256] __attribute__((aligned));
char ctrl_buf[256] __attribute__((aligned));
for (;;) {
iov[0].iov_base = msg_buf;
iov[0].iov_len = sizeof(msg_buf);
memset(&msg_hdr, 0, sizeof(msg_hdr));
msg_hdr.msg_name = &client_addr_buf;
msg_hdr.msg_namelen = sizeof(client_addr_buf);
msg_hdr.msg_iov = iov;
msg_hdr.msg_iovlen = 1;
msg_hdr.msg_control = ctrl_buf;
msg_hdr.msg_controllen = sizeof(ctrl_buf);
printf("namelen_before=%zu\n", (size_t)msg_hdr.msg_namelen);
if ((recv_res = recvmsg(ctx->fd, &msg_hdr, 0)) < 0) {
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
continue;
LOG_ERR("recvmsg: %s", strerror(errno));
continue;
}
printf("namelen_after=%zu\n", (size_t)msg_hdr.msg_namelen);
handle_msg(ctx, msg_buf, recv_res, &msg_hdr);
}
}
int server(const struct server_conf *conf) {
struct server_ctx ctx;
if (server_init(conf, &ctx))
FAIL("failed to create server socket");
server_loop(&ctx);
return 0;
}
Loading…
Cancel
Save