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

Last change on this file since 15 was 15, checked in by Nishi, on Sep 13, 2024 at 10:49:53 PM

close socket properly

  • Property svn:keywords set to Id
File size: 4.1 KB
Line 
1/* $Id: server.c 15 2024-09-13 13:49:53Z 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 bool sslworks = false;
135 if(ssl) {
136 ctx = tw_create_ssl_ctx(port);
137 s = SSL_new(ctx);
138 SSL_set_fd(s, sock);
139 if(SSL_accept(s) <= 0) goto cleanup;
140 sslworks = true;
141 }
142cleanup:
143 if(sslworks){
144 SSL_shutdown(s);
145 }
146 SSL_free(s);
147 close_socket(sock);
148#ifdef __MINGW32__
149 _endthreadex(0);
150#endif
151}
152
153void tw_server_loop(void) {
154 struct timeval tv;
155 while(1) {
156 FD_ZERO(&fdset);
157 int i;
158 for(i = 0; i < sockcount; i++) {
159 FD_SET(sockets[i], &fdset);
160 }
161 tv.tv_sec = 1;
162 tv.tv_usec = 0;
163 int ret = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
164 if(ret == -1) {
165 break;
166 } else if(ret > 0) {
167 /* connection */
168 int i;
169 for(i = 0; i < sockcount; i++) {
170 if(FD_ISSET(sockets[i], &fdset)) {
171 SOCKADDR claddr;
172 int clen = sizeof(claddr);
173 int sock = accept(sockets[i], (struct sockaddr*)&claddr, &clen);
174 cm_log("Server", "New connection accepted");
175#ifdef __MINGW32__
176 HANDLE thread;
177 struct pass_entry* e = malloc(sizeof(*e));
178 e->sock = sock;
179 e->ssl = config.ports[i] & (1ULL << 32);
180 e->port = config.ports[i];
181 thread = (HANDLE)_beginthreadex(NULL, 0, tw_server_pass, e, 0, NULL);
182#else
183 pid_t pid = fork();
184 if(pid == 0) {
185 tw_server_pass(sock, config.ports[i] & (1ULL << 32), config.ports[i]);
186 _exit(0);
187 } else {
188 close_socket(sock);
189 }
190#endif
191 }
192 }
193 }
194 }
195}
Note: See TracBrowser for help on using the repository browser.