11/* kcptun-libev (c) 2019-2025 He Xian <hexian000@outlook.com>
22 * This code is licensed under MIT license (see LICENSE for details) */
33
4+ /**
5+ * @file main.c
6+ * @brief Main entry point for kcptun-libev
7+ */
8+
49/* internal */
510#include "conf.h"
611#include "crypto.h"
2429#include <stdlib.h>
2530#include <string.h>
2631
32+ /**
33+ * Global structure to hold parsed command line arguments
34+ */
2735static struct {
2836 const char * conf_path ;
2937 const char * user_name ;
@@ -34,14 +42,27 @@ static struct {
3442 bool daemonize : 1 ;
3543} args = { 0 };
3644
45+ /**
46+ * Global application state for signal watchers
47+ */
3748static struct {
3849 ev_signal w_sighup ;
3950 ev_signal w_sigint ;
4051 ev_signal w_sigterm ;
4152} app ;
4253
54+ /**
55+ * Signal handler callback for processing system signals
56+ * @param loop Event loop instance
57+ * @param watcher Signal watcher that triggered
58+ * @param revents Event flags
59+ */
4360void signal_cb (struct ev_loop * loop , ev_signal * watcher , const int revents );
4461
62+ /**
63+ * Print program usage information and available command line options
64+ * @param argv0 Program name from argv[0]
65+ */
4566static void print_usage (char * argv0 )
4667{
4768 (void )fprintf (
@@ -68,6 +89,15 @@ static void print_usage(char *argv0)
6889 (void )fflush (stderr );
6990}
7091
92+ /**
93+ * @brief Parse command line arguments and populate global args structure
94+ * @param argc Number of command line arguments
95+ * @param argv Array of command line argument strings
96+ *
97+ * Parses all supported command line options and stores the configuration
98+ * in the global args structure. Exits the program on invalid arguments
99+ * or when help is requested.
100+ */
71101static void parse_args (int argc , char * * argv )
72102{
73103#define OPT_REQUIRE_ARG (argc , argv , i ) \
@@ -132,41 +162,51 @@ static void parse_args(int argc, char **argv)
132162 }
133163
134164#undef OPT_REQUIRE_ARG
165+ /* Set initial log level based on verbosity argument */
135166 slog_setlevel (LOG_LEVEL_NOTICE + args .verbosity );
136167}
137168
138169int main (int argc , char * * argv )
139170{
171+ /* Initialize application and parse command line arguments */
140172 init (argc , argv );
141173 parse_args (argc , argv );
142174#if WITH_CRYPTO
175+ /* Handle PSK generation mode - generate key and exit */
143176 if (args .genpsk ) {
144177 genpsk (args .genpsk );
145178 return EXIT_SUCCESS ;
146179 }
147180#endif
181+ /* Validate that configuration file was specified */
148182 if (args .conf_path == NULL ) {
149183 LOGF ("config file must be specified" );
150184 print_usage (argv [0 ]);
151185 return EXIT_FAILURE ;
152186 }
187+ /* Load and parse configuration file */
153188 struct config * restrict conf = conf_read (args .conf_path );
154189 if (conf == NULL ) {
155190 LOGF_F ("failed to read config `%s'" , args .conf_path );
156191 return EXIT_FAILURE ;
157192 }
193+ /* Adjust log level based on config and command line verbosity */
158194 slog_setlevel (conf -> log_level + args .verbosity );
195+ /* Load required dynamic libraries */
159196 loadlibs ();
160197
198+ /* Initialize libev event loop */
161199 struct ev_loop * loop = ev_default_loop (0 );
162200 CHECK (loop != NULL );
163201
202+ /* Create and initialize server instance */
164203 struct server * restrict s = server_new (loop , conf );
165204 if (s == NULL ) {
166205 LOGE_F ("failed to init %s" , conf_modestr (conf ));
167206 conf_free (conf );
168207 return EXIT_FAILURE ;
169208 }
209+ /* Start the server (bind sockets, etc.) */
170210 bool ok = server_start (s );
171211 if (!ok ) {
172212 LOGE_F ("failed to start %s" , conf_modestr (conf ));
@@ -175,8 +215,10 @@ int main(int argc, char **argv)
175215 return EXIT_FAILURE ;
176216 }
177217
218+ /* Handle user identity and daemonization */
178219 {
179220 struct user_ident ident , * pident = NULL ;
221+ /* Use command line user or config file user */
180222 const char * user_name =
181223 args .user_name ? args .user_name : conf -> user ;
182224 if (user_name != NULL ) {
@@ -185,25 +227,31 @@ int main(int argc, char **argv)
185227 }
186228 pident = & ident ;
187229 }
230+ /* Either daemonize (with privilege drop) or just drop privileges */
188231 if (args .daemonize ) {
189232 daemonize (pident , true, false);
190233 } else if (pident != NULL ) {
191234 drop_privileges (pident );
192235 }
193236 }
194237
195- /* signal watchers */
238+ /* Set up signal watchers for graceful shutdown and config reload */
196239 {
240+ /* SIGHUP: reload configuration */
197241 ev_signal * restrict w_sighup = & app .w_sighup ;
198242 ev_signal_init (w_sighup , signal_cb , SIGHUP );
199243 ev_set_priority (w_sighup , EV_MAXPRI );
200244 w_sighup -> data = s ;
201245 ev_signal_start (loop , w_sighup );
246+
247+ /* SIGINT: graceful shutdown (Ctrl+C) */
202248 ev_signal * restrict w_sigint = & app .w_sigint ;
203249 ev_signal_init (w_sigint , signal_cb , SIGINT );
204250 ev_set_priority (w_sigint , EV_MAXPRI );
205251 w_sigint -> data = s ;
206252 ev_signal_start (loop , w_sigint );
253+
254+ /* SIGTERM: graceful shutdown (service stop) */
207255 ev_signal * restrict w_sigterm = & app .w_sigterm ;
208256 ev_signal_init (w_sigterm , signal_cb , SIGTERM );
209257 ev_set_priority (w_sigterm , EV_MAXPRI );
@@ -214,10 +262,11 @@ int main(int argc, char **argv)
214262#if WITH_SYSTEMD
215263 (void )sd_notify (0 , "READY=1" );
216264#endif
217- /* start event loop */
265+ /* Start the main event loop - this blocks until shutdown */
218266 LOGN_F ("%s start" , conf_modestr (conf ));
219267 ev_run (loop , 0 );
220268
269+ /* Cleanup sequence after event loop exits */
221270 server_stop (s );
222271 server_free (s );
223272 LOGN_F ("%s shutdown gracefully" , conf_modestr (conf ));
@@ -239,22 +288,26 @@ void signal_cb(struct ev_loop *loop, ev_signal *watcher, const int revents)
239288#if WITH_SYSTEMD
240289 (void )sd_notify (0 , "RELOADING=1" );
241290#endif
291+ /* Attempt to reload configuration file */
242292 struct config * conf = conf_read (args .conf_path );
243293 if (conf == NULL ) {
244294 LOGE_F ("failed to read config: %s" , args .conf_path );
245295 return ;
246296 }
297+ /* Validate that the new config is compatible (same mode) */
247298 if (s -> conf -> mode != conf -> mode ) {
248299 conf_modestr (conf );
249300 LOGE_F ("incompatible config: mode %s (0x%x) -> %s (0x%x)" ,
250301 conf_modestr (s -> conf ), s -> conf -> mode ,
251302 conf_modestr (conf ), conf -> mode );
252303 return ;
253304 }
305+ /* Apply the new configuration */
254306 slog_setlevel (conf -> log_level );
255307 conf_free ((struct config * )s -> conf );
256308 server_loadconf (s , conf );
257309 LOGN ("config successfully reloaded" );
310+ /* Re-resolve any hostnames in case DNS changed */
258311 (void )server_resolve (s );
259312#if WITH_SYSTEMD
260313 (void )sd_notify (0 , "READY=1" );
@@ -266,6 +319,7 @@ void signal_cb(struct ev_loop *loop, ev_signal *watcher, const int revents)
266319#if WITH_SYSTEMD
267320 (void )sd_notify (0 , "STOPPING=1" );
268321#endif
322+ /* Break out of the main event loop */
269323 ev_break (loop , EVBREAK_ALL );
270324 } break ;
271325 default :;
0 commit comments