Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

netsession_server.cpp

Go to the documentation of this file.
00001 /*
00002         $Id: netsession_server.cpp,v 1.7 2001/03/23 15:09:36 mbn Exp $
00003 
00004         ------------------------------------------------------------------------
00005         ClanLib, the platform independent game SDK.
00006 
00007         This library is distributed under the GNU LIBRARY GENERAL PUBLIC LICENSE
00008         version 2. See COPYING for details.
00009 
00010         For a total list of contributers see CREDITS.
00011 
00012         ------------------------------------------------------------------------
00013 */
00014 
00015 #ifdef WIN32
00016 #pragma warning (disable:4786)
00017 #endif
00018 
00019 #include <API/Core/System/error.h>
00020 #include <API/Core/System/mutex.h>
00021 #include <API/Network/netcomputer.h>
00022 #include <API/Network/netgroup.h>
00023 #include <API/Network/netmessage.h>
00024 #include <API/Core/System/error.h>
00025 #include <API/Core/System/thread.h>
00026 #include <API/Core/System/cl_assert.h>
00027 #include <API/Core/System/system.h>
00028 #include <Network/Generic/network_delivery_impl.h>
00029 #include <Network/Generic/netsession_server.h>
00030 #include <Network/Generic/netsession_generic.h>
00031 #include <Network/Generic/network_generic.h>
00032 #include <Core/IOData/Generic/outputsource_memory_generic.h>
00033 #include <Core/IOData/Generic/inputsource_memory_generic.h>
00034 
00035 CL_NetSession_Server::CL_NetSession_Server(
00036         CL_ConnectionProvider *provider,
00037         const char *game_id,
00038         int port)
00039 : CL_NetSession_Generic(provider)
00040 {
00041         mutex = CL_Mutex::create();
00042 
00043         this->game_id = game_id;
00044         this->port = port;
00045         
00046         id_counter = 1; // server is zero, that's why we start at 1.
00047         
00048         udp_connection = provider->create_udp_connection(port);
00049         
00050         provider->start_accept_on_port(port);
00051 
00052         exit_thread = false;
00053         thread = CL_Thread::create(this);
00054         thread->start();
00055 }
00056 
00057 CL_NetSession_Server::~CL_NetSession_Server()
00058 {
00059         exit_thread = true;
00060         thread->wait();
00061         delete thread;
00062 
00063         provider->stop_accept_on_port(port);
00064         
00065         // clean up connections to clients:
00066         {
00067                 for (
00068                         std::list<CL_NetComputer_Host*>::iterator it = prejoin.begin();
00069                         it != prejoin.end();
00070                         it++)
00071                 {
00072                         delete *it;
00073                 }
00074         }
00075         {
00076                 for (
00077                         std::list<CL_NetComputer_Host*>::iterator it = computers.begin();
00078                         it != computers.end();
00079                         it++)
00080                 {
00081                         delete *it;
00082                 }
00083         }
00084 
00085         while (leave_queue.empty() == false)
00086         {
00087                 delete leave_queue.front();
00088                 leave_queue.pop();
00089         }
00090 
00091         delete mutex;
00092 }
00093 
00094 CL_NetComputer &CL_NetSession_Server::get_server()
00095 {
00096         static CL_NetComputer null_server;
00097         return null_server;
00098 }
00099 
00100 CL_NetGroup &CL_NetSession_Server::get_all()
00101 {
00102         return all;
00103 }
00104 
00105 bool CL_NetSession_Server::peek(int channel) const
00106 {
00107         CL_MutexSection mutex_section(mutex);
00108 
00109         CL_NetChannelQueue *queue = find_queue(channel);
00110         if (queue != NULL) return !queue->empty();
00111         
00112         return false;
00113 }
00114 
00115 CL_NetMessage CL_NetSession_Server::receive(int channel, int timeout)
00116 {
00117         CL_MutexSection mutex_section(mutex);
00118 
00119         CL_NetChannelQueue *queue = create_queue(channel);
00120 
00121         while (queue->empty())
00122         {
00123                 int s = timeout;
00124                 if (timeout < 0 || timeout > 20) s = 20;
00125                 mutex->leave();
00126                 CL_System::sleep(s);
00127                 mutex->enter();
00128 
00129                 if (timeout != -1)
00130                 {
00131                         timeout -= s;
00132                         if (timeout <= 0) break;
00133                 }
00134         }
00135 
00136         if (queue->empty()) throw CL_Error("No message to receive.");
00137         CL_NetMessage msg = queue->front(); queue->pop();
00138         check_trigger();
00139         return msg;
00140 }
00141 
00142 void CL_NetSession_Server::send(
00143         const int dest_channel,
00144         const CL_NetComputer &dest,
00145         const CL_NetMessage &message,
00146         bool reliable /*= true*/)
00147 {
00148         CL_MutexSection mutex_section(mutex);
00149 
00150         static bool warning = true;
00151         if (warning && reliable == false)
00152         {
00153                 cl_info(info_network, "cannot send data unreliable (udp): not implemented yet!");
00154                 warning = false;
00155         }
00156 
00157         CL_NetComputer_Host *dest_host = get_computer_host(dest);
00158 /*
00159         CL_NetChannelQueue *queue = find_queue(dest_channel);
00160         
00161         if (queue == NULL)
00162                 return; // nobody has read or write access. Don't send message.
00163 
00164         if (has_read_access(queue, dest_host) == false)
00165                 return; // dest_host is not allowed to read messages on channel.
00166 */
00167         // permissions ok, send message:
00168         CL_OutputSource_MemoryGeneric output;
00169         output.write_int32(Packet_NetChannel_Message_ToClient);
00170         output.write_int32(dest_channel);
00171         output.write_int32(message.data.size());
00172         output.write(message.data.data(), message.data.size());
00173         
00174         CL_ConnectionPacket packet;
00175         packet.size = output.size();
00176         packet.data = output.get_data();
00177 
00178         dest_host->connection->send(packet);
00179 }
00180 
00181 void CL_NetSession_Server::send(
00182         const int dest_channel,
00183         const CL_NetGroup &dest,
00184         const CL_NetMessage &message,
00185         bool reliable /*= true*/)
00186 {
00187         CL_MutexSection mutex_section(mutex);
00188 
00189         const std::list<CL_NetComputer> &computers = dest.get_computers();
00190         std::list<CL_NetComputer>::const_iterator it;
00191 
00192         for (
00193                 it = computers.begin();
00194                 it != computers.end();
00195                 it++)
00196         {
00197                 send(
00198                         dest_channel,
00199                         *it,
00200                         message,
00201                         reliable);
00202         }
00203 }
00204 
00205 CL_NetComputer CL_NetSession_Server::receive_computer_leave()
00206 {
00207         CL_MutexSection mutex_section(mutex);
00208 
00209         if (leave_queue.empty()) return NULL;
00210 
00211         CL_NetComputer ret = leave_queue.front();
00212         leave_queue.pop();
00213         check_trigger();
00214 
00215         // Remove all access rules for this object.
00216         for (
00217                 std::map<int, CL_NetChannelQueue>::iterator it = netchannels.begin();
00218                 it != netchannels.end();
00219                 it++)
00220         {
00221                 CL_NetChannelQueue &queue = (*it).second;
00222                 queue.access.erase(get_computer_host(ret)->id);
00223         }
00224 
00225         return ret;
00226 }
00227 
00228 CL_NetComputer CL_NetSession_Server::receive_computer_join()
00229 {
00230         CL_MutexSection mutex_section(mutex);
00231 
00232         if (join_queue.empty()) throw CL_Error("Computer join queue is empty.");
00233         CL_NetComputer ret(join_queue.front());
00234         join_queue.pop();
00235         check_trigger();
00236 
00237         return ret;
00238 }
00239 
00240 CL_NetComputer CL_NetSession_Server::receive_computer_rejoin()
00241 {
00242         CL_MutexSection mutex_section(mutex);
00243 
00244         if (rejoin_queue.empty()) return NULL;
00245         CL_NetComputer ret(rejoin_queue.front());
00246         rejoin_queue.pop();
00247         check_trigger();
00248 
00249         return ret;
00250 }
00251 
00252 bool CL_NetSession_Server::receive_session_closed()
00253 {
00254         return false; // we are the server - only closed if deleted.
00255 }
00256 
00257 int CL_NetSession_Server::access_status(int /*channel*/) const
00258 {
00259         // server has always full access.
00260         return ACCESS_CHANNEL_READ|ACCESS_CHANNEL_WRITE;
00261 }
00262 
00263 bool CL_NetSession_Server::is_writable(int /*channel*/) const
00264 {
00265         return true;
00266 }
00267 
00268 bool CL_NetSession_Server::is_readable(int /*channel*/) const
00269 {
00270         return true;
00271 }
00272 
00273 // Client side only:
00274 int CL_NetSession_Server::receive_access_changed()
00275 {
00276         return -1; // we are not a client!
00277 }
00278 
00279 // Server side only:
00280 void CL_NetSession_Server::set_access(
00281         int channel,
00282         const CL_NetComputer &computer,
00283         int access_rights)
00284 {
00285         CL_MutexSection mutex_section(mutex);
00286 
00287         CL_NetComputer_Host *computer_host = get_computer_host(computer);
00288         CL_NetChannelQueue *queue = create_queue(channel);
00289 
00290         int cur_access = 0;
00291         std::map<int,int>::iterator access_it = queue->access.find(computer_host->id);
00292         if (access_it != queue->access.end())
00293         {
00294                 cur_access = (*access_it).second;
00295                 (*access_it).second = access_rights;
00296         }
00297         else
00298         {
00299                 queue->access.insert(std::pair<int,int>(computer_host->id, access_rights));
00300         }
00301 
00302         if (cur_access != access_rights)
00303         {
00304                 CL_OutputSource_MemoryGeneric output;
00305                 output.write_int32(Packet_NetChannel_AccessChange);
00306                 output.write_int32(channel);
00307                 output.write_int32(access_rights);
00308         
00309                 CL_ConnectionPacket packet;
00310                 packet.size = output.size();
00311                 packet.data = output.get_data();
00312 
00313                 computer_host->connection->send(packet);
00314         }
00315 }
00316 
00317 void CL_NetSession_Server::set_access(
00318         int channel,
00319         const CL_NetGroup &group,
00320         int access_rights)
00321 {
00322         CL_MutexSection mutex_section(mutex);
00323 
00324         for (
00325                 std::list<CL_NetComputer>::const_iterator it = group.get_computers().begin();
00326                 it != group.get_computers().end();
00327                 it++)
00328         {
00329                 set_access(
00330                         channel,
00331                         *it,
00332                         access_rights);
00333         }
00334 }
00335 
00336 void CL_NetSession_Server::keep_alive()
00337 {
00338         CL_MutexSection mutex_section(mutex);
00339         
00340         if (exit_thread) return;
00341 
00342         // check connections for data:
00343         std::list<CL_NetComputer_Host*>::iterator it_computers = computers.begin();
00344         while (it_computers != computers.end())
00345         {
00346                 while ((*it_computers)->connection->peek())
00347                 {
00348                         CL_ConnectionPacket msg = (*it_computers)->connection->receive();
00349                         
00350                         CL_InputSource_MemoryGeneric input(msg.data, msg.size, true);
00351                         switch (input.read_int32())
00352                         {
00353                         case Packet_NetChannel_AccessChange:
00354                                 cl_info(info_network, "Network Protocol error!");
00355                                 cl_assert(false);
00356                                 break;
00357                         
00358                         case Packet_NetChannel_Message_ToServer:
00359                                 {
00360                                         static bool warning = true;
00361                                         if (warning)
00362                                         {
00363                                                 cl_info(info_network, "permissions not checked: Not implemented yet.");
00364                                                 warning = false;
00365                                         }
00366                                         CL_NetChannelQueue *queue = create_queue(input.read_int32());
00367                                         CL_NetMessage game_msg;
00368                                         int size = input.read_int32();
00369                                         char *data = new char[size];
00370                                         game_msg.from = *it_computers;
00371                                         input.read(data, size);
00372                                         game_msg.data.append(data, size);
00373                                         queue->push(game_msg);
00374                                         trigger.set_flag();
00375                                 }
00376                                 break;
00377 
00378                         default:
00379                                 cl_info(info_network, "Network Protocol error!");
00380                                 cl_assert(false);
00381                         }
00382                 }
00383 
00384                 if ((*it_computers)->connection->connection_lost())
00385                 {
00386                         leave_queue.push(*it_computers);
00387                         all.remove(CL_NetComputer(*it_computers));
00388                         provider->remove_connection((*it_computers)->connection);
00389                         it_computers = computers.erase(it_computers);
00390 
00391                         trigger.set_flag();
00392                 }
00393                 else
00394                 {
00395                         it_computers++;
00396                 }
00397         }
00398 
00399 
00400         // check for "hello to you too" connections:
00401         std::list<CL_NetComputer_Host*>::iterator it_prejoin = prejoin.begin();
00402         while (it_prejoin != prejoin.end())
00403         {
00404                 if ((*it_prejoin)->connection->connection_lost()) // how rude!
00405                 {
00406                         delete *it_prejoin;
00407                         it_prejoin = prejoin.erase(it_prejoin);
00408                         
00409                         continue;
00410                 }
00411 
00412                 if ((*it_prejoin)->connection->peek())
00413                 {
00414                         CL_ConnectionPacket msg = (*it_prejoin)->connection->receive();
00415                         
00416                         CL_InputSource_MemoryGeneric input(msg.data, msg.size);
00417                         if (msg.size >= (int) sizeof(int))
00418                         {
00419                                 switch (input.read_int32())
00420                                 {
00421                                 case Packet_Hello_ToYouToo: // ahh - he wants to join.
00422                                         computers.push_back(*it_prejoin);
00423                                         all.add(CL_NetComputer(*it_prejoin));
00424                                         join_queue.push(*it_prejoin);
00425                                         it_prejoin = prejoin.erase(it_prejoin);
00426                                         trigger.set_flag();
00427                                         continue;
00428 
00429                                 default:
00430                                         cl_info(info_network, "Network Protocol error!");
00431                                         cl_assert(false);
00432                                 }
00433                         }
00434                         
00435                         delete[] ((char*) msg.data);
00436                 }
00437 
00438                 it_prejoin++;
00439         }
00440         
00441         // accept incoming clients:
00442         while (true)
00443         {
00444                 CL_Connection *new_client = provider->accept();
00445                 if (new_client == NULL) break;
00446                 
00447                 CL_OutputSource_MemoryGeneric msg;
00448                 msg.write_int32(Packet_Hello);
00449                 msg.write_int32(id_counter);
00450                 msg.write_int32(game_id.length());
00451                 msg.write(game_id.c_str(), game_id.length());
00452                 
00453                 CL_ConnectionPacket packet(msg.get_data(), msg.size());
00454                 new_client->send(packet);
00455                 
00456                 prejoin.push_back(new CL_NetComputer_Host(this, new_client, id_counter++));
00457         }
00458         
00459         // check for UDP data:
00460         while (udp_connection->peek())
00461         {
00462                 CL_UDPConnectionPacket netmsg = udp_connection->receive();
00463                 
00464                 try
00465                 {
00466                         CL_InputSource_MemoryGeneric message(netmsg.data, netmsg.size);
00467                         
00468                         int msgtype = message.read_int32();
00469                         switch (msgtype)
00470                         {
00471                         case 0: // game ping message. Reply with game_id.
00472                                 {
00473                                         std::string req_game_id = message.read_string();
00474                                         if (req_game_id == game_id)
00475                                         {
00476                                                 CL_OutputSource_MemoryGeneric msg;
00477                                                 msg.write_int32(1); // game ping reply message.
00478                                                 msg.write_string(game_id.c_str());
00479                                         
00480                                                 CL_UDPConnectionPacket reply;
00481                                                 reply.data = msg.get_data();
00482                                                 reply.size = msg.size();
00483                                                 reply.ip_addr = netmsg.ip_addr;
00484                                                 reply.port = netmsg.port;
00485                                                 udp_connection->send(reply);
00486                                         }
00487                                 }
00488                                 break;
00489                                 
00490                         case 1: // game ping reply message.
00491                                 // ignore it. server shouldn't get this message!
00492                                 break;
00493                                 
00494                         case 2: // normal udp game packet.
00495                                 // not implemented yet.
00496                                 break;
00497                         }
00498                 }
00499                 catch (CL_Error err)
00500                 {
00501                         // protocol error. We need some logging stuff.
00502                 }
00503         }
00504 }
00505 
00506 void CL_NetSession_Server::run()
00507 {
00508         while (exit_thread == false)
00509         {
00510                 keep_alive();
00511                 provider->wait_for_connection_data(mutex);
00512         }
00513 }
00514 
00515 CL_NetChannelQueue *CL_NetSession_Server::find_queue(int netchannel) const
00516 {
00517         std::map<int, CL_NetChannelQueue>::const_iterator it = netchannels.find(netchannel);
00518         if (it == netchannels.end()) return NULL;
00519         
00520         return (CL_NetChannelQueue *) (&(*it).second);
00521 }
00522 
00523 CL_NetChannelQueue *CL_NetSession_Server::create_queue(int netchannel)
00524 {
00525         CL_NetChannelQueue *found = find_queue(netchannel);
00526         if (found != NULL) return found;
00527 
00528         CL_NetChannelQueue c;
00529         netchannels.insert(std::pair<int, CL_NetChannelQueue>(netchannel, c));
00530 
00531         return &netchannels[netchannel];
00532 }
00533 
00534 bool CL_NetSession_Server::has_read_access(
00535         CL_NetChannelQueue *channel,
00536         CL_NetComputer_Host *host)
00537 {
00538         std::map<int, int>::iterator it = channel->access.find(host->id);
00539         if (it == channel->access.end()) return false;
00540         
00541         return ((*it).second & ACCESS_CHANNEL_READ) == ACCESS_CHANNEL_READ;
00542 }
00543 
00544 void CL_NetSession_Server::check_trigger()
00545 {
00546         bool queues_empty =
00547                 join_queue.empty() &&
00548                 rejoin_queue.empty() &&
00549                 leave_queue.empty();
00550 
00551         std::map<int,CL_NetChannelQueue>::iterator it;
00552         for (it = netchannels.begin(); it != netchannels.end(); it++)
00553         {
00554                 if (!it->second.empty()) queues_empty = false;
00555         }
00556 
00557         if (queues_empty) trigger.reset();
00558 }
00559 
00560 // ---------
00561 
00562 CL_NetComputer_Host::CL_NetComputer_Host(
00563         CL_NetSession_Server *session,
00564         CL_Connection *connection,
00565         int id)
00566 :
00567         CL_NetComputer_Generic(session)
00568 {
00569         this->connection = connection;
00570         this->id = id;
00571 }
00572 
00573 CL_NetComputer_Host::~CL_NetComputer_Host()
00574 {
00575         delete connection;
00576 }
00577 
00578 unsigned long CL_NetComputer_Host::get_address() const
00579 {
00580 //      return connection->get_address();
00581         return 0;
00582 }
00583 
00584 void CL_NetComputer_Host::disconnect()
00585 {
00586 //      connection->disconnect();
00587 }

Generated at Wed Apr 4 19:54:02 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001