summaryrefslogblamecommitdiff
path: root/src/net/sdltcpnet.cpp
blob: 182263ee54e0b33e8f78e45240e0d52620d99ef7 (plain) (tree)
1
2
3

                       
                                                    
















                                                                         
                   
 
                                        
 
                       

                                         

                       
                      
                                               


                        




                                       
                                                
 
                                               
 

                                                          
                          
                                   
 

                  


                                           
                                                                     
                          
 

                                





                            


                                                
 









                   
                                                     



                             

                                                                   



                                            
                              



                             
                                                                         
                                          



                                                   
                                                
 
                                                    
                                 

                                           

                   
                                       
                                                            











                                                                        
                                                                           
                 
                                   



                                                          
                                                                  
                 
                          


             


                                                
                

 
                                                              



                                             
                                                                             



                                           

                                                  

                                                              
                                    
                                       

 
                                                                           



                                             
                                                                               



                                               
                                                                             



                                           
                                                       


                              




                                                        
/*
 *  The ManaPlus Client
 *  Copyright (C) 2013-2017  The ManaPlus Developers
 *
 *  This file is part of The ManaPlus Client.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "logger.h"

#if defined __linux__ || defined __linux

#include <sys/socket.h>

#if defined(M_TCPOK) && !defined(ANDROID)
#include <netinet/in.h>
#include <netdb.h>
#include <linux/tcp.h>
#else  // defined(M_TCPOK) && !defined(ANDROID)
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <netinet/tcp.h>
// Use linear timeouts for thin streams
#define TCP_THIN_LINEAR_TIMEOUTS 16
// Fast retrans. after 1 dupack
#define TCP_THIN_DUPACK          17
#endif  // defined(M_TCPOK) && !defined(ANDROID)

#endif  // defined __linux__ || defined __linux

PRAGMACLANG6GCC(GCC diagnostic push)
PRAGMACLANG6GCC(GCC diagnostic ignored "-Wold-style-cast")
#include "net/sdltcpnet.h"
PRAGMACLANG6GCC(GCC diagnostic pop)

#include "debug.h"

#if !defined(__native_client__) \
    && (defined(TCP_THIN_LINEAR_TIMEOUTS) \
    || defined(TCP_THIN_DUPACK))
// because actual struct is hidden in SDL_net we reinroducing it here
struct TCPsocketHack final
{
    A_DELETE_COPY(TCPsocketHack)

    int ready;
    int channel;
    IPaddress remoteAddress;
    IPaddress localAddress;
    int sflag;
};
#endif  // !defined(__native_client__)
        // && (defined(TCP_THIN_LINEAR_TIMEOUTS)
        // || defined(TCP_THIN_DUPACK))

void TcpNet::init()
{
    SDLNet_Init();
}

void TcpNet::quit()
{
    SDLNet_Quit();
}

void TcpNet::closeSocket(const TcpNet::Socket socket)
{
    SDLNet_TCP_Close(socket);
}

int TcpNet::send(const TcpNet::Socket sock, const void *const data,
                 const int len)
{
    return SDLNet_TCP_Send(sock, data, len);
}

const char *TcpNet::getError()
{
    return SDLNet_GetError();
}

int TcpNet::resolveHost(IPaddress *const address, const char *const host,
                        const Uint16 port)
{
    return SDLNet_ResolveHost(address, host, port);
}

TcpNet::Socket TcpNet::open(IPaddress *const ip)
{
    const TcpNet::Socket sock = SDLNet_TCP_Open(ip);
#if !defined(__native_client__) \
    && (defined(TCP_THIN_LINEAR_TIMEOUTS) \
    || defined(TCP_THIN_DUPACK))
    if (sock && ip)
    {
        const TCPsocketHack *const hack
            = reinterpret_cast<const TCPsocketHack *>(sock);
        // here we using some magic to compare TCPsocket and own padding
        // because actual struct TCPsocket not in headers
        if (hack)
        {
            const IPaddress &addr = hack->remoteAddress;
            if (addr.host == ip->host && addr.port == ip->port)
            {
                const int val = 1;
#ifdef TCP_THIN_LINEAR_TIMEOUTS
                if (setsockopt(hack->channel, IPPROTO_TCP,
                    TCP_THIN_LINEAR_TIMEOUTS, &val, sizeof(val)))
                {
                    logger->log_r("error on set TCP_THIN_LINEAR_TIMEOUTS");
                }
#endif  // TCP_THIN_LINEAR_TIMEOUTS
#ifdef TCP_THIN_DUPACK
                if (setsockopt(hack->channel, IPPROTO_TCP,
                    TCP_THIN_DUPACK, &val, sizeof(val)))
                {
                    logger->log_r("error on set TCP_THIN_DUPACK");
                }
#endif  // TCP_THIN_DUPACK
            }
        }
    }
#endif  // !defined(__native_client__)
        // && (defined(TCP_THIN_LINEAR_TIMEOUTS)
        // || defined(TCP_THIN_DUPACK))
    return sock;
}

TcpNet::SocketSet TcpNet::allocSocketSet(const int maxsockets)
{
    return SDLNet_AllocSocketSet(maxsockets);
}

int TcpNet::addSocket(const TcpNet::SocketSet set, const TcpNet::Socket sock)
{
    return SDLNet_TCP_AddSocket(set, sock);
}

int TcpNet::socketReady(const TcpNet::Socket sock)
{
    PRAGMACLANG6GCC(GCC diagnostic push)
    PRAGMACLANG6GCC(GCC diagnostic ignored "-Wold-style-cast")
    return SDLNet_SocketReady(sock);
    PRAGMACLANG6GCC(GCC diagnostic pop)
}

int TcpNet::checkSockets(const TcpNet::SocketSet set, const Uint32 timeout)
{
    return SDLNet_CheckSockets(set, timeout);
}

int TcpNet::recv(const TcpNet::Socket sock, void *const data, const int maxlen)
{
    return SDLNet_TCP_Recv(sock, data, maxlen);
}

int TcpNet::delSocket(const TcpNet::SocketSet set, const TcpNet::Socket sock)
{
    return SDLNet_TCP_DelSocket(set, sock);
}

void TcpNet::freeSocketSet(const TcpNet::SocketSet set)
{
    SDLNet_FreeSocketSet(set);
}

TcpNet::Socket TcpNet::accept(const TcpNet::Socket sock)
{
    return SDLNet_TCP_Accept(sock);
}