/[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.80 - (show annotations)
Fri Nov 7 04:58:09 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.79: +7 -0 lines
Content type: text/x-csrc
Load / Reload BWF config file on startup / reload

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

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