]> git.sesse.net Git - cubemap/blob - cubemap.cpp
d0a3ac4d62d5721e42bac1d0f7fed4cec5729b82
[cubemap] / cubemap.cpp
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <assert.h>
5 #include <arpa/inet.h>
6 #include <curl/curl.h>
7 #include <sys/socket.h>
8 #include <pthread.h>
9 #include <sys/types.h>
10 #include <sys/ioctl.h>
11 #include <sys/epoll.h>
12 #include <errno.h>
13 #include <vector>
14 #include <string>
15 #include <map>
16
17 #include "metacube.h"
18 #include "server.h"
19 #include "input.h"
20
21 #define NUM_SERVERS 4
22 #define STREAM_ID "stream"
23 #define STREAM_URL "http://gruessi.zrh.sesse.net:4013/"
24 #define PORT 9094
25
26 using namespace std;
27
28 Server *servers = NULL;
29
30 int create_server_socket(int port)
31 {
32         int server_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
33         if (server_sock == -1) {
34                 perror("socket");
35                 exit(1);
36         }
37
38         int one;        
39         if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
40                 perror("setsockopt(SO_REUSEADDR)");
41                 exit(1);
42         }
43
44         // We want dual-stack sockets. (Sorry, OpenBSD and Windows XP...)
45         int zero = 0;
46         if (setsockopt(server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) == -1) {
47                 perror("setsockopt(IPV6_V6ONLY)");
48                 exit(1);
49         }
50
51         sockaddr_in6 addr;
52         memset(&addr, 0, sizeof(addr));
53         addr.sin6_family = AF_INET6;
54         addr.sin6_port = htons(port);
55
56         if (bind(server_sock, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) == -1) {
57                 perror("bind");
58                 exit(1);
59         }
60
61         if (listen(server_sock, 128) == -1) {
62                 perror("listen");
63                 exit(1);
64         }
65
66         return server_sock;
67 }
68
69 void *acceptor_thread_run(void *arg)
70 {
71         int server_sock = int(intptr_t(arg));
72         int num_accepted = 0;
73         for ( ;; ) {
74                 sockaddr_in6 addr;
75                 socklen_t addrlen = sizeof(addr);
76
77                 // Get a new socket.
78                 int sock = accept(server_sock, reinterpret_cast<sockaddr *>(&addr), &addrlen);
79                 if (sock == -1 && errno == EINTR) {
80                         continue;
81                 }
82                 if (sock == -1) {
83                         perror("accept");
84                         exit(1);
85                 }
86
87                 // Set the socket as nonblocking.
88                 int one = 1;
89                 if (ioctl(sock, FIONBIO, &one) == -1) {
90                         perror("FIONBIO");
91                         exit(1);
92                 }
93
94                 // Pick a server, round-robin, and hand over the socket to it.
95                 servers[num_accepted % NUM_SERVERS].add_client(sock);
96                 ++num_accepted; 
97         }
98 }
99
100 int main(int argc, char **argv)
101 {
102         servers = new Server[NUM_SERVERS];
103         for (int i = 0; i < NUM_SERVERS; ++i) {
104                 servers[i].add_stream(STREAM_ID);
105                 servers[i].run();
106         }
107
108         int server_sock = create_server_socket(PORT);
109
110         pthread_t acceptor_thread;
111         pthread_create(&acceptor_thread, NULL, acceptor_thread_run, reinterpret_cast<void *>(server_sock));
112
113         Input input(STREAM_ID);
114         input.run(STREAM_URL);
115
116         for (int i = 0; i < NUM_SERVERS; ++i) {
117                 servers[i].stop();
118         }
119         delete[] servers;
120 }