source: Main/trunk/Server/server.c@ 13

Last change on this file since 13 was 13, checked in by Nishi, on Sep 13, 2024 at 10:38:57 PM

better

  • Property svn:keywords set to Id
File size: 4.0 KB
Line 
1/* $Id: server.c 13 2024-09-13 13:38:57Z nishi $ */
2
3#include "tw_server.h"
4
5#include "tw_ssl.h"
6#include "tw_config.h"
7
8#include <unistd.h>
9#include <string.h>
10#include <stdbool.h>
11
12#include <cm_log.h>
13
14#ifdef __MINGW32__
15#include <winsock2.h>
16#include <process.h>
17#define NO_IPV6
18#else
19#include <sys/select.h>
20#include <sys/socket.h>
21#include <arpa/inet.h>
22#include <netinet/in.h>
23#include <netinet/tcp.h>
24#endif
25
26extern struct tw_config config;
27
28fd_set fdset;
29int sockcount = 0;
30
31#ifdef NO_IPV6
32#define SOCKADDR struct sockaddr_in
33#else
34#define SOCKADDR struct sockaddr_in6
35#endif
36SOCKADDR addresses[MAX_PORTS];
37int sockets[MAX_PORTS];
38
39void close_socket(int sock) {
40#ifdef __MINGW32__
41 closesocket(sock);
42#else
43 close(sock);
44#endif
45}
46
47int tw_server_init(void) {
48 int i;
49#ifdef __MINGW32__
50 WSADATA wsa;
51 WSAStartup(MAKEWORD(2, 0), &wsa);
52#endif
53 for(i = 0; config.ports[i] != -1; i++)
54 ;
55 sockcount = i;
56 for(i = 0; config.ports[i] != -1; i++) {
57#ifdef NO_IPV6
58 int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
59#else
60 int sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
61#endif
62#ifdef __MINGW32__
63 if(sock == INVALID_SOCKET)
64#else
65 if(sock < 0)
66#endif
67 {
68 cm_log("Server", "Socket creation failure");
69 return 1;
70 }
71 int yes = 1;
72 if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0) {
73 close_socket(sock);
74 cm_log("Server", "setsockopt failure (reuseaddr)");
75 return 1;
76 }
77 if(setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(yes)) < 0) {
78 close_socket(sock);
79 cm_log("Server", "setsockopt failure (nodelay)");
80 return 1;
81 }
82#ifndef NO_IPV6
83 int no = 0;
84 if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&no, sizeof(no)) < 0) {
85 close_socket(sock);
86 cm_log("Server", "setsockopt failure (IPv6)");
87 return 1;
88 }
89#endif
90 memset(&addresses[i], 0, sizeof(addresses[i]));
91#ifdef NO_IPV6
92 addresses[i].sin_family = AF_INET;
93 addresses[i].sin_addr.s_addr = INADDR_ANY;
94 addresses[i].sin_port = htons(config.ports[i]);
95#else
96 addresses[i].sin6_family = AF_INET6;
97 addresses[i].sin6_addr = in6addr_any;
98 addresses[i].sin6_port = htons(config.ports[i]);
99#endif
100 if(bind(sock, (struct sockaddr*)&addresses[i], sizeof(addresses[i])) < 0) {
101 close_socket(sock);
102 cm_log("Server", "Bind failure");
103 return 1;
104 }
105 if(listen(sock, 128) < 0) {
106 close_socket(sock);
107 cm_log("Server", "Listen failure");
108 return 1;
109 }
110 sockets[i] = sock;
111 }
112 return 0;
113}
114
115#ifdef __MINGW32__
116struct pass_entry {
117 int sock;
118 int port;
119 bool ssl;
120};
121
122unsigned int WINAPI tw_server_pass(void* ptr) {
123 int sock = ((struct pass_entry*)ptr)->sock;
124 bool ssl = ((struct pass_entry*)ptr)->ssl;
125 int port = ((struct pass_entry*)ptR)->port;
126 free(ptr);
127#else
128void tw_server_pass(int sock, bool ssl, int port) {
129#endif
130 char* name = config.hostname;
131
132 SSL_CTX* ctx = NULL;
133 SSL* s = NULL;
134 if(ssl) {
135 ctx = tw_create_ssl_ctx(port);
136 s = SSL_new(ctx);
137 SSL_set_fd(s, sock);
138 if(SSL_accept(s) <= 0) goto cleanup;
139 }
140cleanup:
141 close_socket(sock);
142#ifdef __MINGW32__
143 _endthreadex(0);
144#endif
145}
146
147void tw_server_loop(void) {
148 struct timeval tv;
149 while(1) {
150 FD_ZERO(&fdset);
151 int i;
152 for(i = 0; i < sockcount; i++) {
153 FD_SET(sockets[i], &fdset);
154 }
155 tv.tv_sec = 1;
156 tv.tv_usec = 0;
157 int ret = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
158 if(ret == -1) {
159 break;
160 } else if(ret > 0) {
161 /* connection */
162 int i;
163 for(i = 0; i < sockcount; i++) {
164 if(FD_ISSET(sockets[i], &fdset)) {
165 SOCKADDR claddr;
166 int clen = sizeof(claddr);
167 int sock = accept(sockets[i], (struct sockaddr*)&claddr, &clen);
168 cm_log("Server", "New connection accepted");
169#ifdef __MINGW32__
170 HANDLE thread;
171 struct pass_entry* e = malloc(sizeof(*e));
172 e->sock = sock;
173 e->ssl = config.ports[i] & (1ULL << 32);
174 e->port = config.ports[i];
175 thread = (HANDLE)_beginthreadex(NULL, 0, tw_server_pass, e, 0, NULL);
176#else
177 pid_t pid = fork();
178 if(pid == 0) {
179 tw_server_pass(sock, config.ports[i] & (1ULL << 32), config.ports[i]);
180 _exit(0);
181 } else {
182 close_socket(sock);
183 }
184#endif
185 }
186 }
187 }
188 }
189}
Note: See TracBrowser for help on using the repository browser.