/[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.78 - (show annotations)
Tue Nov 4 14:58:56 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.77: +1 -1 lines
Content type: text/x-csrc
Refine file header information comments

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 "common.h"
12 #include "database.h"
13 #include "file_loader.h"
14 #include "io.h"
15 #include "init.h"
16 #include "log.h"
17 #include "login.h"
18 #include "menu.h"
19 #include "net_server.h"
20 #include "section_list.h"
21 #include "section_list_loader.h"
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <pty.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <utmp.h>
30 #include <arpa/inet.h>
31 #include <libssh/callbacks.h>
32 #include <libssh/libssh.h>
33 #include <libssh/server.h>
34 #include <netinet/in.h>
35 #include <sys/epoll.h>
36 #include <sys/socket.h>
37 #include <sys/syscall.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #include <systemd/sd-daemon.h>
41
42 #define WAIT_CHILD_PROCESS_EXIT_TIMEOUT 5 // second
43 #define WAIT_CHILD_PROCESS_KILL_TIMEOUT 1 // second
44
45 struct process_sockaddr_t
46 {
47 pid_t pid;
48 in_addr_t s_addr;
49 };
50 typedef struct process_sockaddr_t PROCESS_SOCKADDR;
51
52 static PROCESS_SOCKADDR process_sockaddr_pool[MAX_CLIENT_LIMIT];
53
54 #define SSH_AUTH_MAX_DURATION (60 * 1000) // milliseconds
55
56 #define 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 unsigned int addrlen;
452 int ret;
453 int flags[2];
454 struct sockaddr_in sin;
455 struct epoll_event ev, events[MAX_EVENTS];
456 int nfds, epollfd;
457 siginfo_t siginfo;
458 int notify_child_exit = 0;
459 time_t tm_notify_child_exit = time(NULL);
460 int sd_notify_stopping = 0;
461 MENU_SET bbs_menu_new;
462 MENU_SET top10_menu_new;
463 int i, j;
464 pid_t pid;
465 int ssh_log_level = SSH_LOG_NOLOG;
466
467 ssh_init();
468
469 sshbind = ssh_bind_new();
470
471 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, hostaddr) < 0 ||
472 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port) < 0 ||
473 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_KEYFILE) < 0 ||
474 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "ssh-rsa,rsa-sha2-512,rsa-sha2-256") < 0 ||
475 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0)
476 {
477 log_error("Error setting SSH bind options: %s\n", ssh_get_error(sshbind));
478 ssh_bind_free(sshbind);
479 return -1;
480 }
481
482 epollfd = epoll_create1(0);
483 if (epollfd < 0)
484 {
485 log_error("epoll_create1() error (%d)\n", errno);
486 return -1;
487 }
488
489 // Server socket
490 for (i = 0; i < 2; i++)
491 {
492 socket_server[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
493
494 if (socket_server[i] < 0)
495 {
496 log_error("Create socket_server error (%d)\n", errno);
497 return -1;
498 }
499
500 sin.sin_family = AF_INET;
501 sin.sin_addr.s_addr = (hostaddr[0] != '\0' ? inet_addr(hostaddr) : INADDR_ANY);
502 sin.sin_port = htons(port[i]);
503
504 // Reuse address and port
505 flags[i] = 1;
506 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEADDR, &flags[i], sizeof(flags[i])) < 0)
507 {
508 log_error("setsockopt SO_REUSEADDR error (%d)\n", errno);
509 }
510 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEPORT, &flags[i], sizeof(flags[i])) < 0)
511 {
512 log_error("setsockopt SO_REUSEPORT error (%d)\n", errno);
513 }
514
515 if (bind(socket_server[i], (struct sockaddr *)&sin, sizeof(sin)) < 0)
516 {
517 log_error("Bind address %s:%u error (%d)\n",
518 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), errno);
519 return -1;
520 }
521
522 if (listen(socket_server[i], 10) < 0)
523 {
524 log_error("Telnet socket listen error (%d)\n", errno);
525 return -1;
526 }
527
528 log_common("Listening at %s:%u\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
529
530 ev.events = EPOLLIN;
531 ev.data.fd = socket_server[i];
532 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, socket_server[i], &ev) == -1)
533 {
534 log_error("epoll_ctl(socket_server[%d]) error (%d)\n", i, errno);
535 if (close(epollfd) < 0)
536 {
537 log_error("close(epoll) error (%d)\n");
538 }
539 return -1;
540 }
541
542 flags[i] = fcntl(socket_server[i], F_GETFL, 0);
543 fcntl(socket_server[i], F_SETFL, flags[i] | O_NONBLOCK);
544 }
545
546 // Startup complete
547 sd_notifyf(0, "READY=1\n"
548 "STATUS=Listening at %s:%d (Telnet) and %s:%d (SSH2)\n"
549 "MAINPID=%d",
550 hostaddr, port[0], hostaddr, port[1], getpid());
551
552 while (!SYS_server_exit || SYS_child_process_count > 0)
553 {
554 if (SYS_server_exit && !sd_notify_stopping)
555 {
556 sd_notify(0, "STOPPING=1");
557 sd_notify_stopping = 1;
558 }
559
560 while ((SYS_child_exit || SYS_server_exit) && SYS_child_process_count > 0)
561 {
562 SYS_child_exit = 0;
563
564 siginfo.si_pid = 0;
565 ret = waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG);
566 if (ret == 0 && siginfo.si_pid > 0)
567 {
568 SYS_child_exit = 1; // Retry waitid
569
570 SYS_child_process_count--;
571 log_common("Child process (%d) exited\n", siginfo.si_pid);
572
573 if (siginfo.si_pid != section_list_loader_pid)
574 {
575 i = 0;
576 for (; i < BBS_max_client; i++)
577 {
578 if (process_sockaddr_pool[i].pid == siginfo.si_pid)
579 {
580 process_sockaddr_pool[i].pid = 0;
581 break;
582 }
583 }
584 if (i >= BBS_max_client)
585 {
586 log_error("Child process (%d) not found in process sockaddr pool\n", siginfo.si_pid);
587 }
588 }
589 }
590 else if (ret == 0)
591 {
592 break;
593 }
594 else if (ret < 0)
595 {
596 log_error("Error in waitid: %d\n", errno);
597 break;
598 }
599 }
600
601 if (SYS_server_exit && !SYS_child_exit && SYS_child_process_count > 0)
602 {
603 if (notify_child_exit == 0)
604 {
605 sd_notifyf(0, "STATUS=Notify %d child process to exit", SYS_child_process_count);
606 log_common("Notify %d child process to exit\n", SYS_child_process_count);
607
608 if (kill(0, SIGTERM) < 0)
609 {
610 log_error("Send SIGTERM signal failed (%d)\n", errno);
611 }
612
613 notify_child_exit = 1;
614 tm_notify_child_exit = time(NULL);
615 }
616 else if (notify_child_exit == 1 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_EXIT_TIMEOUT)
617 {
618 sd_notifyf(0, "STATUS=Kill %d child process", SYS_child_process_count);
619
620 for (i = 0; i < BBS_max_client; i++)
621 {
622 if (process_sockaddr_pool[i].pid != 0)
623 {
624 log_error("Kill child process (pid=%d)\n", process_sockaddr_pool[i].pid);
625 if (kill(process_sockaddr_pool[i].pid, SIGKILL) < 0)
626 {
627 log_error("Send SIGKILL signal failed (%d)\n", errno);
628 }
629 }
630 }
631
632 notify_child_exit = 2;
633 tm_notify_child_exit = time(NULL);
634 }
635 else if (notify_child_exit == 2 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_KILL_TIMEOUT)
636 {
637 log_error("Main process prepare to exit without waiting for %d child process any longer\n", SYS_child_process_count);
638 SYS_child_process_count = 0;
639 }
640 }
641
642 if (SYS_conf_reload && !SYS_server_exit)
643 {
644 SYS_conf_reload = 0;
645 sd_notify(0, "RELOADING=1");
646
647 // Reload configuration
648 if (load_conf(CONF_BBSD) < 0)
649 {
650 log_error("Reload conf failed\n");
651 }
652
653 if (load_menu(&bbs_menu_new, CONF_MENU) < 0)
654 {
655 unload_menu(&bbs_menu_new);
656 log_error("Reload bbs menu failed\n");
657 }
658 else
659 {
660 unload_menu(&bbs_menu);
661 memcpy(&bbs_menu, &bbs_menu_new, sizeof(bbs_menu_new));
662 log_common("Reload bbs menu successfully\n");
663 }
664
665 if (load_menu(&top10_menu_new, CONF_TOP10_MENU) < 0)
666 {
667 unload_menu(&top10_menu_new);
668 log_error("Reload top10 menu failed\n");
669 }
670 else
671 {
672 unload_menu(&top10_menu);
673 top10_menu_new.allow_exit = 1;
674 memcpy(&top10_menu, &top10_menu_new, sizeof(top10_menu_new));
675 log_common("Reload top10 menu successfully\n");
676 }
677
678 for (int i = 0; i < data_files_load_startup_count; i++)
679 {
680 if (load_file(data_files_load_startup[i]) < 0)
681 {
682 log_error("load_file(%s) error\n", data_files_load_startup[i]);
683 }
684 }
685 log_common("Reload data files successfully\n");
686
687 // Load section config and gen_ex
688 if (load_section_config_from_db(1) < 0)
689 {
690 log_error("load_section_config_from_db(1) error\n");
691 }
692 else
693 {
694 log_common("Reload section config and gen_ex successfully\n");
695 }
696
697 sd_notify(0, "READY=1");
698 }
699
700 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
701
702 if (nfds < 0)
703 {
704 if (errno != EINTR)
705 {
706 log_error("epoll_wait() error (%d)\n", errno);
707 break;
708 }
709 continue;
710 }
711
712 // Stop accept new connection on exit
713 if (SYS_server_exit)
714 {
715 continue;
716 }
717
718 for (int i = 0; i < nfds; i++)
719 {
720 if (events[i].data.fd == socket_server[0] || events[i].data.fd == socket_server[1])
721 {
722 SSH_v2 = (events[i].data.fd == socket_server[1] ? 1 : 0);
723
724 while (!SYS_server_exit) // Accept all incoming connections until error
725 {
726 addrlen = sizeof(sin);
727 socket_client = accept(socket_server[SSH_v2], (struct sockaddr *)&sin, &addrlen);
728 if (socket_client < 0)
729 {
730 if (errno == EAGAIN || errno == EWOULDBLOCK)
731 {
732 break;
733 }
734 else if (errno == EINTR)
735 {
736 continue;
737 }
738 else
739 {
740 log_error("accept(socket_server) error (%d)\n", errno);
741 break;
742 }
743 }
744
745 strncpy(hostaddr_client, inet_ntoa(sin.sin_addr), sizeof(hostaddr_client) - 1);
746 hostaddr_client[sizeof(hostaddr_client) - 1] = '\0';
747
748 port_client = ntohs(sin.sin_port);
749
750 log_common("Accept %s connection from %s:%d\n", (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client);
751
752 if (SYS_child_process_count - 1 < BBS_max_client)
753 {
754 j = 0;
755 for (i = 0; i < BBS_max_client; i++)
756 {
757 if (process_sockaddr_pool[i].pid != 0 && process_sockaddr_pool[i].s_addr == sin.sin_addr.s_addr)
758 {
759 j++;
760 if (j >= BBS_max_client_per_ip)
761 {
762 log_common("Too many client connections (%d) from %s\n", j, hostaddr_client);
763 break;
764 }
765 }
766 }
767
768 if (j < BBS_max_client_per_ip)
769 {
770 if ((pid = fork_server()) < 0)
771 {
772 log_error("fork_server() error\n");
773 }
774 else if (pid > 0)
775 {
776 i = 0;
777 for (; i < BBS_max_client; i++)
778 {
779 if (process_sockaddr_pool[i].pid == 0)
780 {
781 break;
782 }
783 }
784
785 if (i >= BBS_max_client)
786 {
787 log_error("Process sockaddr pool depleted\n");
788 }
789 else
790 {
791 process_sockaddr_pool[i].pid = pid;
792 process_sockaddr_pool[i].s_addr = sin.sin_addr.s_addr;
793 }
794 }
795 }
796 }
797 else
798 {
799 log_error("Rejected client connection over limit (%d)\n", SYS_child_process_count - 1);
800 }
801
802 if (close(socket_client) == -1)
803 {
804 log_error("close(socket_lient) error (%d)\n", errno);
805 }
806 }
807 }
808 }
809 }
810
811 if (close(epollfd) < 0)
812 {
813 log_error("close(epoll) error (%d)\n");
814 }
815
816 for (i = 0; i < 2; i++)
817 {
818 fcntl(socket_server[i], F_SETFL, flags[i]);
819
820 if (close(socket_server[i]) == -1)
821 {
822 log_error("Close server socket failed\n");
823 }
824 }
825
826 ssh_bind_free(sshbind);
827 ssh_finalize();
828
829 return 0;
830 }

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