SockIt
|
00001 /* Udpserver.cpp 00002 * 00003 * Listens to connections over UDP. This class is directly exposed to the Javascript. Will not listen to the port 00004 * specified until the listen() method is invoked. This is so the handlers can be attached beforehand. 00005 * 00006 */ 00007 00008 #include "UdpServer.h" 00009 00010 00011 UdpServer::UdpServer(int port, boost::asio::io_service & io_service) 00012 : Udp("SERVER", port, io_service), socket(new udp::socket(io_service)) 00013 { 00014 initialize(); 00015 } 00016 00017 00018 UdpServer::UdpServer(int port, boost::asio::io_service & io_service, map<string, string> options) 00019 : Udp("SERVER", port, io_service), socket(new udp::socket(io_service)) 00020 { 00021 parse_args(options); 00022 00023 initialize(); 00024 } 00025 00026 00027 void UdpServer::shutdown() 00028 { 00029 if(!failed) 00030 { 00031 should_close = true; 00032 00033 if (pending_sends == 0) { 00034 fire_close(); 00035 close(); 00036 } 00037 } 00038 else 00039 { 00040 // Log & fire an error 00041 string message("Trying to shutdown a permanently failed UDP server!"); 00042 Logger::error(message, port, host); 00043 } 00044 00045 } 00046 00047 void UdpServer::close() 00048 { 00049 /* 00050 if (socket->is_open()) 00051 { 00052 if(multicast && multicast_group) 00053 { 00054 socket->set_option( 00055 boost::asio::ip::multicast::leave_group( 00056 boost::asio::ip::address::from_string(*multicast_group))); 00057 } 00058 00059 socket->close(); 00060 } 00061 */ 00062 if(socket->is_open()) 00063 socket->close(); 00064 } 00065 00066 00067 void UdpServer::initialize() 00068 { 00069 log_options(); 00070 00071 listening = false; 00072 00073 if(using_ipv6 && *using_ipv6) 00074 socket->open(udp::v6()); 00075 else 00076 socket->open(udp::v4()); 00077 00078 if(!socket->is_open()) 00079 { 00080 string message("UDP server failed to initialize, could not open socket"); 00081 Logger::error(message, port, host); 00082 fire_error(message); 00083 } 00084 00085 // synchronize the buffer size of the socket with this class's buffer size 00086 boost::asio::socket_base::receive_buffer_size buf_size_option(BUFFER_SIZE); 00087 socket->set_option(buf_size_option); 00088 00089 if(do_not_route) 00090 { 00091 boost::asio::socket_base::do_not_route option(*do_not_route); 00092 socket->set_option(option); 00093 } 00094 00095 if(reuse_address) 00096 { 00097 boost::asio::socket_base::reuse_address option(*reuse_address); 00098 socket->set_option(option); 00099 } 00100 00101 if(multicast) 00102 { 00103 /* force this to be set */ 00104 boost::asio::socket_base::reuse_address option(true); 00105 socket->set_option(option); 00106 } 00107 00108 if(multicast_ttl) 00109 { 00110 boost::asio::ip::multicast::hops option(*multicast_ttl); 00111 socket->set_option(option); 00112 } 00113 00114 // register these methods so they can be invoked from the Javascript 00115 registerMethod("listen", make_method(this, &UdpServer::start_listening)); 00116 } 00117 00118 00119 UdpServer::~UdpServer() 00120 { 00121 close(); 00122 } 00123 00124 00125 void UdpServer::start_listening() 00126 { 00127 if(failed) 00128 { 00129 // Log & fire an error 00130 string message("Trying to start a UDP server that has permanently failed!"); 00131 Logger::error(message, port, host); 00132 return; 00133 } 00134 00135 if(listening) return; 00136 00137 try 00138 { 00139 if(using_ipv6 && *using_ipv6) 00140 socket->bind(udp::endpoint(udp::v6(), port)); 00141 else 00142 socket->bind(udp::endpoint(udp::v4(), port)); 00143 } 00144 catch (boost::system::system_error &e) 00145 { 00146 // Catch this error, and fail gracefully 00147 string message(string("Caught error initializing UDP server: '") + e.what() + "'"); 00148 Logger::error(message, port, host); 00149 00150 // Stop this server from ever doing anything again 00151 failed = true; 00152 return; 00153 } 00154 00155 Logger::info("bind!", port, host); 00156 00157 if(multicast) 00158 { 00159 if(!multicast_group) 00160 { 00161 Logger::error("UdpServer: Multicast set, but no multicast group given", port, host); 00162 } 00163 else 00164 { 00165 // Try to join the multicast group, and fail gracefully if we can't join it 00166 try 00167 { 00168 socket->set_option(boost::asio::ip::multicast::join_group( 00169 boost::asio::ip::address::from_string(*multicast_group))); 00170 } 00171 catch(boost::system::system_error & error) 00172 { 00173 // Catch this error, and fail gracefully 00174 string message(string("Caught error initializing UDP joinging multicast group: '") + error.what() + "'"); 00175 Logger::error(message, port, host); 00176 00177 failed = true; 00178 return; 00179 } 00180 } 00181 } 00182 00183 listen(); 00184 fire_open(); 00185 00186 listening = true; 00187 } 00188 00189 00190 void UdpServer::listen() 00191 { 00192 Logger::info("udpserver: starting to listen", port, host); 00193 00194 if(remote_endpoint && remote_endpoint.get()) 00195 socket->async_receive_from(boost::asio::buffer(receive_buffer), *remote_endpoint, 00196 boost::bind(&UdpServer::receive_handler, this, _1, _2, socket, remote_endpoint, host, port)); 00197 else 00198 Logger::warn("remote endpoint is null", port, host); 00199 } 00200 00201 int UdpServer::get_port() 00202 { 00203 return port; 00204 } 00205 00206 00207 void UdpServer::fire_error_event(const string & message) 00208 { 00209 fire_error(message); 00210 } 00211 00212 00213 void UdpServer::fire_data_event(const string data, boost::shared_ptr<udp::socket> socket, boost::shared_ptr<udp::endpoint> endpoint) 00214 { 00215 fire_data(boost::make_shared<UdpEvent>(this, socket, endpoint, data)); 00216 }