initial commit
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…
Reference in New Issue