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

network_delivery_socket.cpp

Go to the documentation of this file.
00001 /*
00002         $Id: network_delivery_socket.cpp,v 1.1 2001/02/15 13:18:52 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/cl_assert.h"
00021 #include <Network/Generic/network_delivery_impl.h>
00022 #include <Network/Generic/network_delivery_socket.h>
00023 
00024 #include <string.h>
00025 #include <errno.h>
00026 
00027 // ClanLib network magic. This magic is the first DWORD sent across a socket.
00028 // If the received DWORD doesn't match our magic, we can be sure it isn't a clanlib
00029 // networking application on that port.
00030 #define NETWORK_MAGIC 0x16042104
00031 
00032 /******************************************************************************
00033                          Unix Socket implementation
00034 ******************************************************************************/
00035 
00036 CL_UniformSocket::CL_UniformSocket(CL_ConnectionProvider *_provider)
00037 {
00038         provider = _provider;
00039         is_connection_lost = false;
00040         sock = CL_INVALID_SOCKET;
00041         send_pos = 0;
00042 
00043         recv_state = expect_magic;
00044         cur_message = NULL;
00045         cur_message_size = -1;
00046 }
00047 
00048 CL_UniformSocket::~CL_UniformSocket()
00049 {
00050         if (sock != CL_INVALID_SOCKET) closesocket(sock);
00051         provider->remove_connection(this);
00052 }
00053 
00054 bool CL_UniformSocket::read_avail()
00055 {
00056         fd_set rfds;
00057 
00058         FD_ZERO(&rfds);
00059         FD_SET(sock, &rfds);
00060 
00061         timeval timeout;
00062         memset(&timeout, 0, sizeof(timeval));
00063 
00064         int retval = select(sock+1, &rfds, NULL, NULL, &timeout);
00065         if (retval == -1 || retval == 0) 
00066         {
00067                 return false;
00068         }
00069 
00070         char buf[1024];
00071 
00072         int data_received = ::recv(
00073                 sock,
00074                 buf,
00075                 1024,
00076                 0);
00077 
00078         if (data_received == 0 || data_received == -1)
00079         {
00080                 is_connection_lost = true;
00081                 return false;
00082         }
00083         recv_buffer.append(buf, data_received);
00084 
00085         return true;
00086 }
00087 
00088 bool CL_UniformSocket::require_avail(unsigned int size)
00089 {
00090         return recv_buffer.size() >= size;
00091 }
00092 
00093 bool CL_UniformSocket::get_avail(void *buf, unsigned int size)
00094 {
00095         if (recv_buffer.size() < size) return false;
00096 
00097         memcpy(buf, recv_buffer.data(), size);
00098         recv_buffer.erase(0, size);
00099 
00100         return true;
00101 }
00102 
00103 bool CL_UniformSocket::init_socket(int init_socket)
00104 {
00105         static int sol_tcp = -1;
00106         if (sol_tcp == -1) sol_tcp = getprotobyname("tcp")->p_proto;
00107 
00108         if (init_socket != CL_INVALID_SOCKET)
00109         {
00110                 sock = init_socket;
00111 
00112         // set socket into non-blocking mode:
00113 #ifdef WIN32
00114                 u_long argp = 1;
00115                 ioctlsocket(sock, FIONBIO, &argp);
00116 #else
00117                 fcntl(sock, F_SETFL, O_NONBLOCK);
00118 #endif
00119 
00120                 int value = 1;
00121                 setsockopt(sock, sol_tcp, TCP_NODELAY, (const char *) &value, sizeof(int));
00122                 write_int(NETWORK_MAGIC);
00123         }
00124         else
00125         {
00126                 sock = socket(AF_INET, SOCK_STREAM, 0);
00127                 if (sock == CL_INVALID_SOCKET) return false;
00128 
00129         // set socket into non-blocking mode:
00130 #ifdef WIN32
00131                 u_long argp = 1;
00132                 ioctlsocket(sock, FIONBIO, &argp);
00133 #else
00134                 fcntl(sock, F_SETFL, O_NONBLOCK);
00135 #endif
00136 
00137                 int value = 1;
00138                 setsockopt(sock, sol_tcp, TCP_NODELAY, (const char *) &value, sizeof(int));
00139         }
00140 
00141         return true;
00142 }
00143 
00144 bool CL_UniformSocket::peek()
00145 {
00146         if (sock == CL_INVALID_SOCKET) return false;
00147 
00148         read_avail();
00149         send_avail();
00150 
00151         switch (recv_state)
00152         {
00153         case expect_magic:
00154                 {
00155                         int found_magic;
00156                         if (get_avail(&found_magic, sizeof(int)) == false) return false;
00157                         found_magic = ntohl(found_magic);
00158                         if (found_magic != NETWORK_MAGIC)
00159                         {
00160                                 is_connection_lost=true;
00161                         }
00162                         else recv_state = expect_packet_size;
00163                 }
00164 
00165         case expect_packet_size:
00166                 {
00167                         if (get_avail(&cur_message_size, sizeof(int)) == false) return false;
00168                         cur_message_size = ntohl(cur_message_size);
00169                         recv_state = expect_packet_data;
00170                 }
00171 
00172         case expect_packet_data:
00173                 {
00174                         if (!require_avail(cur_message_size)) return false;
00175                         cur_message = new char[cur_message_size];
00176                         get_avail(cur_message, cur_message_size);
00177                         recv_state = packet_finished;
00178                 }
00179 
00180         case packet_finished:
00181                 return true;
00182 
00183         default:
00184                 throw CL_Error("Network protocol error.");
00185                 return false;
00186         };
00187 
00188         return false;
00189 }
00190 
00191 CL_ConnectionPacket CL_UniformSocket::receive()
00192 {
00193         if (peek() == false)
00194         {
00195                 CL_ConnectionPacket ret;
00196                 ret.size = 0;
00197                 ret.data = NULL;
00198                 return ret;
00199         }
00200 
00201         CL_ConnectionPacket ret;
00202         ret.size = cur_message_size;
00203         ret.data = cur_message;
00204 
00205         recv_state = expect_packet_size;
00206 
00207         return ret;
00208 }
00209 
00210 void CL_UniformSocket::send(CL_ConnectionPacket message)
00211 {
00212         write_int(message.size);
00213         write_data(message.data, message.size);
00214 }
00215 
00216 bool CL_UniformSocket::connection_lost()
00217 {
00218         return is_connection_lost;
00219 }
00220 
00221 unsigned long CL_UniformSocket::read_int()
00222 {
00223         unsigned char data[4];
00224         int read = 0;
00225         while (read < 4)
00226         {
00227                 int val = recv(sock, (char *) data+read, 4-read, 0);
00228                 if (val == 0 || val == -1) 
00229                 {
00230                         is_connection_lost = true;
00231                         return 0;
00232                 }
00233 
00234                 read += val;
00235         }
00236 
00237         return ntohl(*((unsigned long *) data));
00238 }
00239 
00240 void CL_UniformSocket::write_int(unsigned long value)
00241 {
00242         unsigned long write_num = htonl(value);
00243 
00244         write_data(&write_num, sizeof(unsigned long));
00245 }
00246 
00247 void CL_UniformSocket::write_data(void *data, unsigned int size)
00248 {
00249         send_buffer.push(std::string((char *) data, size));
00250         send_avail();
00251 }
00252 #include <iostream>
00253 bool CL_UniformSocket::send_avail()
00254 {
00255         if (send_buffer.empty()) return true;
00256 
00257         std::string &buf = send_buffer.front();
00258         int size = buf.size();
00259         int res = ::send(sock, buf.data()+send_pos, size-send_pos, 0);
00260         if (res == CL_SOCKET_ERROR)
00261         {
00262 #ifdef WIN32
00263                 if (WSAGetLastError() == WSAEWOULDBLOCK) return false;
00264 #else
00265                 if (errno == EAGAIN) return false;
00266 #endif
00267         
00268                 cl_info_debug(info_network, PRINT_SOCK_ERROR());
00269                 is_connection_lost = true;
00270                 return true;
00271         }
00272 
00273         send_pos += res;
00274         if (send_pos  == size)
00275         {
00276                 send_buffer.pop();
00277                 send_pos = 0;
00278         }
00279 
00280         return send_buffer.empty();
00281 }
00282 
00283 bool CL_UniformSocket::try_connect(unsigned long remote_ip_network_format, int port)
00284 {
00285         sockaddr_in sock_addr;
00286         sock_addr.sin_family = AF_INET;
00287         sock_addr.sin_addr.s_addr = remote_ip_network_format;
00288         sock_addr.sin_port = htons(port);
00289 
00290         int res = ::connect(sock, (sockaddr *) &sock_addr, sizeof(sockaddr_in));
00291 
00292         fd_set fdfailure, fdwrite;
00293         FD_ZERO(&fdfailure);
00294         FD_ZERO(&fdwrite);
00295         FD_SET(sock, &fdfailure);
00296         FD_SET(sock, &fdwrite);
00297         res = ::select(sock+1, NULL, &fdwrite, &fdfailure, NULL);
00298         if (res > 0)
00299         {
00300                 if (FD_ISSET(sock, &fdfailure)) // connection failed
00301                 {
00302                         throw CL_Error("Connection refused");
00303                 }
00304 
00305                 write_int(NETWORK_MAGIC);
00306 
00307                 return true;
00308         }
00309         else 
00310         {
00311 //              cl_info_debug(info_network, PRINT_SOCK_ERROR());
00312                 throw CL_Error(PRINT_SOCK_ERROR());
00313                 return false;
00314         }
00315 }
00316 
00317 /******************************************************************************
00318                                         CL_UniformAcceptSocket implementation
00319 ******************************************************************************/
00320 
00321 CL_UniformAcceptSocket::CL_UniformAcceptSocket(CL_ConnectionProvider *provider)
00322 : CL_UniformSocket(provider)
00323 {
00324         port = -1;
00325 }
00326 
00327 CL_UniformAcceptSocket::~CL_UniformAcceptSocket()
00328 {
00329 }
00330 
00331 bool CL_UniformAcceptSocket::bind(int _port)
00332 {
00333         if (!init_socket()) return false;
00334 
00335         sockaddr_in addr;
00336         addr.sin_family = AF_INET;
00337         addr.sin_addr.s_addr = INADDR_ANY;
00338         addr.sin_port = htons(_port);
00339 
00340         // Bind the socket to the specified port
00341         int err = ::bind(sock, (sockaddr *) &addr, sizeof(sockaddr_in));        
00342         if (err == CL_SOCKET_ERROR) throw CL_Error(PRINT_SOCK_ERROR());
00343 
00344         // Call getsockname to determine allocated port-number,
00345         // since socket might have been created with _port==0 (any)
00346         socklen_t len = sizeof(sockaddr_in);
00347         err = getsockname(sock, (sockaddr *) &addr, &len);
00348         if (err == CL_SOCKET_ERROR) throw CL_Error(PRINT_SOCK_ERROR());
00349 
00350         port = ntohs(addr.sin_port);
00351         
00352         // Make the socket listen for incoming connection attempts
00353         err = listen(sock, 64);
00354         if (err == CL_SOCKET_ERROR) throw CL_Error(PRINT_SOCK_ERROR());
00355 
00356         return true;
00357 }
00358 
00359 bool CL_UniformAcceptSocket::peek()
00360 {
00361         fd_set rfds;
00362 
00363         FD_ZERO(&rfds);
00364         FD_SET(sock, &rfds);
00365 
00366         timeval timeout;
00367         memset(&timeout, 0, sizeof(timeval));
00368 
00369         int retval = select(sock+1, &rfds, NULL, NULL, &timeout);
00370         cl_assert(retval != -1);
00371 
00372         if (retval == 0) return false;
00373         else return true;
00374 }
00375 
00376 CL_UniformSocket *CL_UniformAcceptSocket::accept()
00377 {
00378         fd_set rfds;
00379         FD_ZERO(&rfds);
00380         FD_SET(sock, &rfds);
00381 
00382         timeval timeout;
00383         memset(&timeout, 0, sizeof(timeval));
00384 
00385         int retval = select(sock+1, &rfds, NULL, NULL, &timeout);
00386         if (retval == -1 || retval == 0) 
00387         {
00388                 return NULL;
00389         }
00390 
00391         int res_sock = ::accept(sock, NULL, NULL);
00392         cl_assert(res_sock != CL_INVALID_SOCKET);
00393 
00394         CL_UniformSocket *ret = new CL_UniformSocket(provider);
00395         ret->init_socket(res_sock);
00396 
00397         return ret;
00398 }
00399 
00400 bool CL_UniformAcceptSocket::try_connect(unsigned long remote_ip_network_format, int port)
00401 {
00402         cl_assert(false);
00403 
00404         return false;
00405 }
00406 
00407 CL_ConnectionPacket CL_UniformAcceptSocket::receive()
00408 {
00409         cl_assert(false);
00410         CL_ConnectionPacket ret;
00411         return ret;
00412 }
00413 
00414 void CL_UniformAcceptSocket::send(CL_ConnectionPacket message)
00415 {
00416         cl_assert(false);
00417 }
00418 
00419 bool CL_UniformAcceptSocket::connection_lost()
00420 {
00421         cl_assert(false);
00422         return false;
00423 }
00424 
00425 /******************************************************************************
00426                                         CL_UniformUDPConnection implementation
00427 ******************************************************************************/
00428 
00429 CL_UniformUDPConnection::CL_UniformUDPConnection()
00430 {
00431         sock = CL_INVALID_SOCKET;
00432         port = -1;
00433 }
00434 
00435 CL_UniformUDPConnection::~CL_UniformUDPConnection()
00436 {
00437         if (sock != CL_INVALID_SOCKET) closesocket(sock);
00438 }
00439 
00440 bool CL_UniformUDPConnection::bind(unsigned int _port)
00441 {
00442         int res;
00443 
00444         sock = socket(AF_INET, SOCK_DGRAM, 0);
00445         if (sock == CL_INVALID_SOCKET) return false;
00446 
00447         sockaddr_in addr;
00448         memset(&addr, 0, sizeof(sockaddr_in));
00449         addr.sin_family = AF_INET;
00450         addr.sin_addr.s_addr = INADDR_ANY;
00451         addr.sin_port = htons(_port);
00452 
00453         res = ::bind(sock, (sockaddr *) &addr, sizeof(addr));
00454         if (res == -1) throw CL_Error(PRINT_SOCK_ERROR());
00455 
00456         int enable = 1;
00457         res = setsockopt(
00458                 sock,
00459                 SOL_SOCKET,
00460                 SO_BROADCAST,
00461                 (const char *) &enable,
00462                 sizeof(int));
00463 
00464         if (res == -1)
00465         {
00466                 cl_info(info_network, PRINT_SOCK_ERROR());
00467                 closesocket(sock);
00468                 return false;
00469         }
00470 
00471         // Call getsockname to determine allocated port-number,
00472         // since socket might have been created with _port==0 (any)
00473         socklen_t len = sizeof(sockaddr_in);
00474         res = getsockname(sock, (sockaddr *) &addr, &len);
00475         if (res == -1) throw CL_Error(PRINT_SOCK_ERROR());
00476 
00477         port = ntohs(addr.sin_port);
00478 
00479         return true;
00480 }
00481 
00482 bool CL_UniformUDPConnection::peek()
00483 {
00484         if (sock == CL_INVALID_SOCKET) return false;
00485 
00486         fd_set rfds;
00487 
00488         FD_ZERO(&rfds);
00489         FD_SET(sock, &rfds);
00490 
00491         timeval timeout;
00492         memset(&timeout, 0, sizeof(timeval));
00493 
00494         int retval = select(sock+1, &rfds, NULL, NULL, &timeout);
00495         if (retval == -1) return false;
00496 
00497         return (retval > 0);
00498 }
00499 
00500 CL_UDPConnectionPacket CL_UniformUDPConnection::receive()
00501 {
00502         char *receive_buf = new char[8096];
00503 
00504         sockaddr_in addr;
00505         memset(&addr, 0, sizeof(sockaddr_in));
00506         addr.sin_family = AF_INET;
00507         socklen_t len_addr = sizeof(addr);
00508         int res = ::recvfrom(sock, receive_buf, 8096, 0, (sockaddr *) &addr, &len_addr);
00509         cl_assert(res != CL_SOCKET_ERROR);
00510 
00511         CL_UDPConnectionPacket ret;
00512         ret.data = receive_buf;
00513         ret.size = res;
00514         ret.ip_addr = addr.sin_addr.s_addr;
00515         ret.port = ntohs(addr.sin_port);
00516 
00517         return ret;
00518 }
00519 
00520 void CL_UniformUDPConnection::send(CL_UDPConnectionPacket message)
00521 {
00522         sockaddr_in addr;
00523         memset(&addr, 0, sizeof(sockaddr_in));
00524         addr.sin_family = AF_INET;
00525         addr.sin_addr.s_addr = message.ip_addr;
00526         addr.sin_port = htons(message.port);
00527 
00528         cl_assert(sock != CL_INVALID_SOCKET);
00529         cl_assert(message.size < 2000);
00530 
00531         int res = ::sendto(
00532                 sock,
00533                 (char *) message.data,
00534                 message.size,
00535                 0,
00536                 (sockaddr *) &addr,
00537                 sizeof(sockaddr_in));
00538 
00539         if (res == CL_SOCKET_ERROR)
00540         {
00541                 cl_info(info_network, PRINT_SOCK_ERROR());
00542         }
00543 
00544         cl_assert(res != -1);
00545 }
00546 
00547 void CL_UniformUDPConnection::broadcast(CL_UDPConnectionPacket message)
00548 {
00549         cl_assert(sock != CL_INVALID_SOCKET);
00550         cl_assert(message.size < 2000);
00551 
00552         sockaddr_in addr;
00553         memset(&addr, 0, sizeof(sockaddr_in));
00554         addr.sin_family = AF_INET;
00555         addr.sin_addr.s_addr = INADDR_BROADCAST;
00556         addr.sin_port = htons(message.port);
00557 
00558         int res = ::sendto(
00559                 sock,
00560                 (char *) message.data,
00561                 message.size,
00562                 0,
00563                 (sockaddr *) &addr,
00564                 sizeof(sockaddr_in));
00565                 
00566         if (res == -1)
00567         {
00568                 cl_info(info_network, PRINT_SOCK_ERROR());
00569         }
00570 
00571         cl_assert(res != -1);
00572 }
00573 
00574 unsigned int CL_UniformUDPConnection::get_port()
00575 {
00576         return port;
00577 }
00578 
00579 // error messages under win32 are hell as usual:
00580 
00581 #ifdef WIN32
00582 const char *get_win32_sock_error(DWORD err)
00583 {
00584         switch (err)
00585         {
00586         case WSAEACCES: return "Permission denied";
00587         case WSAEADDRINUSE: return "Address already in use";
00588         case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
00589         case WSAEAFNOSUPPORT: return "Address family not supported by protocol family";
00590         case WSAEALREADY: return "Operation already in progress";
00591         case WSAECONNABORTED: return "Software caused connection abort";
00592         case WSAECONNREFUSED: return "Connection refused";
00593         case WSAECONNRESET: return "Connection reset by peer";
00594         case WSAEDESTADDRREQ: return "Destination address required";
00595         case WSAEFAULT: return "Bad address";
00596         case WSAEHOSTDOWN: return "Host is down";
00597         case WSAEHOSTUNREACH: return "No route to host";
00598         case WSAEINPROGRESS: return "Operation now in progress";
00599         case WSAEINTR: return "Interrupted function call";
00600         case WSAEINVAL: return "Invalid argument";
00601         case WSAEISCONN: return "Socket is already connected";
00602         case WSAEMFILE: return "Too many open files";
00603         case WSAEMSGSIZE: return "Message too long";
00604         case WSAENETDOWN: return "Network is down";
00605         case WSAENETRESET: return "Network dropped connection on reset";
00606         case WSAENETUNREACH: return "Network is unreachable";
00607         case WSAENOBUFS: return "No buffer space available";
00608         case WSAENOPROTOOPT: return "Bad protocol option";
00609         case WSAENOTCONN: return "Socket is not connected";
00610         case WSAENOTSOCK: return "Socket operation on non-socket";
00611         case WSAEOPNOTSUPP: return "Operation not supported";
00612         case WSAEPFNOSUPPORT: return "Protocol family not supported";
00613         case WSAEPROCLIM: return "Too many processes";
00614         case WSAEPROTONOSUPPORT: return "Protocol not supported";
00615         case WSAEPROTOTYPE : return "Protocol wrong type for socket";
00616         case WSAESHUTDOWN: return "Cannot send after socket shutdown";
00617         case WSAESOCKTNOSUPPORT: return "Socket type not supported";
00618         case WSAETIMEDOUT: return "Connection timed out";
00619 //      case WSATYPE_NOT_FOUND: return "Class type not found";
00620         case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
00621 //      case WSAHOST_NOT_FOUND: return "Host not found";
00622         case WSANOTINITIALISED: return "Successful WSAStartup not yet performed";
00623         case WSANO_DATA: return "Valid name, no data record of requested type";
00624         case WSANO_RECOVERY: return "This is a non-recoverable error";
00625         case WSASYSNOTREADY: return "Network subsystem is unavailable";
00626         case WSATRY_AGAIN: return "Non-authoritative host not found";
00627         case WSAVERNOTSUPPORTED: return "WINSOCK.DLL version out of range";
00628         case WSAEDISCON: return "Graceful shutdown in progress";
00629         default: return "Unknown WSA error";
00630         };
00631 
00632 /*
00633         static char err_buffer[16*1024];
00634         FormatMessage(
00635                 FORMAT_MESSAGE_FROM_SYSTEM,
00636                 NULL,
00637                 GetLastError(),
00638                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00639                 err_buffer,
00640                 16*1024,
00641                 NULL);
00642 
00643         return err_buffer;
00644 */
00645 }
00646 #endif

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