/[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.30 - (show annotations)
Tue May 13 07:30:53 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.29: +15 -13 lines
Content type: text/x-csrc
Remove sigprocmask

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 #define _XOPEN_SOURCE 500
18 #define _POSIX_C_SOURCE 200809L
19 #define _GNU_SOURCE
20
21 #include "net_server.h"
22 #include "common.h"
23 #include "log.h"
24 #include "io.h"
25 #include "fork.h"
26 #include "menu.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/syscall.h>
34 #include <sys/socket.h>
35 #include <sys/wait.h>
36 #include <sys/epoll.h>
37 #include <arpa/inet.h>
38
39 int net_server(const char *hostaddr, in_port_t port)
40 {
41 unsigned int namelen;
42 int ret;
43 int flags;
44 struct sockaddr_in sin;
45 struct epoll_event ev, events[MAX_EVENTS];
46 int nfds, epollfd;
47 siginfo_t siginfo;
48
49 socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
50
51 if (socket_server < 0)
52 {
53 log_error("Create socket failed\n");
54 return -1;
55 }
56
57 sin.sin_family = AF_INET;
58 sin.sin_addr.s_addr = (hostaddr[0] != '\0' ? inet_addr(hostaddr) : INADDR_ANY);
59 sin.sin_port = htons(port);
60
61 // Reuse address and port
62 flags = 1;
63 if (setsockopt(socket_server, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)) < 0)
64 {
65 log_error("setsockopt SO_REUSEADDR error (%d)\n", errno);
66 }
67 if (setsockopt(socket_server, SOL_SOCKET, SO_REUSEPORT, &flags, sizeof(flags)) < 0)
68 {
69 log_error("setsockopt SO_REUSEPORT error (%d)\n", errno);
70 }
71
72 if (bind(socket_server, (struct sockaddr *)&sin, sizeof(sin)) < 0)
73 {
74 log_error("Bind address %s:%u failed (%d)\n",
75 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), errno);
76 return -1;
77 }
78
79 if (listen(socket_server, 10) < 0)
80 {
81 log_error("Socket listen failed (%d)\n", errno);
82 return -1;
83 }
84
85 strncpy(hostaddr_server, inet_ntoa(sin.sin_addr), sizeof(hostaddr_server) - 1);
86 hostaddr_server[sizeof(hostaddr_server) - 1] = '\0';
87
88 port_server = ntohs(sin.sin_port);
89 namelen = sizeof(sin);
90
91 log_std("Listening at %s:%d\n", hostaddr_server, port_server);
92
93 epollfd = epoll_create1(0);
94 if (epollfd < 0)
95 {
96 log_error("epoll_create1() error (%d)\n", errno);
97 return -1;
98 }
99
100 ev.events = EPOLLIN;
101 ev.data.fd = socket_server;
102 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, socket_server, &ev) == -1)
103 {
104 log_error("epoll_ctl(socket_server) error (%d)\n", errno);
105 if (close(epollfd) < 0)
106 {
107 log_error("close(epoll) error (%d)\n");
108 }
109 return -1;
110 }
111
112 flags = fcntl(socket_server, F_GETFL, 0);
113 fcntl(socket_server, F_SETFL, flags | O_NONBLOCK);
114
115 while (!SYS_server_exit || SYS_child_process_count > 0)
116 {
117 while ((SYS_child_exit || SYS_server_exit) && SYS_child_process_count > 0)
118 {
119 SYS_child_exit = 0;
120
121 siginfo.si_pid = 0;
122 ret = waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG);
123 if (ret == 0 && siginfo.si_pid > 0)
124 {
125 SYS_child_exit = 1; // Retry waitid
126
127 SYS_child_process_count--;
128 log_std("Child process (%d) exited\n", siginfo.si_pid);
129 }
130 else if (ret == 0)
131 {
132 break;
133 }
134 else if (ret < 0)
135 {
136 log_error("Error in waitid: %d\n", errno);
137 break;
138 }
139 }
140
141 if (SYS_server_exit && !SYS_child_exit && SYS_child_process_count > 0)
142 {
143 log_std("Notify %d child process to exit\n", SYS_child_process_count);
144 if (kill(0, SIGTERM) < 0)
145 {
146 log_error("Send SIGTERM signal failed (%d)\n", errno);
147 }
148 }
149
150 if (SYS_menu_reload && !SYS_server_exit)
151 {
152 SYS_menu_reload = 0;
153
154 if (reload_menu(&bbs_menu) < 0)
155 {
156 log_error("Reload menu failed\n");
157 }
158 else
159 {
160 log_std("Reload menu successfully\n");
161 }
162 }
163
164 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
165
166 if (nfds < 0)
167 {
168 if (errno != EINTR)
169 {
170 log_error("epoll_wait() error (%d)\n", errno);
171 break;
172 }
173 continue;
174 }
175
176 // Stop accept new connection on exit
177 if (SYS_server_exit)
178 {
179 continue;
180 }
181
182 for (int i = 0; i < nfds; i++)
183 {
184 if (events[i].data.fd == socket_server)
185 {
186 while (!SYS_server_exit) // Accept all incoming connections until error
187 {
188 socket_client = accept(socket_server, (struct sockaddr *)&sin, &namelen);
189 if (socket_client < 0)
190 {
191 if (errno == EAGAIN || errno == EWOULDBLOCK)
192 {
193 break;
194 }
195 else if (errno == EINTR)
196 {
197 continue;
198 }
199 else
200 {
201 log_error("accept(socket_server) error (%d)\n", errno);
202 break;
203 }
204 }
205
206 strncpy(hostaddr_client, inet_ntoa(sin.sin_addr), sizeof(hostaddr_client) - 1);
207 hostaddr_client[sizeof(hostaddr_client) - 1] = '\0';
208
209 port_client = ntohs(sin.sin_port);
210
211 log_std("Accept connection from %s:%d\n", hostaddr_client, port_client);
212
213 if (fork_server() < 0)
214 {
215 log_error("fork_server() error\n");
216 }
217
218 if (close(socket_client) == -1)
219 {
220 log_error("close(socket_lient) error (%d)\n", errno);
221 }
222 }
223 }
224 }
225 }
226
227 if (close(epollfd) < 0)
228 {
229 log_error("close(epoll) error (%d)\n");
230 }
231
232 fcntl(socket_server, F_SETFL, flags);
233
234 if (close(socket_server) == -1)
235 {
236 log_error("Close server socket failed\n");
237 }
238
239 return 0;
240 }

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