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

netsession_client.cpp

Go to the documentation of this file.
00001 /*
00002         $Id: netsession_client.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_client.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_Client::CL_NetSession_Client(
00036         int ip_addr,
00037         int port,
00038         const std::string &game_id,
00039         CL_ConnectionProvider *provider)
00040 : CL_NetSession_Generic(provider)
00041 {
00042         mutex = CL_Mutex::create();
00043 
00044         tcp_connection = provider->create_tcp_connection(
00045                 ip_addr,
00046                 port);
00047 
00048         if (tcp_connection == NULL)
00049         {
00050                 throw CL_Error("Could not connect to host.");
00051         }
00052 
00053         udp_connection = NULL; // still no support for udp in client.
00054 
00055         // client code currently only knows about the server.
00056         server = CL_NetComputer(new CL_NetComputer_Server(this));
00057         all.add(server);
00058 
00059         // do "hello to you too" handshake.
00060         CL_ConnectionPacket p = tcp_connection->receive();
00061         while (p.size == 0) // wait until we get a hello packet.
00062         {
00063                 provider->wait_for_connection_data(mutex);
00064                 p = tcp_connection->receive();
00065         }
00066         
00067         CL_InputSource_MemoryGeneric input(p.data, p.size, true);
00068         if (input.read_int32() != Packet_Hello)
00069         {
00070                 throw CL_Error("Protocol error. Didn't get a Hello.");
00071         }
00072         our_id = input.read_int32();
00073 
00074         int size = input.read_int32();
00075         if (size > 1000)
00076                 throw CL_Error("Protocol error. Game ID size above 1000.");
00077 
00078         char *str = new char[size+1];
00079         str[size] = 0; // null-terminate.
00080         input.read(str, size);
00081         
00082         if (game_id != str) // not same game_id. probably an other clanlib game.
00083         {
00084                 delete[] str;
00085                 throw CL_Error("Wrong netsession id.");
00086         }
00087 
00088         delete[] str;
00089         
00090         // say "HelloToYouToo" to officially join the netsession:
00091         CL_OutputSource_MemoryGeneric output;
00092         output.write_int32(Packet_Hello_ToYouToo);
00093         tcp_connection->send(
00094                 CL_ConnectionPacket(
00095                         output.get_data(),
00096                         output.size()));
00097 
00098         exit_thread = false;
00099         thread = CL_Thread::create(this);
00100         thread->start();
00101 }
00102 
00103 CL_NetSession_Client::~CL_NetSession_Client()
00104 {
00105         exit_thread = true;
00106         thread->wait();
00107         delete thread;
00108 
00109         delete tcp_connection;
00110         delete udp_connection;
00111 
00112         // clean up connections to clients:
00113         for (
00114                 std::list<CL_NetChannelQueue_Client*>::iterator it = netchannels.begin();
00115                 it != netchannels.end();
00116                 it++)
00117         {
00118                 delete *it;
00119         }
00120 /*
00121         should be enabled when the client knows about other clients...
00122 
00123         while (leave_queue.empty() == false)
00124         {
00125                 delete leave_queue.pop();
00126         }
00127 */
00128 
00129         delete mutex;
00130 }
00131 
00132 CL_NetComputer &CL_NetSession_Client::get_server()
00133 {
00134         return server;
00135 }
00136 
00137 CL_NetGroup &CL_NetSession_Client::get_all()
00138 {
00139         return all;
00140 }
00141 
00142 bool CL_NetSession_Client::peek(int channel) const
00143 {
00144         CL_MutexSection mutex_section(mutex);
00145 
00146         CL_NetChannelQueue_Client *queue = find_queue(channel);
00147         if (queue != NULL)
00148         {
00149                 return !queue->empty();
00150         }
00151 
00152         return false;
00153 }
00154 
00155 CL_NetMessage CL_NetSession_Client::receive(int channel, int timeout)
00156 {
00157         CL_MutexSection mutex_section(mutex);
00158 
00159         CL_NetChannelQueue_Client *queue = create_queue(channel);
00160 
00161         while (queue->empty()) 
00162         {
00163                 int s = timeout;
00164                 if (timeout < 0 || timeout > 20) s = 20;
00165                 mutex->leave();
00166                 CL_System::sleep(s);
00167                 mutex->enter();
00168 
00169                 if (timeout != -1)
00170                 {
00171                         timeout -= s;
00172                         if (timeout <= 0) break;
00173                 }
00174         }
00175 
00176         if (queue->empty()) throw CL_Error("No message to receive!");
00177         CL_NetMessage msg = queue->front(); queue->pop();
00178         check_trigger();
00179         return msg;
00180 }
00181 
00182 void CL_NetSession_Client::send(
00183         const int dest_channel,
00184         const CL_NetGroup &dest,
00185         const CL_NetMessage &message,
00186         bool reliable /*= true*/)
00187 {
00188         CL_MutexSection mutex_section(mutex);
00189 
00190         static bool warning = true;
00191         if (warning && reliable == false)
00192         {
00193                 cl_info(info_network, "cannot send data unreliable (udp): not implemented yet!");
00194                 warning = false;
00195         }
00196 /*      
00197         CL_NetChannelQueue_Client *queue = find_queue(dest_channel);
00198 
00199         if (queue == NULL)
00200                 throw CL_Error("No write access to netchannel.");
00201 
00202         if ((queue->access & ACCESS_CHANNEL_WRITE) != ACCESS_CHANNEL_WRITE)
00203                 throw CL_Error("No write access to netchannel.");
00204 */
00205         // permissions ok, send message:
00206         CL_OutputSource_MemoryGeneric output;
00207         output.write_int32(Packet_NetChannel_Message_ToServer);
00208         output.write_int32(dest_channel);
00209 
00210         // todo: write the computer id's on destination computers here.
00211 
00212         output.write_int32(message.data.size());
00213         output.write(message.data.data(), message.data.size());
00214 
00215         CL_ConnectionPacket packet;
00216         packet.size = output.size();
00217         packet.data = output.get_data();
00218 
00219         tcp_connection->send(packet);
00220 }
00221 
00222 CL_NetComputer CL_NetSession_Client::receive_computer_leave()
00223 {
00224         throw CL_Error("Computer leave queue empty.");
00225 }
00226 
00227 CL_NetComputer CL_NetSession_Client::receive_computer_join()
00228 {
00229         throw CL_Error("Computer join queue empty.");
00230 }
00231 
00232 CL_NetComputer CL_NetSession_Client::receive_computer_rejoin()
00233 {
00234         throw CL_Error("Computer rejoin queue empty.");
00235 }
00236 
00237 bool CL_NetSession_Client::receive_session_closed()
00238 {
00239         CL_MutexSection mutex_section(mutex);
00240         return tcp_connection->connection_lost();
00241 }
00242 
00243 int CL_NetSession_Client::access_status(int channel) const
00244 {
00245         CL_MutexSection mutex_section(mutex);
00246 
00247         CL_NetChannelQueue_Client *queue = find_queue(channel);
00248         return (queue == NULL) ? 0 : queue->access;
00249 }
00250 
00251 bool CL_NetSession_Client::is_writable(int channel) const
00252 {
00253         CL_MutexSection mutex_section(mutex);
00254 
00255         CL_NetChannelQueue_Client *queue = find_queue(channel);
00256         if (queue == NULL) return false;
00257 
00258         return (queue->access & ACCESS_CHANNEL_WRITE) == ACCESS_CHANNEL_WRITE;
00259 }
00260 
00261 bool CL_NetSession_Client::is_readable(int channel) const
00262 {
00263         CL_MutexSection mutex_section(mutex);
00264 
00265         CL_NetChannelQueue_Client *queue = find_queue(channel);
00266         if (queue == NULL) return false;
00267 
00268         return (queue->access & ACCESS_CHANNEL_READ) == ACCESS_CHANNEL_READ;
00269 }
00270 
00271 // Client side only:
00272 int CL_NetSession_Client::receive_access_changed()
00273 {
00274         CL_MutexSection mutex_section(mutex);
00275 
00276         if (access_queue.empty()) return -1;
00277         int id = access_queue.front()->channel_id;
00278         access_queue.pop();
00279         check_trigger();
00280         return id;
00281 }
00282 
00283 // Server side only:
00284 void CL_NetSession_Client::set_access(
00285         int channel,
00286         const CL_NetComputer &computer,
00287         int access_rights)
00288 {
00289         throw CL_Error("We are not the network server. Cannot change access.");
00290 }
00291 
00292 void CL_NetSession_Client::set_access(
00293         int channel,
00294         const CL_NetGroup &group,
00295         int access_rights)
00296 {
00297         throw CL_Error("We are not the network server. Cannot change access.");
00298 }
00299 
00300 void CL_NetSession_Client::keep_alive()
00301 {
00302         CL_MutexSection mutex_section(mutex);
00303 
00304         if (tcp_connection->connection_lost())
00305         {
00306                 provider->remove_connection(tcp_connection);
00307                 return;
00308         }
00309 
00310         while (tcp_connection->peek())
00311         {
00312                 if (exit_thread) return;
00313 
00314                 CL_ConnectionPacket msg = tcp_connection->receive();
00315                         
00316                 CL_InputSource_MemoryGeneric input(msg.data, msg.size, true);
00317                 switch (input.read_int32())
00318                 {
00319                 case Packet_NetChannel_AccessChange:
00320                         {
00321                                 CL_NetChannelQueue_Client *queue = create_queue(input.read_int32());
00322                                 queue->access = input.read_int32();
00323                                 access_queue.push(queue);
00324                                 trigger.set_flag();
00325                         }
00326                         break;
00327                 
00328                 case Packet_NetChannel_Message_ToClient:
00329                         {
00330                                 CL_NetChannelQueue_Client *queue = create_queue(input.read_int32());
00331                                 CL_NetMessage game_msg;
00332                                 int size = input.read_int32();
00333                                 char *data = new char[size];
00334                                 game_msg.from = server;
00335                                 input.read(data, size);
00336                                 game_msg.data.append(data, size);
00337                                 queue->push(game_msg);
00338                                 trigger.set_flag();
00339                         }
00340                         break;
00341 
00342                 default:
00343                         cl_info(info_network, "Network Protocol error!");
00344                         cl_assert(false);
00345                 }
00346         }
00347 }
00348 
00349 CL_NetChannelQueue_Client *CL_NetSession_Client::find_queue(int netchannel) const
00350 {
00351         CL_MutexSection mutex_section(mutex);
00352 
00353         // Note: This really should be a STL map, not a list. Too lazy to fix it now -- mbn.
00354         for (
00355                 std::list<CL_NetChannelQueue_Client*>::const_iterator it = netchannels.begin();
00356                 it != netchannels.end();
00357                 it++)
00358         {
00359                 if ((*it)->channel_id == netchannel) return *it;
00360         }
00361 
00362         return NULL;
00363 }
00364 
00365 CL_NetChannelQueue_Client *CL_NetSession_Client::create_queue(int netchannel)
00366 {
00367         CL_MutexSection mutex_section(mutex);
00368 
00369         CL_NetChannelQueue_Client *found = find_queue(netchannel);
00370         if (found != NULL) return found;
00371         
00372         CL_NetChannelQueue_Client *c = new CL_NetChannelQueue_Client;
00373         c->channel_id = netchannel;
00374         c->access = 0;
00375 
00376         netchannels.push_back(c);
00377 
00378         return c;
00379 }
00380 
00381 void CL_NetSession_Client::run()
00382 {
00383         while (exit_thread == false)
00384         {
00385                 keep_alive();
00386                 provider->wait_for_connection_data(mutex);
00387         }
00388 }
00389 
00390 void CL_NetSession_Client::check_trigger()
00391 {
00392         bool queues_empty = access_queue.empty();
00393 
00394         std::list<CL_NetChannelQueue_Client*>::iterator it;
00395         for (it = netchannels.begin(); it != netchannels.end(); it++)
00396         {
00397                 if (!(*it)->empty()) queues_empty = false;
00398         }
00399 
00400         if (queues_empty) trigger.reset();
00401 }
00402 
00404 // CL_NetComputer_Server
00405 
00406 CL_NetComputer_Server::CL_NetComputer_Server(CL_NetSession_Client *session)
00407 : CL_NetComputer_Generic(session)
00408 {
00409 }
00410 
00411 CL_NetComputer_Server::~CL_NetComputer_Server()
00412 {
00413 }
00414 
00415 unsigned long CL_NetComputer_Server::get_address() const
00416 {
00417 //      return get_session()->tcp_connection->get_address();
00418         return 0;
00419 }
00420 
00421 void CL_NetComputer_Server::disconnect()
00422 {
00423 //      get_session()->tcp_connection->disconnect();
00424 }
00425 
00426 CL_NetSession_Client *CL_NetComputer_Server::get_session()
00427 {
00428         return static_cast<CL_NetSession_Client*>(CL_NetComputer_Generic::get_session());
00429 }

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