128 lines
4.1 KiB
C
128 lines
4.1 KiB
C
#include <stdio.h>
|
|||
|
|
#include <time.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include "c_TcpServer.h"
|
||
|
|
#include "c_SocketStream.h"
|
||
|
|
#include "c_SockAddr.h"
|
||
|
|
#include "c_TcpPollReactor.h"
|
||
|
|
|
||
|
|
#if defined(_WIN32) || defined(_WIN64)
|
||
|
|
#pragma comment(lib, "ws2_32.lib")
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Reactor connection event callback.
|
||
|
|
* Fired automatically by c_TcpPollReactor whenever an inbound client connects.
|
||
|
|
*/
|
||
|
|
static bool OnPollTimeServerConnect(c_TcpServer_t* server, c_socket_t client_sock, const c_SockAddr_t* peer_addr, void* args) {
|
||
|
|
(void)args;
|
||
|
|
char ip_str[INET6_ADDRSTRLEN] = {0};
|
||
|
|
uint16_t port = c_SockAddr_GetPort(peer_addr);
|
||
|
|
|
||
|
|
if (c_SockAddr_ToString(peer_addr, ip_str, sizeof(ip_str)) == C_ERR_OK) {
|
||
|
|
printf("[POLL INFO] Accepted client connection from: %s:%d\n", ip_str, (int)port);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool OnDataRequest(c_TcpServer_t* server, c_socket_t s , void* args) {
|
||
|
|
(void)args;
|
||
|
|
char host[32]={0};
|
||
|
|
char port[9]={0};
|
||
|
|
|
||
|
|
c_SocketUtil_GetNameInfoForSocket(s, host, sizeof(host), port, sizeof(port));
|
||
|
|
printf("Request from %s:%s\n", host, port);
|
||
|
|
|
||
|
|
char buffer[1024] = {0};
|
||
|
|
int err = recv(s, buffer, sizeof(buffer), 0);
|
||
|
|
|
||
|
|
printf("body: %.*s\n", err, buffer);
|
||
|
|
/* 1. Wrap raw client socket inside polymorphic Output Stream pipeline */
|
||
|
|
time_t raw_time = time(NULL);
|
||
|
|
struct tm* time_info = localtime(&raw_time);
|
||
|
|
|
||
|
|
char time_buffer[64] = {0};
|
||
|
|
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S\n", time_info);
|
||
|
|
|
||
|
|
/* 3. Flush plaintext string down into the polymorphic socket driver channel */
|
||
|
|
c_size_t bytes_written = 0;
|
||
|
|
c_SocketUtil_Send(s, time_buffer, strlen(time_buffer), &bytes_written);
|
||
|
|
|
||
|
|
if (strncmp(buffer, "STOP", 4)==0) {
|
||
|
|
server->is_running = false;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
static void OnClose(c_TcpServer_t* server, c_socket_t s, void* args) {
|
||
|
|
(void)args;
|
||
|
|
char host[32]={0};
|
||
|
|
char port[9]={0};
|
||
|
|
|
||
|
|
c_SocketUtil_GetNameInfoForSocket(s, host, sizeof(host), port, sizeof(port));
|
||
|
|
printf("Client Closed from %s:%s\n", host, port);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void OnError(c_TcpServer_t* server, c_socket_t s, int err, void* args) {
|
||
|
|
(void)args;
|
||
|
|
char host[32]={0};
|
||
|
|
char port[9]={0};
|
||
|
|
|
||
|
|
c_SocketUtil_GetNameInfoForSocket(s, host, sizeof(host), port, sizeof(port));
|
||
|
|
printf("[ERROR] Server %s:%s ON %s\n", host, port, c_TcpServer_GetErrorString(err));
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(void) {
|
||
|
|
c_Socket_Init();
|
||
|
|
uint16_t server_port = 1313;
|
||
|
|
c_TcpServer_t server;
|
||
|
|
|
||
|
|
printf("[SERVER] Initializing Poll-driven Time Server on port %d...\n", server_port);
|
||
|
|
|
||
|
|
/* 1. Spin up master server listener instance with your explicit flags signature layout */
|
||
|
|
c_err_t err = c_TcpServer_Init(&server, AF_INET, server_port, 512, NULL);
|
||
|
|
if (err != C_SUCCESS) {
|
||
|
|
fprintf(stderr, "[ERROR] Failed to open master server listening socket\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_TcpServer_SetCallbacks(&server, OnPollTimeServerConnect, OnDataRequest, OnClose, OnError);
|
||
|
|
|
||
|
|
/* 2. Instantiate the Polymorphic POSIX poll Reactor multiplexer backend */
|
||
|
|
c_TcpReactor_t* poll_reactor = NULL;
|
||
|
|
err = c_TcpPollReactor_Create(&poll_reactor, &server.allocator);
|
||
|
|
if (err != C_SUCCESS) {
|
||
|
|
fprintf(stderr, "[ERROR] Failed to instantiate c_TcpPollReactor driver context\n");
|
||
|
|
c_TcpServer_Destroy(&server);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 3. Bind poll multiplexer backend to server execution dispatcher context */
|
||
|
|
err = c_TcpServer_SetReactor(&server, poll_reactor);
|
||
|
|
if (err != C_SUCCESS) {
|
||
|
|
fprintf(stderr, "[ERROR] Failed to wire reactor driver onto dispatcher context\n");
|
||
|
|
c_TcpServer_Destroy(&server);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
printf("[SERVER] Multiplexed Time Server is fully running via c_TcpPollReactor...\n");
|
||
|
|
|
||
|
|
/* 4. Non-recursive event loop dispatcher loop (Polled with 1000ms heartbeat intervals) */
|
||
|
|
while (server.is_running) {
|
||
|
|
c_TcpServer_Run(&server, 1000, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 5. Complete cleanup resource teardowns */
|
||
|
|
c_TcpServer_Destroy(&server);
|
||
|
|
printf("[SERVER] Time Server cleanly terminated.\n");
|
||
|
|
|
||
|
|
c_Socket_Destroy();
|
||
|
|
return 0;
|
||
|
|
}
|