/[LeafOK_CVS]/lbbs/src/net_server.c
ViewVC logotype

Contents of /lbbs/src/net_server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.82 - (show annotations)
Fri Nov 14 08:45:25 2025 UTC (4 months ago) by sysadm
Branch: MAIN
Changes since 1.81: +66 -51 lines
Content type: text/x-csrc
Refact process_sockaddr_pool with hash_dict_pid_sockaddr and hash_dict_sockaddr_count

1 /* SPDX-License-Identifier: GPL-3.0-or-later */
2 /*
3 * net_server
4 * - network server with SSH support
5 *
6 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "bbs.h"
14 #include "bbs_main.h"
15 #include "bwf.h"
16 #include "common.h"
17 #include "database.h"
18 #include "file_loader.h"
19 #include "hash_dict.h"
20 #include "io.h"
21 #include "init.h"
22 #include "log.h"
23 #include "login.h"
24 #include "menu.h"
25 #include "net_server.h"
26 #include "section_list.h"
27 #include "section_list_loader.h"
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <pty.h>
31 #include <signal.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <utmp.h>
36 #include <arpa/inet.h>
37 #include <libssh/callbacks.h>
38 #include <libssh/libssh.h>
39 #include <libssh/server.h>
40 #include <netinet/in.h>
41 #include <sys/epoll.h>
42 #include <sys/socket.h>
43 #include <sys/syscall.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <systemd/sd-daemon.h>
47
48 enum _net_server_constant_t
49 {
50 WAIT_CHILD_PROCESS_EXIT_TIMEOUT = 5, // second
51 WAIT_CHILD_PROCESS_KILL_TIMEOUT = 1, // second
52
53 SSH_AUTH_MAX_DURATION = 60 * 1000, // milliseconds
54 };
55
56 static const char SFTP_SERVER_PATH[] = "/usr/lib/sftp-server";
57
58 /* A userdata struct for session. */
59 struct session_data_struct
60 {
61 int tries;
62 int error;
63 };
64
65 /* A userdata struct for channel. */
66 struct channel_data_struct
67 {
68 /* pid of the child process the channel will spawn. */
69 pid_t pid;
70 /* For PTY allocation */
71 socket_t pty_master;
72 socket_t pty_slave;
73 /* For communication with the child process. */
74 socket_t child_stdin;
75 socket_t child_stdout;
76 /* Only used for subsystem and exec requests. */
77 socket_t child_stderr;
78 /* Event which is used to poll the above descriptors. */
79 ssh_event event;
80 /* Terminal size struct. */
81 struct winsize *winsize;
82 };
83
84 static int auth_password(ssh_session session, const char *user,
85 const char *password, void *userdata)
86 {
87 struct session_data_struct *sdata = (struct session_data_struct *)userdata;
88 int ret;
89
90 if (strcmp(user, "guest") == 0)
91 {
92 ret = load_guest_info();
93 }
94 else
95 {
96 ret = check_user(user, password);
97 }
98
99 if (ret == 0)
100 {
101 return SSH_AUTH_SUCCESS;
102 }
103
104 if ((++(sdata->tries)) >= BBS_login_retry_times)
105 {
106 sdata->error = 1;
107 }
108
109 return SSH_AUTH_DENIED;
110 }
111
112 static int pty_request(ssh_session session, ssh_channel channel, const char *term,
113 int cols, int rows, int px, int py, void *userdata)
114 {
115 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
116 int rc;
117
118 (void)session;
119 (void)channel;
120 (void)term;
121
122 cdata->winsize->ws_row = (unsigned short int)rows;
123 cdata->winsize->ws_col = (unsigned short int)cols;
124 cdata->winsize->ws_xpixel = (unsigned short int)px;
125 cdata->winsize->ws_ypixel = (unsigned short int)py;
126
127 rc = openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL, cdata->winsize);
128 if (rc != 0)
129 {
130 log_error("Failed to open pty\n");
131 return SSH_ERROR;
132 }
133
134 return SSH_OK;
135 }
136
137 static int pty_resize(ssh_session session, ssh_channel channel, int cols, int rows,
138 int py, int px, void *userdata)
139 {
140 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
141
142 (void)session;
143 (void)channel;
144
145 cdata->winsize->ws_row = (unsigned short int)rows;
146 cdata->winsize->ws_col = (unsigned short int)cols;
147 cdata->winsize->ws_xpixel = (unsigned short int)px;
148 cdata->winsize->ws_ypixel = (unsigned short int)py;
149
150 if (cdata->pty_master != -1)
151 {
152 return ioctl(cdata->pty_master, TIOCSWINSZ, cdata->winsize);
153 }
154
155 return SSH_ERROR;
156 }
157
158 static int exec_pty(const char *mode, const char *command, struct channel_data_struct *cdata)
159 {
160 (void)cdata;
161
162 if (command != NULL)
163 {
164 log_error("Forbid exec /bin/sh %s %s)\n", mode, command);
165 }
166
167 return SSH_OK;
168 }
169
170 static int exec_nopty(const char *command, struct channel_data_struct *cdata)
171 {
172 (void)cdata;
173
174 if (command != NULL)
175 {
176 log_error("Forbid exec /bin/sh -c %s)\n", command);
177 }
178
179 return SSH_OK;
180 }
181
182 static int exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata)
183 {
184 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
185
186 (void)session;
187 (void)channel;
188
189 if (cdata->pid > 0)
190 {
191 return SSH_ERROR;
192 }
193
194 if (cdata->pty_master != -1 && cdata->pty_slave != -1)
195 {
196 return exec_pty("-c", command, cdata);
197 }
198 return exec_nopty(command, cdata);
199 }
200
201 static int shell_request(ssh_session session, ssh_channel channel, void *userdata)
202 {
203 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
204
205 (void)session;
206 (void)channel;
207
208 if (cdata->pid > 0)
209 {
210 return SSH_ERROR;
211 }
212
213 if (cdata->pty_master != -1 && cdata->pty_slave != -1)
214 {
215 return exec_pty("-l", NULL, cdata);
216 }
217 /* Client requested a shell without a pty, let's pretend we allow that */
218 return SSH_OK;
219 }
220
221 static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata)
222 {
223 (void)session;
224 (void)channel;
225
226 log_error("subsystem_request(subsystem=%s)\n", subsystem);
227
228 /* subsystem requests behave similarly to exec requests. */
229 if (strcmp(subsystem, "sftp") == 0)
230 {
231 return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
232 }
233 return SSH_ERROR;
234 }
235
236 static ssh_channel channel_open(ssh_session session, void *userdata)
237 {
238 (void)userdata;
239
240 if (SSH_channel != NULL)
241 {
242 return NULL;
243 }
244
245 SSH_channel = ssh_channel_new(session);
246
247 return SSH_channel;
248 }
249
250 static int fork_server(void)
251 {
252 ssh_event event;
253 long int ssh_timeout = 0;
254 int pid;
255 int i;
256 int ret;
257
258 /* Structure for storing the pty size. */
259 struct winsize wsize = {
260 .ws_row = 0,
261 .ws_col = 0,
262 .ws_xpixel = 0,
263 .ws_ypixel = 0};
264
265 /* Our struct holding information about the channel. */
266 struct channel_data_struct cdata = {
267 .pid = 0,
268 .pty_master = -1,
269 .pty_slave = -1,
270 .child_stdin = -1,
271 .child_stdout = -1,
272 .child_stderr = -1,
273 .event = NULL,
274 .winsize = &wsize};
275
276 struct session_data_struct cb_data = {
277 .tries = 0,
278 .error = 0,
279 };
280
281 struct ssh_channel_callbacks_struct channel_cb = {
282 .userdata = &cdata,
283 .channel_pty_request_function = pty_request,
284 .channel_pty_window_change_function = pty_resize,
285 .channel_shell_request_function = shell_request,
286 .channel_exec_request_function = exec_request,
287 .channel_subsystem_request_function = subsystem_request};
288
289 struct ssh_server_callbacks_struct server_cb = {
290 .userdata = &cb_data,
291 .auth_password_function = auth_password,
292 .channel_open_request_session_function = channel_open,
293 };
294
295 pid = fork();
296
297 if (pid > 0) // Parent process
298 {
299 SYS_child_process_count++;
300 log_common("Child process (%d) start\n", pid);
301 return pid;
302 }
303 else if (pid < 0) // Error
304 {
305 log_error("fork() error (%d)\n", errno);
306 return -1;
307 }
308
309 // Child process
310
311 if (close(socket_server[0]) == -1 || close(socket_server[1]) == -1)
312 {
313 log_error("Close server socket failed\n");
314 }
315
316 SSH_session = ssh_new();
317
318 if (SSH_v2)
319 {
320 if (ssh_bind_accept_fd(sshbind, SSH_session, socket_client) != SSH_OK)
321 {
322 log_error("ssh_bind_accept_fd() error: %s\n", ssh_get_error(SSH_session));
323 goto cleanup;
324 }
325
326 ssh_bind_free(sshbind);
327
328 ssh_timeout = 60; // second
329 if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
330 {
331 log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session));
332 goto cleanup;
333 }
334
335 ssh_set_auth_methods(SSH_session, SSH_AUTH_METHOD_PASSWORD);
336
337 ssh_callbacks_init(&server_cb);
338 ssh_callbacks_init(&channel_cb);
339
340 ssh_set_server_callbacks(SSH_session, &server_cb);
341
342 if (ssh_handle_key_exchange(SSH_session))
343 {
344 log_error("ssh_handle_key_exchange() error: %s\n", ssh_get_error(SSH_session));
345 goto cleanup;
346 }
347
348 event = ssh_event_new();
349 ssh_event_add_session(event, SSH_session);
350
351 for (i = 0; i < SSH_AUTH_MAX_DURATION && !SYS_server_exit && !cb_data.error && SSH_channel == NULL; i += 100)
352 {
353 ret = ssh_event_dopoll(event, 100); // 0.1 second
354 if (ret == SSH_ERROR)
355 {
356 #ifdef _DEBUG
357 log_error("ssh_event_dopoll() error: %s\n", ssh_get_error(SSH_session));
358 #endif
359 goto cleanup;
360 }
361 }
362
363 if (cb_data.error)
364 {
365 log_error("SSH auth error, tried %d times\n", cb_data.tries);
366 goto cleanup;
367 }
368
369 ssh_set_channel_callbacks(SSH_channel, &channel_cb);
370
371 do
372 {
373 ret = ssh_event_dopoll(event, 100); // 0.1 second
374 if (ret == SSH_ERROR)
375 {
376 ssh_channel_close(SSH_channel);
377 }
378
379 if (ret == SSH_AGAIN) // loop until SSH connection is fully established
380 {
381 /* Executed only once, once the child process starts. */
382 cdata.event = event;
383 break;
384 }
385 } while (ssh_channel_is_open(SSH_channel));
386
387 ssh_timeout = 0;
388 if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
389 {
390 log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session));
391 goto cleanup;
392 }
393 }
394
395 // Redirect Input
396 close(STDIN_FILENO);
397 if (dup2(socket_client, STDIN_FILENO) == -1)
398 {
399 log_error("Redirect stdin to client socket failed\n");
400 goto cleanup;
401 }
402
403 // Redirect Output
404 close(STDOUT_FILENO);
405 if (dup2(socket_client, STDOUT_FILENO) == -1)
406 {
407 log_error("Redirect stdout to client socket failed\n");
408 goto cleanup;
409 }
410
411 SYS_child_process_count = 0;
412
413 bbs_main();
414
415 cleanup:
416 // Child process exit
417 SYS_server_exit = 1;
418
419 if (SSH_v2)
420 {
421 close(cdata.pty_master);
422 close(cdata.child_stdin);
423 close(cdata.child_stdout);
424 close(cdata.child_stderr);
425
426 ssh_channel_free(SSH_channel);
427 ssh_disconnect(SSH_session);
428 }
429 else if (close(socket_client) == -1)
430 {
431 log_error("Close client socket failed\n");
432 }
433
434 ssh_free(SSH_session);
435 ssh_finalize();
436
437 // Close Input and Output for client
438 close(STDIN_FILENO);
439 close(STDOUT_FILENO);
440
441 log_common("Process exit normally\n");
442 log_end();
443
444 _exit(0);
445
446 return 0;
447 }
448
449 int net_server(const char *hostaddr, in_port_t port[])
450 {
451 HASH_DICT *hash_dict_pid_sockaddr = NULL;
452 HASH_DICT *hash_dict_sockaddr_count = NULL;
453
454 unsigned int addrlen;
455 int ret;
456 int flags[2];
457 struct sockaddr_in sin;
458 struct epoll_event ev, events[MAX_EVENTS];
459 int nfds, epollfd;
460 siginfo_t siginfo;
461 int notify_child_exit = 0;
462 time_t tm_notify_child_exit = time(NULL);
463 int sd_notify_stopping = 0;
464 MENU_SET bbs_menu_new;
465 MENU_SET top10_menu_new;
466 int i, j;
467 pid_t pid;
468 int ssh_log_level = SSH_LOG_NOLOG;
469
470 ssh_init();
471
472 sshbind = ssh_bind_new();
473
474 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, hostaddr) < 0 ||
475 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port) < 0 ||
476 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_KEYFILE) < 0 ||
477 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "ssh-rsa,rsa-sha2-512,rsa-sha2-256") < 0 ||
478 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0)
479 {
480 log_error("Error setting SSH bind options: %s\n", ssh_get_error(sshbind));
481 ssh_bind_free(sshbind);
482 return -1;
483 }
484
485 epollfd = epoll_create1(0);
486 if (epollfd < 0)
487 {
488 log_error("epoll_create1() error (%d)\n", errno);
489 return -1;
490 }
491
492 // Server socket
493 for (i = 0; i < 2; i++)
494 {
495 socket_server[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
496
497 if (socket_server[i] < 0)
498 {
499 log_error("Create socket_server error (%d)\n", errno);
500 return -1;
501 }
502
503 sin.sin_family = AF_INET;
504 sin.sin_addr.s_addr = (hostaddr[0] != '\0' ? inet_addr(hostaddr) : INADDR_ANY);
505 sin.sin_port = htons(port[i]);
506
507 // Reuse address and port
508 flags[i] = 1;
509 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEADDR, &flags[i], sizeof(flags[i])) < 0)
510 {
511 log_error("setsockopt SO_REUSEADDR error (%d)\n", errno);
512 }
513 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEPORT, &flags[i], sizeof(flags[i])) < 0)
514 {
515 log_error("setsockopt SO_REUSEPORT error (%d)\n", errno);
516 }
517
518 if (bind(socket_server[i], (struct sockaddr *)&sin, sizeof(sin)) < 0)
519 {
520 log_error("Bind address %s:%u error (%d)\n",
521 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), errno);
522 return -1;
523 }
524
525 if (listen(socket_server[i], 10) < 0)
526 {
527 log_error("Telnet socket listen error (%d)\n", errno);
528 return -1;
529 }
530
531 log_common("Listening at %s:%u\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
532
533 ev.events = EPOLLIN;
534 ev.data.fd = socket_server[i];
535 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, socket_server[i], &ev) == -1)
536 {
537 log_error("epoll_ctl(socket_server[%d]) error (%d)\n", i, errno);
538 if (close(epollfd) < 0)
539 {
540 log_error("close(epoll) error (%d)\n");
541 }
542 return -1;
543 }
544
545 flags[i] = fcntl(socket_server[i], F_GETFL, 0);
546 fcntl(socket_server[i], F_SETFL, flags[i] | O_NONBLOCK);
547 }
548
549 hash_dict_pid_sockaddr = hash_dict_create(MAX_CLIENT_LIMIT);
550 if (hash_dict_pid_sockaddr == NULL)
551 {
552 log_error("hash_dict_create(hash_dict_pid_sockaddr) error\n");
553 return -1;
554 }
555 hash_dict_sockaddr_count = hash_dict_create(MAX_CLIENT_LIMIT);
556 if (hash_dict_sockaddr_count == NULL)
557 {
558 log_error("hash_dict_create(hash_dict_sockaddr_count) error\n");
559 return -1;
560 }
561
562 // Startup complete
563 sd_notifyf(0, "READY=1\n"
564 "STATUS=Listening at %s:%d (Telnet) and %s:%d (SSH2)\n"
565 "MAINPID=%d",
566 hostaddr, port[0], hostaddr, port[1], getpid());
567
568 while (!SYS_server_exit || SYS_child_process_count > 0)
569 {
570 if (SYS_server_exit && !sd_notify_stopping)
571 {
572 sd_notify(0, "STOPPING=1");
573 sd_notify_stopping = 1;
574 }
575
576 while ((SYS_child_exit || SYS_server_exit) && SYS_child_process_count > 0)
577 {
578 SYS_child_exit = 0;
579
580 siginfo.si_pid = 0;
581 ret = waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG);
582 if (ret == 0 && siginfo.si_pid > 0)
583 {
584 SYS_child_exit = 1; // Retry waitid
585
586 SYS_child_process_count--;
587 log_common("Child process (%d) exited\n", siginfo.si_pid);
588
589 if (siginfo.si_pid != section_list_loader_pid)
590 {
591 j = 0;
592 ret = hash_dict_get(hash_dict_pid_sockaddr, (uint64_t)siginfo.si_pid, (int64_t *)&j);
593 if (ret < 0)
594 {
595 log_error("hash_dict_get(hash_dict_pid_sockaddr, %d) error\n", siginfo.si_pid);
596 }
597 else
598 {
599 sin.sin_addr.s_addr = (uint32_t)j;
600 j = 0;
601 ret = hash_dict_get(hash_dict_sockaddr_count, sin.sin_addr.s_addr, (int64_t *)&j);
602 if (ret < 0)
603 {
604 log_error("hash_dict_get(hash_dict_sockaddr_count, %d) error\n", sin.sin_addr.s_addr);
605 }
606 else if (ret == 0)
607 {
608 log_error("hash_dict_get(hash_dict_sockaddr_count, %d) not found\n", sin.sin_addr.s_addr);
609 j = 1;
610 }
611
612 j--;
613 ret = hash_dict_set(hash_dict_sockaddr_count, sin.sin_addr.s_addr, j);
614 if (ret < 0)
615 {
616 log_error("hash_dict_set(hash_dict_sockaddr_count, %d, %d) error\n", sin.sin_addr.s_addr, j);
617 }
618
619 ret = hash_dict_del(hash_dict_pid_sockaddr, (uint64_t)siginfo.si_pid);
620 if (ret < 0)
621 {
622 log_error("hash_dict_del(hash_dict_pid_sockaddr, %d) error\n", siginfo.si_pid);
623 }
624 }
625 }
626 }
627 else if (ret == 0)
628 {
629 break;
630 }
631 else if (ret < 0)
632 {
633 log_error("Error in waitid: %d\n", errno);
634 break;
635 }
636 }
637
638 if (SYS_server_exit && !SYS_child_exit && SYS_child_process_count > 0)
639 {
640 if (notify_child_exit == 0)
641 {
642 sd_notifyf(0, "STATUS=Notify %d child process to exit", SYS_child_process_count);
643 log_common("Notify %d child process to exit\n", SYS_child_process_count);
644
645 if (kill(-getpid(), SIGTERM) < 0)
646 {
647 log_error("Send SIGTERM signal failed (%d)\n", errno);
648 }
649
650 notify_child_exit = 1;
651 tm_notify_child_exit = time(NULL);
652 }
653 else if (notify_child_exit == 1 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_EXIT_TIMEOUT)
654 {
655 sd_notifyf(0, "STATUS=Kill %d child process", SYS_child_process_count);
656
657 if (kill(-getpid(), SIGKILL) < 0)
658 {
659 log_error("Send SIGKILL signal failed (%d)\n", errno);
660 }
661
662 notify_child_exit = 2;
663 tm_notify_child_exit = time(NULL);
664 }
665 else if (notify_child_exit == 2 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_KILL_TIMEOUT)
666 {
667 log_error("Main process prepare to exit without waiting for %d child process any longer\n", SYS_child_process_count);
668 SYS_child_process_count = 0;
669 }
670 }
671
672 if (SYS_conf_reload && !SYS_server_exit)
673 {
674 SYS_conf_reload = 0;
675 sd_notify(0, "RELOADING=1");
676
677 // Reload configuration
678 if (load_conf(CONF_BBSD) < 0)
679 {
680 log_error("Reload conf failed\n");
681 }
682
683 // Reload BWF config
684 if (bwf_load(CONF_BWF) < 0)
685 {
686 log_error("Reload BWF conf failed\n");
687 }
688
689 if (load_menu(&bbs_menu_new, CONF_MENU) < 0)
690 {
691 unload_menu(&bbs_menu_new);
692 log_error("Reload bbs menu failed\n");
693 }
694 else
695 {
696 unload_menu(&bbs_menu);
697 memcpy(&bbs_menu, &bbs_menu_new, sizeof(bbs_menu_new));
698 log_common("Reload bbs menu successfully\n");
699 }
700
701 if (load_menu(&top10_menu_new, CONF_TOP10_MENU) < 0)
702 {
703 unload_menu(&top10_menu_new);
704 log_error("Reload top10 menu failed\n");
705 }
706 else
707 {
708 unload_menu(&top10_menu);
709 top10_menu_new.allow_exit = 1;
710 memcpy(&top10_menu, &top10_menu_new, sizeof(top10_menu_new));
711 log_common("Reload top10 menu successfully\n");
712 }
713
714 for (int i = 0; i < data_files_load_startup_count; i++)
715 {
716 if (load_file(data_files_load_startup[i]) < 0)
717 {
718 log_error("load_file(%s) error\n", data_files_load_startup[i]);
719 }
720 }
721 log_common("Reload data files successfully\n");
722
723 // Load section config and gen_ex
724 if (load_section_config_from_db(1) < 0)
725 {
726 log_error("load_section_config_from_db(1) error\n");
727 }
728 else
729 {
730 log_common("Reload section config and gen_ex successfully\n");
731 }
732
733 sd_notify(0, "READY=1");
734 }
735
736 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
737
738 if (nfds < 0)
739 {
740 if (errno != EINTR)
741 {
742 log_error("epoll_wait() error (%d)\n", errno);
743 break;
744 }
745 continue;
746 }
747
748 // Stop accept new connection on exit
749 if (SYS_server_exit)
750 {
751 continue;
752 }
753
754 for (int i = 0; i < nfds; i++)
755 {
756 if (events[i].data.fd == socket_server[0] || events[i].data.fd == socket_server[1])
757 {
758 SSH_v2 = (events[i].data.fd == socket_server[1] ? 1 : 0);
759
760 while (!SYS_server_exit) // Accept all incoming connections until error
761 {
762 addrlen = sizeof(sin);
763 socket_client = accept(socket_server[SSH_v2], (struct sockaddr *)&sin, &addrlen);
764 if (socket_client < 0)
765 {
766 if (errno == EAGAIN || errno == EWOULDBLOCK)
767 {
768 break;
769 }
770 else if (errno == EINTR)
771 {
772 continue;
773 }
774 else
775 {
776 log_error("accept(socket_server) error (%d)\n", errno);
777 break;
778 }
779 }
780
781 strncpy(hostaddr_client, inet_ntoa(sin.sin_addr), sizeof(hostaddr_client) - 1);
782 hostaddr_client[sizeof(hostaddr_client) - 1] = '\0';
783
784 port_client = ntohs(sin.sin_port);
785
786 log_common("Accept %s connection from %s:%d\n", (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client);
787
788 if (SYS_child_process_count - 1 < BBS_max_client)
789 {
790 j = 0;
791 ret = hash_dict_get(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, (int64_t *)&j);
792 if (ret < 0)
793 {
794 log_error("hash_dict_get(hash_dict_sockaddr_count, %s) error\n", hostaddr_client);
795 }
796
797 if (j < BBS_max_client_per_ip)
798 {
799 if ((pid = fork_server()) < 0)
800 {
801 log_error("fork_server() error\n");
802 }
803 else if (pid > 0)
804 {
805 ret = hash_dict_set(hash_dict_pid_sockaddr, (uint64_t)pid, sin.sin_addr.s_addr);
806 if (ret < 0)
807 {
808 log_error("hash_dict_set(hash_dict_pid_sockaddr, %d, %s) error\n", pid, hostaddr_client);
809 }
810
811 ret = hash_dict_set(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, j + 1);
812 if (ret < 0)
813 {
814 log_error("hash_dict_set(hash_dict_sockaddr_count, %s, %d) error\n", hostaddr_client, j + 1);
815 }
816 }
817 }
818 else
819 {
820 log_error("Rejected client connection from %s over limit per IP (%d)\n", hostaddr_client, BBS_max_client_per_ip);
821 }
822 }
823 else
824 {
825 log_error("Rejected client connection over limit (%d)\n", SYS_child_process_count - 1);
826 }
827
828 if (close(socket_client) == -1)
829 {
830 log_error("close(socket_lient) error (%d)\n", errno);
831 }
832 }
833 }
834 }
835 }
836
837 if (close(epollfd) < 0)
838 {
839 log_error("close(epoll) error (%d)\n");
840 }
841
842 for (i = 0; i < 2; i++)
843 {
844 fcntl(socket_server[i], F_SETFL, flags[i]);
845
846 if (close(socket_server[i]) == -1)
847 {
848 log_error("Close server socket failed\n");
849 }
850 }
851
852 hash_dict_destroy(hash_dict_pid_sockaddr);
853 hash_dict_destroy(hash_dict_sockaddr_count);
854
855 ssh_bind_free(sshbind);
856 ssh_finalize();
857
858 return 0;
859 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1