/[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.74 - (show annotations)
Sat Oct 25 03:11:11 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.73: +186 -18 lines
Content type: text/x-csrc
Add implementation of PTY related interfaces to fix compatibility issue.

1 /***************************************************************************
2 net_server.c - description
3 -------------------
4 Copyright : (C) 2004-2025 by Leaflet
5 Email : leaflet@leafok.com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 3 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17 #include "bbs.h"
18 #include "bbs_main.h"
19 #include "common.h"
20 #include "database.h"
21 #include "file_loader.h"
22 #include "io.h"
23 #include "init.h"
24 #include "log.h"
25 #include "login.h"
26 #include "menu.h"
27 #include "net_server.h"
28 #include "section_list.h"
29 #include "section_list_loader.h"
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <pty.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <utmp.h>
38 #include <arpa/inet.h>
39 #include <libssh/callbacks.h>
40 #include <libssh/libssh.h>
41 #include <libssh/server.h>
42 #include <netinet/in.h>
43 #include <sys/epoll.h>
44 #include <sys/socket.h>
45 #include <sys/syscall.h>
46 #include <sys/types.h>
47 #include <sys/wait.h>
48 #include <systemd/sd-daemon.h>
49
50 #define WAIT_CHILD_PROCESS_EXIT_TIMEOUT 5 // second
51 #define WAIT_CHILD_PROCESS_KILL_TIMEOUT 1 // second
52
53 struct process_sockaddr_t
54 {
55 pid_t pid;
56 in_addr_t s_addr;
57 };
58 typedef struct process_sockaddr_t PROCESS_SOCKADDR;
59
60 static PROCESS_SOCKADDR process_sockaddr_pool[MAX_CLIENT_LIMIT];
61
62 #define SSH_AUTH_MAX_DURATION (60 * 1000) // milliseconds
63
64 #define 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_callbacks_init(&channel_cb);
337 ssh_callbacks_init(&server_cb);
338
339 ssh_set_server_callbacks(SSH_session, &server_cb);
340
341 ssh_timeout = 60; // second
342 if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
343 {
344 log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session));
345 goto cleanup;
346 }
347
348 if (ssh_handle_key_exchange(SSH_session))
349 {
350 log_error("ssh_handle_key_exchange() error: %s\n", ssh_get_error(SSH_session));
351 goto cleanup;
352 }
353 ssh_set_auth_methods(SSH_session, SSH_AUTH_METHOD_PASSWORD);
354
355 event = ssh_event_new();
356 ssh_event_add_session(event, SSH_session);
357
358 for (i = 0; i < SSH_AUTH_MAX_DURATION && !SYS_server_exit && !cb_data.error && SSH_channel == NULL; i += 100)
359 {
360 ret = ssh_event_dopoll(event, 100); // 0.1 second
361 if (ret == SSH_ERROR)
362 {
363 #ifdef _DEBUG
364 log_error("ssh_event_dopoll() error: %s\n", ssh_get_error(SSH_session));
365 #endif
366 goto cleanup;
367 }
368 }
369
370 if (cb_data.error)
371 {
372 log_error("SSH auth error, tried %d times\n", cb_data.tries);
373 goto cleanup;
374 }
375
376 ssh_set_channel_callbacks(SSH_channel, &channel_cb);
377
378 ssh_timeout = 0;
379 if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
380 {
381 log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session));
382 goto cleanup;
383 }
384 }
385
386 // Redirect Input
387 close(STDIN_FILENO);
388 if (dup2(socket_client, STDIN_FILENO) == -1)
389 {
390 log_error("Redirect stdin to client socket failed\n");
391 goto cleanup;
392 }
393
394 // Redirect Output
395 close(STDOUT_FILENO);
396 if (dup2(socket_client, STDOUT_FILENO) == -1)
397 {
398 log_error("Redirect stdout to client socket failed\n");
399 goto cleanup;
400 }
401
402 SYS_child_process_count = 0;
403
404 bbs_main();
405
406 cleanup:
407 // Child process exit
408 SYS_server_exit = 1;
409
410 if (SSH_v2)
411 {
412 close(cdata.pty_master);
413 close(cdata.child_stdin);
414 close(cdata.child_stdout);
415 close(cdata.child_stderr);
416
417 ssh_channel_free(SSH_channel);
418 ssh_disconnect(SSH_session);
419 }
420 else if (close(socket_client) == -1)
421 {
422 log_error("Close client socket failed\n");
423 }
424
425 ssh_free(SSH_session);
426 ssh_finalize();
427
428 // Close Input and Output for client
429 close(STDIN_FILENO);
430 close(STDOUT_FILENO);
431
432 log_common("Process exit normally\n");
433 log_end();
434
435 _exit(0);
436
437 return 0;
438 }
439
440 int net_server(const char *hostaddr, in_port_t port[])
441 {
442 unsigned int addrlen;
443 int ret;
444 int flags[2];
445 struct sockaddr_in sin;
446 struct epoll_event ev, events[MAX_EVENTS];
447 int nfds, epollfd;
448 siginfo_t siginfo;
449 int notify_child_exit = 0;
450 time_t tm_notify_child_exit = time(NULL);
451 int sd_notify_stopping = 0;
452 MENU_SET bbs_menu_new;
453 MENU_SET top10_menu_new;
454 int i, j;
455 pid_t pid;
456 int ssh_log_level = SSH_LOG_NOLOG;
457
458 ssh_init();
459
460 sshbind = ssh_bind_new();
461
462 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, hostaddr) < 0 ||
463 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port) < 0 ||
464 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_KEYFILE) < 0 ||
465 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "ssh-rsa,rsa-sha2-512,rsa-sha2-256") < 0 ||
466 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0)
467 {
468 log_error("Error setting SSH bind options: %s\n", ssh_get_error(sshbind));
469 ssh_bind_free(sshbind);
470 return -1;
471 }
472
473 epollfd = epoll_create1(0);
474 if (epollfd < 0)
475 {
476 log_error("epoll_create1() error (%d)\n", errno);
477 return -1;
478 }
479
480 // Server socket
481 for (i = 0; i < 2; i++)
482 {
483 socket_server[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
484
485 if (socket_server[i] < 0)
486 {
487 log_error("Create socket_server error (%d)\n", errno);
488 return -1;
489 }
490
491 sin.sin_family = AF_INET;
492 sin.sin_addr.s_addr = (hostaddr[0] != '\0' ? inet_addr(hostaddr) : INADDR_ANY);
493 sin.sin_port = htons(port[i]);
494
495 // Reuse address and port
496 flags[i] = 1;
497 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEADDR, &flags[i], sizeof(flags[i])) < 0)
498 {
499 log_error("setsockopt SO_REUSEADDR error (%d)\n", errno);
500 }
501 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEPORT, &flags[i], sizeof(flags[i])) < 0)
502 {
503 log_error("setsockopt SO_REUSEPORT error (%d)\n", errno);
504 }
505
506 if (bind(socket_server[i], (struct sockaddr *)&sin, sizeof(sin)) < 0)
507 {
508 log_error("Bind address %s:%u error (%d)\n",
509 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), errno);
510 return -1;
511 }
512
513 if (listen(socket_server[i], 10) < 0)
514 {
515 log_error("Telnet socket listen error (%d)\n", errno);
516 return -1;
517 }
518
519 log_common("Listening at %s:%u\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
520
521 ev.events = EPOLLIN;
522 ev.data.fd = socket_server[i];
523 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, socket_server[i], &ev) == -1)
524 {
525 log_error("epoll_ctl(socket_server[%d]) error (%d)\n", i, errno);
526 if (close(epollfd) < 0)
527 {
528 log_error("close(epoll) error (%d)\n");
529 }
530 return -1;
531 }
532
533 flags[i] = fcntl(socket_server[i], F_GETFL, 0);
534 fcntl(socket_server[i], F_SETFL, flags[i] | O_NONBLOCK);
535 }
536
537 // Startup complete
538 sd_notifyf(0, "READY=1\n"
539 "STATUS=Listening at %s:%d (Telnet) and %s:%d (SSH2)\n"
540 "MAINPID=%d",
541 hostaddr, port[0], hostaddr, port[1], getpid());
542
543 while (!SYS_server_exit || SYS_child_process_count > 0)
544 {
545 if (SYS_server_exit && !sd_notify_stopping)
546 {
547 sd_notify(0, "STOPPING=1");
548 sd_notify_stopping = 1;
549 }
550
551 while ((SYS_child_exit || SYS_server_exit) && SYS_child_process_count > 0)
552 {
553 SYS_child_exit = 0;
554
555 siginfo.si_pid = 0;
556 ret = waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG);
557 if (ret == 0 && siginfo.si_pid > 0)
558 {
559 SYS_child_exit = 1; // Retry waitid
560
561 SYS_child_process_count--;
562 log_common("Child process (%d) exited\n", siginfo.si_pid);
563
564 if (siginfo.si_pid != section_list_loader_pid)
565 {
566 i = 0;
567 for (; i < BBS_max_client; i++)
568 {
569 if (process_sockaddr_pool[i].pid == siginfo.si_pid)
570 {
571 process_sockaddr_pool[i].pid = 0;
572 break;
573 }
574 }
575 if (i >= BBS_max_client)
576 {
577 log_error("Child process (%d) not found in process sockaddr pool\n", siginfo.si_pid);
578 }
579 }
580 }
581 else if (ret == 0)
582 {
583 break;
584 }
585 else if (ret < 0)
586 {
587 log_error("Error in waitid: %d\n", errno);
588 break;
589 }
590 }
591
592 if (SYS_server_exit && !SYS_child_exit && SYS_child_process_count > 0)
593 {
594 if (notify_child_exit == 0)
595 {
596 sd_notifyf(0, "STATUS=Notify %d child process to exit", SYS_child_process_count);
597 log_common("Notify %d child process to exit\n", SYS_child_process_count);
598
599 if (kill(0, SIGTERM) < 0)
600 {
601 log_error("Send SIGTERM signal failed (%d)\n", errno);
602 }
603
604 notify_child_exit = 1;
605 tm_notify_child_exit = time(NULL);
606 }
607 else if (notify_child_exit == 1 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_EXIT_TIMEOUT)
608 {
609 sd_notifyf(0, "STATUS=Kill %d child process", SYS_child_process_count);
610
611 for (i = 0; i < BBS_max_client; i++)
612 {
613 if (process_sockaddr_pool[i].pid != 0)
614 {
615 log_error("Kill child process (pid=%d)\n", process_sockaddr_pool[i].pid);
616 if (kill(process_sockaddr_pool[i].pid, SIGKILL) < 0)
617 {
618 log_error("Send SIGKILL signal failed (%d)\n", errno);
619 }
620 }
621 }
622
623 notify_child_exit = 2;
624 tm_notify_child_exit = time(NULL);
625 }
626 else if (notify_child_exit == 2 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_KILL_TIMEOUT)
627 {
628 log_error("Main process prepare to exit without waiting for %d child process any longer\n", SYS_child_process_count);
629 SYS_child_process_count = 0;
630 }
631 }
632
633 if (SYS_conf_reload && !SYS_server_exit)
634 {
635 SYS_conf_reload = 0;
636 sd_notify(0, "RELOADING=1");
637
638 // Reload configuration
639 if (load_conf(CONF_BBSD) < 0)
640 {
641 log_error("Reload conf failed\n");
642 }
643
644 if (load_menu(&bbs_menu_new, CONF_MENU) < 0)
645 {
646 unload_menu(&bbs_menu_new);
647 log_error("Reload bbs menu failed\n");
648 }
649 else
650 {
651 unload_menu(&bbs_menu);
652 memcpy(&bbs_menu, &bbs_menu_new, sizeof(bbs_menu_new));
653 log_common("Reload bbs menu successfully\n");
654 }
655
656 if (load_menu(&top10_menu_new, CONF_TOP10_MENU) < 0)
657 {
658 unload_menu(&top10_menu_new);
659 log_error("Reload top10 menu failed\n");
660 }
661 else
662 {
663 unload_menu(&top10_menu);
664 top10_menu_new.allow_exit = 1;
665 memcpy(&top10_menu, &top10_menu_new, sizeof(top10_menu_new));
666 log_common("Reload top10 menu successfully\n");
667 }
668
669 for (int i = 0; i < data_files_load_startup_count; i++)
670 {
671 if (load_file(data_files_load_startup[i]) < 0)
672 {
673 log_error("load_file_mmap(%s) error\n", data_files_load_startup[i]);
674 }
675 }
676 log_common("Reload data files successfully\n");
677
678 // Load section config and gen_ex
679 if (load_section_config_from_db(1) < 0)
680 {
681 log_error("load_section_config_from_db(1) error\n");
682 }
683 else
684 {
685 log_common("Reload section config and gen_ex successfully\n");
686 }
687
688 sd_notify(0, "READY=1");
689 }
690
691 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
692
693 if (nfds < 0)
694 {
695 if (errno != EINTR)
696 {
697 log_error("epoll_wait() error (%d)\n", errno);
698 break;
699 }
700 continue;
701 }
702
703 // Stop accept new connection on exit
704 if (SYS_server_exit)
705 {
706 continue;
707 }
708
709 for (int i = 0; i < nfds; i++)
710 {
711 if (events[i].data.fd == socket_server[0] || events[i].data.fd == socket_server[1])
712 {
713 SSH_v2 = (events[i].data.fd == socket_server[1] ? 1 : 0);
714
715 while (!SYS_server_exit) // Accept all incoming connections until error
716 {
717 addrlen = sizeof(sin);
718 socket_client = accept(socket_server[SSH_v2], (struct sockaddr *)&sin, &addrlen);
719 if (socket_client < 0)
720 {
721 if (errno == EAGAIN || errno == EWOULDBLOCK)
722 {
723 break;
724 }
725 else if (errno == EINTR)
726 {
727 continue;
728 }
729 else
730 {
731 log_error("accept(socket_server) error (%d)\n", errno);
732 break;
733 }
734 }
735
736 strncpy(hostaddr_client, inet_ntoa(sin.sin_addr), sizeof(hostaddr_client) - 1);
737 hostaddr_client[sizeof(hostaddr_client) - 1] = '\0';
738
739 port_client = ntohs(sin.sin_port);
740
741 log_common("Accept %s connection from %s:%d\n", (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client);
742
743 if (SYS_child_process_count - 1 < BBS_max_client)
744 {
745 j = 0;
746 for (i = 0; i < BBS_max_client; i++)
747 {
748 if (process_sockaddr_pool[i].pid != 0 && process_sockaddr_pool[i].s_addr == sin.sin_addr.s_addr)
749 {
750 j++;
751 if (j >= BBS_max_client_per_ip)
752 {
753 log_common("Too many client connections (%d) from %s\n", j, hostaddr_client);
754 break;
755 }
756 }
757 }
758
759 if (j < BBS_max_client_per_ip)
760 {
761 if ((pid = fork_server()) < 0)
762 {
763 log_error("fork_server() error\n");
764 }
765 else if (pid > 0)
766 {
767 i = 0;
768 for (; i < BBS_max_client; i++)
769 {
770 if (process_sockaddr_pool[i].pid == 0)
771 {
772 break;
773 }
774 }
775
776 if (i >= BBS_max_client)
777 {
778 log_error("Process sockaddr pool depleted\n");
779 }
780 else
781 {
782 process_sockaddr_pool[i].pid = pid;
783 process_sockaddr_pool[i].s_addr = sin.sin_addr.s_addr;
784 }
785 }
786 }
787 }
788 else
789 {
790 log_error("Rejected client connection over limit (%d)\n", SYS_child_process_count - 1);
791 }
792
793 if (close(socket_client) == -1)
794 {
795 log_error("close(socket_lient) error (%d)\n", errno);
796 }
797 }
798 }
799 }
800 }
801
802 if (close(epollfd) < 0)
803 {
804 log_error("close(epoll) error (%d)\n");
805 }
806
807 for (i = 0; i < 2; i++)
808 {
809 fcntl(socket_server[i], F_SETFL, flags[i]);
810
811 if (close(socket_server[i]) == -1)
812 {
813 log_error("Close server socket failed\n");
814 }
815 }
816
817 ssh_bind_free(sshbind);
818 ssh_finalize();
819
820 return 0;
821 }

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