aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMr. Goblin <mrgoblin@mrgoblin.net>2026-09-27 22:51:34 +0300
committerMr. Goblin <mrgoblin@mrgoblin.net>2026-09-27 22:51:34 +0300
commit76eae6e283c42d1c4a5a0efb94f7d6366d40487b (patch)
treefb61705947e7c43212c27b8d87ea323fa201f6ea
parent753621c39b76bd90610ea758567525425f8e2913 (diff)
echo server
-rw-r--r--Makefile6
-rw-r--r--PROTOCOL3
-rw-r--r--btasktd.c114
-rw-r--r--codes.c22
-rw-r--r--codes.h18
5 files changed, 144 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 133e59c..f4ec5b6 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ MAINBINARIES = btasktd
.SUFFIXES:
.SUFFIXES: .c .o
-.PHONY: all clean dist ctags
+.PHONY: all clean dist ctags rebuild
all: $(MAINBINARIES)
@@ -38,11 +38,13 @@ dist:
clean:
rm -f $(MAINBINARIES) *.o *.test tags
+rebuild: clean all
+
.c.o:
$(CC) $(DEBUG) $(CFLAGS) -c $< -o $@
-BTASKTD_OBJECTS = btasktd.o cliflags.o
+BTASKTD_OBJECTS = btasktd.o cliflags.o codes.o
BTASKTD_LIBS = -lc
btasktd: $(BTASKTD_OBJECTS)
diff --git a/PROTOCOL b/PROTOCOL
index 9abf559..ea7dd4c 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -1,5 +1,5 @@
-------------------------------------------------------------------------
-ANSWER CODES
+RESPONSE CODES
-------------------------------------------------------------------------
200 OK
201 Created
@@ -8,4 +8,5 @@ ANSWER CODES
403 Forbidden
404 Not found
409 Conflict
+413 Too long request
503 Service unavailable
diff --git a/btasktd.c b/btasktd.c
index 6abb00c..75af779 100644
--- a/btasktd.c
+++ b/btasktd.c
@@ -59,10 +59,26 @@
# define BTASKTD_CLIENT_BUF_SIZE 4096
#endif
+#ifndef BTASKTD_MAX_RESPONSE_BUF_SIZE
+# define BTASKTD_MAX_RESPONSE_BUF_SIZE 8192
+#endif
+
+#ifndef BTASKTD_RESPONSE_BUF_SIZE
+# define BTASKTD_RESPONSE_BUF_SIZE \
+ ((BTASKTD_MAX_RESPONSE_BUF_SIZE) - 256)
+#endif
+
+
struct user {
int fd;
char buf[BTASKTD_CLIENT_BUF_SIZE];
- int bi;
+ int bi; /* buf index */
+};
+
+/* BODY SHOULD BE EMPTY OR END WITH CRLF (\r\n, 13 10) */
+struct response {
+ int code;
+ const char *body; /* for empty use NULL or "" */
};
struct btasktd {
@@ -96,10 +112,45 @@ find_free_user(const struct user *arr, int count)
}
static void
-send_client(int fd, const char *s)
+reset_user_buf(struct user *pu)
+{
+ pu->bi = 0;
+ memset(pu->buf, '\0', sizeof(pu->buf));
+}
+
+static void
+reset_user(struct user *pu)
+{
+ pu->fd = -1;
+ reset_user_buf(pu);
+}
+
+static void
+send_to_client(int fd, const char *s)
{
int len = strlen(s);
- send(fd, s, len, 0);
+ int code = send(fd, s, len, 0);
+ if (-1 == code)
+ perror("send");
+}
+
+static void
+send_response(int fd, struct response r)
+{
+ char buf[BTASKTD_MAX_RESPONSE_BUF_SIZE] = {0};
+ if (NULL == r.body)
+ r.body = "";
+ snprintf(buf, sizeof(buf), "%s%s.\r\n", code_to_str(r.code),
+ r.body);
+ send_to_client(fd, buf);
+}
+
+static void
+send_response_code(int fd, int code)
+{
+ struct response r = { CODE_200_OK, NULL };
+ r.code = code;
+ send_response(fd, r);
}
static void
@@ -116,7 +167,7 @@ handle_accept(struct btasktd *this)
set_nonblock(fd);
idx = find_free_user(this->users, this->users_cnt);
if (-1 == idx) {
- send_client(fd, CODE_503_STR);
+ send_response_code(fd, CODE_503_SERVICE_UNAVAILABLE);
close(fd);
}
this->users[idx].fd = fd;
@@ -128,17 +179,48 @@ handle_timeout(struct btasktd *this)
{
}
-static int
-buf_append(char *buf, int *bi, int bsize, const char *str)
+static void
+handle_buf(struct btasktd *this, int id, int should_send_response)
{
- int len = strlen(str);
- if (bi + len > bsize)
- return -1;
+ struct response resp;
+ struct user *pu = &(this->users[id]);
+ char buf[BTASKTD_RESPONSE_BUF_SIZE] = {0};
+ /* dummy yet */
+ resp.code = CODE_200_OK;
+ resp.body = "";
+ if (should_send_response) {
+ snprintf(buf, sizeof(buf), "%s", pu->buf);
+#if 1
+ send_to_client(pu->fd, buf);
+#else
+ resp.body = buf;
+ send_response(pu->fd, resp);
+#endif
+ }
+ reset_user_buf(pu);
}
static void
handle_user(struct btasktd *this, int id)
{
+ int valread;
+ struct user *pu = &(this->users[id]);
+ unsigned sz = sizeof(pu->buf) - (pu->bi) - 1;
+ valread = recv(pu->fd, pu->buf + pu->bi, sz, 0);
+ if (0 == valread) {
+ if (pu->bi > 0) {
+ handle_buf(this, id, 0);
+ }
+ close(pu->fd);
+ reset_user(pu);
+ return;
+ } else if (-1 == valread) {
+ perror("recv");
+ close(pu->fd);
+ reset_user(pu);
+ return;
+ }
+ handle_buf(this, id, 1);
}
int
@@ -232,26 +314,26 @@ main(int argc, char **argv)
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
- res = bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
+ res = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR,
+ &opt, sizeof(opt));
if (0 != res) {
close(server_fd);
free(users);
- perror("bind");
+ perror("setsockopt");
return 1;
}
- res = listen(server_fd, BTASKTD_QUEUE_LEN);
+ res = bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
if (0 != res) {
close(server_fd);
free(users);
- perror("listen");
+ perror("bind");
return 1;
}
- res = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR,
- &opt, sizeof(opt));
+ res = listen(server_fd, BTASKTD_QUEUE_LEN);
if (0 != res) {
close(server_fd);
free(users);
- perror("setsockopt");
+ perror("listen");
return 1;
}
diff --git a/codes.c b/codes.c
new file mode 100644
index 0000000..1ec22a2
--- /dev/null
+++ b/codes.c
@@ -0,0 +1,22 @@
+#include "codes.h"
+
+#define C(code) \
+ case (code): \
+ return CODE_##code##_STR;
+
+const char *
+code_to_str(int code)
+{
+ switch (code) {
+ C(200)
+ C(201)
+ C(400)
+ C(401)
+ C(403)
+ C(404)
+ C(409)
+ C(413)
+ C(503)
+ }
+ return "666 UNKNOWN CODE\r\n";
+}
diff --git a/codes.h b/codes.h
index e1e464d..8746e17 100644
--- a/codes.h
+++ b/codes.h
@@ -4,6 +4,23 @@
extern "C" {
#endif
+const char *
+code_to_str(int code);
+
+/* vim macro to transform str #define to code:
+0/\\r D0VU:s/ /€ü_/g /CODE€ü_ llllldf"€ý53xhp$phhi 0:s/DEFINE€ü_/define 0j
+*/
+
+#define CODE_200_OK 200
+#define CODE_201_CREATED 201
+#define CODE_400_BAD_REQUEST 400
+#define CODE_401_UNAUTHORIZED 401
+#define CODE_403_FORBIDDEN 403
+#define CODE_404_NOT_FOUND 404
+#define CODE_409_CONFLICT 409
+#define CODE_413_REQUEST_TOO_LONG 413
+#define CODE_503_SERVICE_UNAVAILABLE 503
+
#define CODE_200_STR "200 OK\r\n"
#define CODE_201_STR "201 Created\r\n"
#define CODE_400_STR "400 Bad request\r\n"
@@ -11,6 +28,7 @@ extern "C" {
#define CODE_403_STR "403 Forbidden\r\n"
#define CODE_404_STR "404 Not found\r\n"
#define CODE_409_STR "409 Conflict\r\n"
+#define CODE_413_STR "413 Too long request\r\n"
#define CODE_503_STR "503 Service unavailable\r\n"
#ifdef __cplusplus