QDNix
Quick’n’dirty *NIX
server.c
1 #include <netinet/in.h>
2 #include <openssl/prov_ssl.h>
3 #include <openssl/types.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdint.h>
8 #include <unistd.h>
9 #include <signal.h>
10 #include <sys/socket.h>
11 #include <arpa/inet.h>
12 #include <sys/select.h>
13 #include <openssl/ssl.h>
14 #include <openssl/err.h>
15 #include <stdio.h>
16 
17 #include "geminid.h"
18 
19 static void
20 client_handler(int sock, SSL_CTX *ctx, const char *srv_dir)
21 {
22  SSL *client_tls;
23 
24  client_tls = SSL_new(ctx);
25  SSL_set_fd(client_tls, sock);
26 
27  if (SSL_accept(client_tls) <= 0)
28  {
29  ERR_print_errors_fp(stderr);
30  goto end;
31  }
32 
33  gemini_protocol_handler(client_tls, srv_dir);
34 
35 end:
36  SSL_shutdown(client_tls);
37  SSL_free(client_tls);
38  close(sock);
39 }
40 
41 static int
42 create_server(uint16_t port)
43 {
44  struct sockaddr_in6 addr;
45  int sock;
46 
47  addr.sin6_family = AF_INET6;
48  addr.sin6_port = htons(port);
49  addr.sin6_addr = in6addr_any;
50 
51  sock = socket(AF_INET6, SOCK_STREAM, 0);
52  if (sock < 0)
53  {
54  exit(EXIT_FAILURE);
55  }
56 
57  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
58 
59  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
60  {
61  exit(EXIT_FAILURE);
62  }
63 
64  if (listen(sock, 5) < 0)
65  {
66  exit(EXIT_FAILURE);
67  }
68 
69  return (sock);
70 }
71 
72 
73 int
74 server(const char *srv_dir, uint16_t port,
75  const char *cert_file, const char *key_file)
76 {
77  int server_sock;
78  struct sockaddr_in6 addr;
79  socklen_t addrlen;
80  int client_sock;
81  pid_t pid;
82  SSL_CTX *ctx;
83 
84  ctx = create_tls_context(cert_file, key_file);
85  server_sock = create_server(port);
86  while (1)
87  {
88  client_sock = accept(server_sock, (struct sockaddr *)&addr, &addrlen);
89  if (client_sock < 0)
90  {
91  printf("Can't accept");
92  continue;
93  }
94 
95  pid = fork();
96  if (pid == 0)
97  {
98  close(server_sock);
99  client_handler(client_sock, ctx, srv_dir);
100  exit(0);
101  }
102  else if (pid > 0)
103  {
104  close(client_sock);
105  }
106  else
107  {
108  printf("can't fork");
109  }
110  }
111 
112  (void)ctx;
113 
114  return (0);
115 }