/[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.81 - (show annotations)
Tue Nov 11 00:28:05 2025 UTC (4 months ago) by sysadm
Branch: MAIN
Changes since 1.80: +4 -0 lines
Content type: text/x-csrc
Use config.h

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

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