Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_network_mock.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
27#include "nilorea/n_str.h"
28#include "nilorea/n_log.h"
29#include "nilorea/n_network.h"
30#include "nilorea/n_common.h"
31
32#include <getopt.h>
33#include <string.h>
34#include <pthread.h>
35#include <unistd.h>
36
38#define MOCK_PORT 19090
39
41static N_MOCK_SERVER* g_server = NULL;
42
49static void on_request(N_HTTP_REQUEST* req, N_HTTP_RESPONSE* resp, void* user_data) {
50 (void)user_data;
51 n_log(LOG_INFO, "mock: %s %s", req->method, req->path);
52
53 if (strcmp(req->method, "GET") == 0 &&
54 strcmp(req->path, "/api/test") == 0) {
55 resp->status_code = 200;
56 strncpy(resp->content_type, "application/json",
57 sizeof(resp->content_type) - 1);
58 resp->body = char_to_nstr("{\"status\":\"ok\"}");
59 } else {
60 resp->status_code = 404;
61 strncpy(resp->content_type, "text/plain",
62 sizeof(resp->content_type) - 1);
63 resp->body = char_to_nstr("Not Found");
64 }
65}
66
72static void* server_thread(void* arg) {
73 (void)arg;
75 return NULL;
76}
77
78int main(int argc, char* argv[]) {
79 int log_level = LOG_ERR;
80 int getoptret = 0;
81
82 while ((getoptret = getopt(argc, argv, "V:h")) != -1) {
83 switch (getoptret) {
84 case 'V':
85 if (strcmp(optarg, "LOG_DEBUG") == 0)
87 else if (strcmp(optarg, "LOG_INFO") == 0)
89 else if (strcmp(optarg, "LOG_NOTICE") == 0)
91 else if (strcmp(optarg, "LOG_ERR") == 0)
93 break;
94 case 'h':
95 default:
96 fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
97 return 1;
98 }
99 }
101
102 /* Start mock server */
104 if (!g_server) {
105 fprintf(stderr, "FAIL: could not start mock server\n");
106 return 1;
107 }
108 printf("CHECK start server ... PASS\n");
109
110 /* Run server in a thread */
111 pthread_t thr;
112 if (pthread_create(&thr, NULL, server_thread, NULL) != 0) {
113 fprintf(stderr, "FAIL: could not create server thread\n");
115 return 1;
116 }
117
118 /* Give the server thread time to start accepting */
119 usleep(100000); /* 100ms */
120
121 /* Connect and send a GET /api/test request */
122 int sock_fd = -1;
123 {
124 struct addrinfo hints;
125 struct addrinfo* res = NULL;
126 memset(&hints, 0, sizeof(hints));
127 hints.ai_family = AF_INET;
128 hints.ai_socktype = SOCK_STREAM;
129 char port_str[16];
130 snprintf(port_str, sizeof(port_str), "%d", MOCK_PORT);
131 if (getaddrinfo("127.0.0.1", port_str, &hints, &res) != 0 || !res) {
132 fprintf(stderr, "FAIL: getaddrinfo\n");
134 pthread_join(thr, NULL);
136 return 1;
137 }
138 sock_fd = (int)socket(res->ai_family, res->ai_socktype,
139 res->ai_protocol);
140 if (sock_fd < 0 ||
141 connect(sock_fd, res->ai_addr, res->ai_addrlen) != 0) {
142 fprintf(stderr, "FAIL: connect\n");
143 freeaddrinfo(res);
145 pthread_join(thr, NULL);
147 return 1;
148 }
149 freeaddrinfo(res);
150 }
151
152 /* Send HTTP request */
153 const char* http_req =
154 "GET /api/test HTTP/1.1\r\n"
155 "Host: localhost\r\n"
156 "Connection: close\r\n"
157 "\r\n";
158 ssize_t sent = send(sock_fd, http_req, strlen(http_req), 0);
159 if (sent <= 0) {
160 fprintf(stderr, "FAIL: send\n");
161 close(sock_fd);
163 pthread_join(thr, NULL);
165 return 1;
166 }
167
168 /* Read response */
169 char resp_buf[4096];
170 memset(resp_buf, 0, sizeof(resp_buf));
171 ssize_t total = 0;
172 ssize_t nr = 0;
173 while ((nr = recv(sock_fd, resp_buf + total,
174 sizeof(resp_buf) - 1 - (size_t)total, 0)) > 0) {
175 total += nr;
176 }
177 close(sock_fd);
178
179 printf("Response:\n%s\n", resp_buf);
180
181 /* Verify response contains expected data */
182 int pass = 1;
183 if (strstr(resp_buf, "200") == NULL) {
184 fprintf(stderr, "FAIL: expected 200 in response\n");
185 pass = 0;
186 }
187 if (strstr(resp_buf, "{\"status\":\"ok\"}") == NULL) {
188 fprintf(stderr, "FAIL: expected JSON body in response\n");
189 pass = 0;
190 }
191 printf("CHECK GET /api/test ... %s\n", pass ? "PASS" : "FAIL");
192
193 /* Stop server and clean up */
195 pthread_join(thr, NULL);
197
198 printf("CHECK cleanup ... PASS\n");
199 return pass ? 0 : 1;
200}
int main(void)
int getoptret
Definition ex_fluid.c:60
int log_level
Definition ex_fluid.c:61
static char * port_str
static void * server_thread(void *arg)
Thread function that runs the server accept loop.
#define MOCK_PORT
mock server port
static void on_request(N_HTTP_REQUEST *req, N_HTTP_RESPONSE *resp, void *user_data)
Request handler: returns JSON for GET /api/test, 404 otherwise.
static N_MOCK_SERVER * g_server
global server pointer for thread
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_DEBUG
debug-level messages
Definition n_log.h:83
#define LOG_ERR
error conditions
Definition n_log.h:75
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:120
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:79
#define LOG_INFO
informational
Definition n_log.h:81
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:254
N_STR * body
response body
Definition n_network.h:757
char path[2048]
request path
Definition n_network.h:747
char method[16]
HTTP method.
Definition n_network.h:746
int status_code
HTTP status code.
Definition n_network.h:755
char content_type[128]
Content-Type header value.
Definition n_network.h:756
void n_mock_server_free(N_MOCK_SERVER **server)
Free a mock server and close the listening socket.
Definition n_network.c:5570
void n_mock_server_stop(N_MOCK_SERVER *server)
Signal the mock server to stop accepting connections.
Definition n_network.c:5561
void n_mock_server_run(N_MOCK_SERVER *server)
Run the mock server accept loop.
Definition n_network.c:5476
N_MOCK_SERVER * n_mock_server_start(int port, void(*on_request)(N_HTTP_REQUEST *, N_HTTP_RESPONSE *, void *), void *user_data)
Start a mock HTTP server: set up listener and return immediately.
Definition n_network.c:5442
parsed HTTP request for mock server callback
Definition n_network.h:745
HTTP response to send from mock server callback.
Definition n_network.h:754
mock HTTP server handle
Definition n_network.h:761
Common headers and low-level functions & define.
Generic log system.
Network Engine.
N_STR and string function declaration.