int NetClient::authenticate()
{
    COUT<<" enter "<<__PRETTY_FUNCTION__<<endl;

    Packet    packet2;
    string    str_callsign, str_passwd;
    NetBuffer netbuf;

    //Get the name and password from vegastrike.config
    //Maybe someday use a default Guest account if no callsign or password is provided thus allowing
    //Player to wander but not interact with the universe
    this->callsign = str_callsign = vs_config->getVariable( "player", "callsign", "" );
    this->password = str_passwd = vs_config->getVariable( "player", "password", "" );
    if ( global_username.length() )
        this->callsign = global_username;
    if ( global_password.length() )
        this->password = global_password;
    if ( str_callsign.length() && str_passwd.length() ) {
        netbuf.addString( str_callsign );
        netbuf.addString( str_passwd );

        packet2.send( CMD_LOGIN, 0,
                     netbuf.getData(), netbuf.getDataLength(),
                     SENDRELIABLE, NULL, *this->clt_tcp_sock,
                     __FILE__, PSEUDO__LINE__( 165 ) );
        COUT<<"Send login for player <"<<str_callsign<<">:<*******"
        "> - buffer length : "<<packet2.getDataLength()
            <<" (+"<<packet2.getHeaderLength()<<" header len"<<endl;
    } else {
        cerr<<"Callsign and/or password not specified in vegastrike.config, please check this."<<endl<<endl;
        return -1;
    }
    return 0;
}
int NetClient::loginAuth( string str_callsign, string str_passwd, string &error )
{
    COUT<<"enter "<<"NetClient::loginLoop"<<endl;
    lastsave.clear();
    ship_select_list.clear();

    Packet    packet2;
    NetBuffer netbuf;

    //memset( buffer, 0, tmplen+1);
    netbuf.addString( str_callsign );
    netbuf.addString( str_passwd );

    packet2.send( CMD_LOGIN, 0,
                 netbuf.getData(), netbuf.getDataLength(),
                 SENDRELIABLE, NULL, *this->clt_tcp_sock,
                 __FILE__, PSEUDO__LINE__( 316 ) );
    COUT<<"Sent login for player <"<<str_callsign<<">:<*******"
        <<">"<<endl
        <<"   - buffer length : "<<packet2.getDataLength()<<endl;
    this->callsign = str_callsign;
    this->password = str_passwd;
    //Now the loop
    return loginLoop( error );
}
void NetClient::respawnRequest()
{
    Packet    packet2;
    NetBuffer netbuf;
    //No data.
    packet2.send( CMD_RESPAWN, 0,
                 netbuf.getData(), netbuf.getDataLength(),
                 SENDRELIABLE, NULL, *this->clt_tcp_sock,
                 __FILE__, PSEUDO__LINE__( 165 ) );
}
void NetClient::textMessage( const std::string &data )
{
    Packet    packet2;
    NetBuffer netbuf;
    netbuf.addString( data );
    //No data.
    packet2.send( CMD_TXTMESSAGE, 0,
                 netbuf.getData(), netbuf.getDataLength(),
                 SENDRELIABLE, NULL, *this->clt_tcp_sock,
                 __FILE__, PSEUDO__LINE__( 165 ) );
}
/*
 ************************************************************
 **** Create a new character                              ***
 ************************************************************
 */
bool NetClient::selectShip( unsigned int ship )
{
    if (lastsave.empty() || lastsave[0] == "") {
        NetBuffer netbuf;
        string    shipname;
        netbuf.addShort( (unsigned short) ship );
        if ( ship < ship_select_list.size() )
            shipname = ship_select_list[ship];
        netbuf.addString( shipname );
        Packet p;
        p.send( CMD_CHOOSESHIP, 0, netbuf.getData(), netbuf.getDataLength(), SENDRELIABLE,
               NULL, *clt_tcp_sock, __FILE__, PSEUDO__LINE__( 628 ) );
        string err;
        int    ret = loginLoop( err );
        if (ret != 1 || lastsave.size() < 2 || lastsave[0] == "") {
            cout<<"Error in CHOOSEHIP: "<<err
                <<"choice="<<ship<<"("<<shipname<<"), max="<<ret<<endl;
            return false;
        }
    }
    return true;
}
void NetClient::synchronizeTime( SOCKETALT *udpsock )
{
    int            i  = 0;
    int            timeout = 0;
    int            recv;
    timeval        tv = {1, 0};   //Timeout after 1 second, request send again.
    double         ping; //use deltaTime?
    double         pingavg           = 0.;
    double         timeavg           = 0.;
    std::map< double, double >times;     //sorted container.
    double         initialTime       = queryTime();
    static int     NUM_TIMES         = XMLSupport::parse_int( vs_config->getVariable( "network", "servertime_calibration", "10" ) );
    static int     UDP_TIMEOUT       = XMLSupport::parse_int( vs_config->getVariable( "network", "udp_timeout", "1" ) );
    static int     clt_port_read     = XMLSupport::parse_int( vs_config->getVariable( "network", "udp_listen_port", "6778" ) );
    if (clt_port_read > 65535 || clt_port_read <= 0)
        clt_port_read = 0;
    static int     clt_port_read_max = XMLSupport::parse_int( vs_config->getVariable( "network", "udp_listen_port_max", "6778" ) );
    if (clt_port_read_max > 65535 || clt_port_read_max <= 0)
        clt_port_read_max = clt_port_read;
    unsigned short clt_port          = (unsigned short) clt_port_read;
    unsigned short clt_port_max      = (unsigned short) clt_port_read_max;
    if (clt_port_max < clt_port)
        clt_port_max = clt_port;
    static string  nettransport      = vs_config->getVariable( "network", "transport", "udp" );

    //std::string addr;
    unsigned short port = this->_serverport;
    //getConfigServerAddress(addr, port);
    if ( !( udpsock != NULL && udpsock->setRemoteAddress( NetUIBase::lookupHost( this->_serverip.c_str(), port ) ) ) ) {
        do
            *this->clt_udp_sock = NetUIUDP::createSocket( this->_serverip.c_str(), port, clt_port, _sock_set );
        while ( ( !this->clt_udp_sock->valid() ) && (clt_port++) );
    } else {
        this->clt_udp_sock = udpsock;
    }
    COUT<<"created UDP socket ("<<this->_serverip<<","<<port<<", listen on "<<clt_port<<") -> "<<this->clt_udp_sock<<endl;
    if (nettransport == "udp") {
        //NETFIXME:  Keep trying ports until a connection is established.
        COUT<<"Default lossy transport configured to UDP."<<endl;
        this->lossy_socket = clt_udp_sock;
    } else {
        COUT<<"Default lossy transport configured to TCP (behind firewall)."<<endl;
        this->lossy_socket = clt_tcp_sock;
        clt_port = 0;
    }
    this->clt_tcp_sock->set_block();
    this->clt_udp_sock->set_block();
    //Wait for NUM_TIMES (10) successful tries, or 10 consecutive 1-second timeouts
    //(we use UDP on the response (SENDANDFORGET) to improve timing accuracy).
    while (i < NUM_TIMES && timeout < UDP_TIMEOUT) {
        Packet    packet;
        NetBuffer outData;
        outData.addShort( clt_port );
        packet.send( CMD_SERVERTIME, 0,
                    outData.getData(), outData.getDataLength(),                      //No data.
                    SENDRELIABLE, NULL, *this->clt_tcp_sock,
                    __FILE__, PSEUDO__LINE__( 343 ) );
        recv = this->recvMsg( &packet, &tv );
        //If we have no response.
        if (recv <= 0) {
            COUT<<"synchronizeTime() Timed out"<<endl;
            ++timeout;
            if (timeout >= UDP_TIMEOUT) {
                if (this->lossy_socket->isTcp() == false) {
                    if (clt_port < clt_port_max && !udpsock) {
                        NetUIUDP::disconnectSaveUDP( *this->clt_udp_sock );
                        *this->clt_udp_sock = NetUIUDP::createSocket( this->_serverip.c_str(), port, clt_port, _sock_set );
                        clt_port++;
                        COUT<<"Trying UDP port "<<clt_port<<"."<<endl;
                    } else {
                        //no UDP requests made it, fallback to TCP.
                        this->lossy_socket = this->clt_tcp_sock;
                        clt_port = 0;
                        COUT<<"Setting default lossy transport to TCP (UDP timeout)."<<endl;
                    }
                    timeout = 0;
                }
            }
        } else if (packet.getCommand() == CMD_SERVERTIME) {
            //NETFIXME: obtain actual ping time
            //ping = getPingTime( &tv );
            ping = exp( vsrandom.uniformInc( -10, 0 ) );
            if (ping > 0 && ping < 1.) {
                ++i;
                NetBuffer data( packet.getData(), packet.getDataLength() );
                double    serverTime  = data.getDouble();
                double    currentTime = queryTime();
                serverTime += initialTime-currentTime;
                times.insert( std::multimap< double, double >::value_type( ping, serverTime-ping ) );
                timeout     = 0;
            } else {
                ++timeout;
            }
        }
    }
    this->clt_tcp_sock->set_nonblock();
    this->clt_udp_sock->set_nonblock();
//std::sort(times[0], times[i]);
    if (i >= NUM_TIMES) {
        int    mid      = i/2;
        double median   = 0.;
        double tot      = 0.;
        int    location = 0;
        std::map< double, double >::const_iterator iter;
        for (iter = times.begin(); iter != times.end(); ++iter) {
            if (location == mid) {
                median = iter->first;
                if (i%2 == 1) {
                    ++iter;
                    median += iter->first;
                }
                break;
            }
            ++location;
        }
        if (i%2 == 1)
            median /= 2;
        for (iter = times.begin(); iter != times.end(); ++iter) {
            double wdiff = exp( -10*(median-iter->first)*(median-iter->first) );
            pingavg += wdiff*iter->first;
            timeavg += wdiff*iter->second;
            tot     += wdiff;
        }
        pingavg /= tot;
        timeavg /= tot;
    } else {
        COUT<<"Error in time synchronization: connection ended or timed out.";
    }
    this->deltatime = pingavg;
    double newTime = timeavg+queryTime()-initialTime;
    COUT<<"Setting time to: New time: "<<newTime<<endl;
    setNewTime( newTime );
    for (unsigned int cpnum = 0; cpnum < _Universe->numPlayers(); cpnum++)
        //Seems like a bad idea... shouldn't this rely on SIMULATION_ATOM?
        _Universe->AccessCockpit( cpnum )->TimeOfLastCollision = -200;
    cur_time = newTime;
}
void NetServer::sendLoginAccept( ClientPtr clt, Cockpit *cp )
{
    COUT<<"enter "<<__PRETTY_FUNCTION__<<endl;
    //Verify that client already has a character
    NetBuffer netbuf;
    Unit     *un = cp->GetParent();
    if (!un) {
        sendLoginError( clt );
        return;
    }
    //Put the save parts in buffers in order to load them properly
    netbuf.Reset();

    string datestr = _Universe->current_stardate.GetFullTrekDate();
    netbuf.addString( datestr );
    netbuf.addString( clt->savegame[0] );
    netbuf.addString( clt->savegame[1] );

    Packet    packet2;

    //Create a cockpit for the player and parse its savegame
    ObjSerial cltserial = un->GetSerial();

    COUT<<">>> SEND LOGIN ACCEPT =( serial #"<<cltserial<<" )= --------------------------------------"<<endl;
    COUT<<"SAVE="<<clt->savegame[0].length()<<" bytes - XML="<<clt->savegame[1].length()<<" bytes"<<endl;
    cerr<<"SENDING STARDATE : "<<datestr<<endl;
    //Add the initial star system filename + hash if crypto++ support too
    string sysname = cp->savegame->GetStarSystem();
    string relsys  = sysname+".system";
    netbuf.addString( relsys );

    //Generate the starsystem before addclient so that it already contains serials
    StarSystem    *sts    = zonemgr->addZone( sysname );

#ifdef CRYPTO
    unsigned char *digest = new unsigned char[FileUtil::Hash.DigestSize()];
    string sysxml;
    if ( !( sysxml = zonemgr->getSystem( relsys ) ).empty() )
        FileUtil::HashStringCompute( sysxml, digest );
    else if ( !sysname.empty() )
        FileUtil::HashFileCompute( relsys, digest, SystemFile );
    netbuf.addShort( FileUtil::Hash.DigestSize() );
    netbuf.addBuffer( digest, FileUtil::Hash.DigestSize() );
    delete[] digest;
#else
    netbuf.addShort( 0 );
#endif

    int zoneid = _Universe->StarSystemIndex( sts );
    netbuf.addShort( zoneid );

    //Add system string to packet...
    //Long, I know, but is there any other way to keep all the proper graphics-related data that the server discards?
    //netbuf.addString( zonemgr->getSystem(sysname) );

    packet2.send( LOGIN_ACCEPT, cltserial, netbuf.getData(),
                 netbuf.getDataLength(), SENDRELIABLE, &clt->cltadr, clt->tcp_sock, __FILE__, PSEUDO__LINE__( 241 ) );
    //Now that we have a starsystem, we will want to make a mission.
    if (Mission::getNthPlayerMission( _Universe->whichPlayerStarship( un ), 0 ) == NULL) {
        if (active_missions.size() == 1)
            active_missions[0]->DirectorInitgame();
        //Make a mission specially for this cockpit.
        unsigned int oldcp = _Universe->CurrentCockpit();
        _Universe->SetActiveCockpit( cp );
        _Universe->pushActiveStarSystem( _Universe->AccessCockpit()->activeStarSystem );
        LoadMission( "", vs_config->getVariable( "server", "serverscript", "import server;my_obj=server.player()" ), false );
        _Universe->popActiveStarSystem();
        _Universe->SetActiveCockpit( oldcp );
    }
}