There is now a partially functional block display in the aesalon GUI.
[aesalon.git] / src / platform / TCPServerSocket.cpp
blobb8c05c96e1651bb0df197e6b09d52f6202c1a8ba
1 #include <sys/types.h>
2 #include <sys/time.h>
3 #include <sys/socket.h>
4 #include <arpa/inet.h>
5 #include <unistd.h>
6 #include <cstring>
7 #include <iostream>
8 #include <netdb.h>
9 #include <errno.h>
11 #include "TCPServerSocket.h"
12 #include "PlatformException.h"
13 #include "misc/String.h"
15 namespace Aesalon {
16 namespace Platform {
18 TCPServerSocket::TCPServerSocket(int port) : port(port) {
19 struct addrinfo hints, *result, *rp;
21 memset(&hints, 0, sizeof(hints));
22 hints.ai_family = AF_UNSPEC;
23 hints.ai_socktype = SOCK_STREAM;
24 hints.ai_flags = AI_PASSIVE;
25 hints.ai_protocol = 0;
26 hints.ai_canonname = NULL;
27 hints.ai_addr = NULL;
28 hints.ai_next = NULL;
30 int ret = getaddrinfo(NULL, Misc::String::from<int>(port).c_str(), &hints, &result);
31 if(ret != 0) {
32 throw PlatformException(Misc::StreamAsString() << "Couldn't resolve hostname: " << gai_strerror(ret), false);
35 for(rp = result; rp != NULL; rp = rp->ai_next) {
36 socket_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
37 if(socket_fd == -1) continue;
39 if(bind(socket_fd, rp->ai_addr, rp->ai_addrlen) == 0) break;
41 int e = errno;
42 close(socket_fd);
43 errno = e;
45 if(rp == NULL) throw PlatformException("Couldn't open port for listening: ");
46 freeaddrinfo(result);
48 if(listen(socket_fd, 8) == -1) throw PlatformException("Couldn't listen on socket: ");
50 int yes = 1;
52 if(setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
53 throw PlatformException("Couldn't set SO_REUSEADDR on socket: ");
56 TCPServerSocket::~TCPServerSocket() {
58 close(socket_fd);
61 int TCPServerSocket::get_port() const {
62 if(port != 0) return port;
64 /* TODO: find the randomly-allocated port . . . */
65 return 0;
68 void TCPServerSocket::accept_connections() {
69 int s_fd;
71 fd_set listen_set, read_set;
72 struct timeval tv;
73 FD_ZERO(&listen_set);
74 FD_ZERO(&read_set);
75 FD_SET(socket_fd, &listen_set);
77 tv.tv_sec = 0;
78 tv.tv_usec = 0;
80 read_set = listen_set;
82 while(select(socket_fd+1, &read_set, NULL, NULL, &tv)) {
83 if(FD_ISSET(socket_fd, &read_set)) {
84 s_fd = accept(socket_fd, NULL, 0);
85 socket_list.push_back(new TCPSocket(s_fd));
87 read_set = listen_set;
91 void TCPServerSocket::remove_invalid_sockets() {
92 socket_list_t::iterator i = socket_list.begin();
94 /* NOTE: this is quite inefficient with large amounts of sockets . . . */
95 for(; i != socket_list.end(); i ++) {
96 if(!(*i)->is_valid()) {
97 (*i) = 0;
98 socket_list.erase(i);
99 i = socket_list.begin();
104 void TCPServerSocket::send_data(std::string data) {
105 socket_list_t::iterator i = socket_list.begin();
107 for(; i != socket_list.end(); i ++) {
108 (*i)->send_data(data);
112 void TCPServerSocket::send_data(Misc::SmartPointer<EventQueue> data) {
113 while(data->peek_event()) {
114 std::string data_string = data->peek_event()->serialize();
115 std::cout << "TCPServerSocket::send_data(): sending \"" << data_string << "\"\n";
116 send_data(data_string);
117 data->pop_event();
121 void TCPServerSocket::disconnect_all() {
122 socket_list_t::iterator i = socket_list.begin();
123 for(; i != socket_list.end(); i ++) {
124 if((*i)->is_valid()) (*i)->disconnect();
128 } // namespace Platform
129 } // namespace Aesalon