<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <asio.hpp>

#include <cstring>
#include <cstdlib>
#include <iostream>
#include <vector>

#include "antenna.hxx"
#include "tuner.hxx"
#include "io.hxx"
#include "packet_processor.hxx"
#include "abuhops.hxx"

using namespace std;

namespace abuhops {
  #define MIN_TIME_BETWEEN_WHOAMI 1024
  #define MAX_TIME_BETWEEN_WHOAMI 4096
  #define MIN_TIME_BETWEEN_PING 16384
  #define MAX_TIME_BETWEEN_PING 32768
  #define TIME_BETWEEN_CONNECT 1024
  #define MAX_CONNECT_ATTEMPTS 16

  #define CONNECT 0
  #define PING 1
  #define PROXY 2
  #define POST 3
  #define LIST 4
  #define SIGN 5
  #define BYE 6

  #define YOUARE 0
  #define PONG 1
  #define FROMOTHER 2
  #define ADVERT 3
  #define SIGNATURE 5

  #define IPV4PORT 12545
  #define IPV6PORT 12546
  #define SERVER "ABENDSTERN.SERVEGAME.COM."

  #define HMAC_SIZE 32
  #define MAX_NAME_LENGTH 128

  #ifdef DEBUG
  #define debug(x) cout << "abuhops: " << x << endl;
  #else
  #define debug(x)
  #endif

  static unsigned timeUntilPing = 0;

  static bool isConnected4 = false,  isConnected6 = false, isConnecting = true;
  static unsigned timeUntilConnectXmit = 0;
  static byte connectPacket[1+4+4+HMAC_SIZE+MAX_NAME_LENGTH+1];
  static unsigned connectPacketSize;
  static unsigned connectionAttempts = 0;

  static bool knowIpv4Address = false, knowIpv6Address = false;

  static Antenna::endpoint server4, server6;
  static bool hasv4 = false, hasv6 = false;
  static bool hasInit = false;

  static void sendConnectPacket();
  static void processPacket(bool v6, const byte* data, unsigned len);

  void connect(unsigned id, const char* name,
               unsigned timestamp, const char* hmac) {
    debug(">> CONNECT");
    if (!hasInit) {
      hasInit = true;

      try {
        //Look server IP address up
        asio::io_service svc;
        asio::ip::udp::resolver resolver(svc);
        asio::ip::udp::resolver::query query(SERVER, "0");
        asio::ip::udp::resolver::iterator it(resolver.resolve(query)), end;
        while (it != end && (!hasv4 || !hasv6)) {
          asio::ip::address addr(it++->endpoint().address());
          if (addr.is_v4() && !hasv4) {
            hasv4 = true;
            server4 = Antenna::endpoint(addr, IPV4PORT);
            cout << "Resolved " << SERVER << " ipv4 to " << addr.to_string()
                 << endl;
          } else if (addr.is_v6() && !hasv6) {
            hasv6 = true;
            server6 = Antenna::endpoint(addr, IPV6PORT);
            cout << "Resolved " << SERVER << " ipv6 to " << addr.to_string()
                 << endl;
          }
        }
      } catch (const asio::system_error& err) {
        cerr << "Error resolving " << SERVER << ": " << err.what() << endl;
      }

      //Even if we did get a result for a certain protocol, we can't use it
      //if it is not available
      hasv4 &= antenna.hasV4();
      hasv6 &= antenna.hasV6();

      ensureRegistered();
    }

    //Set initial conditions
    isConnected4 = isConnected6 = false;
    isConnecting = true;
    timeUntilConnectXmit = 0;
    connectionAttempts = 0;

    //Write the connection packet
    byte* pack = connectPacket;
    *pack++ = CONNECT;
    io::write(pack, id);
    io::write(pack, timestamp);
    //Convert HMAC from hex
    for (unsigned i = 0; i < HMAC_SIZE; ++i) {
#define HEXIT(x) (x >= '0' && x <= '9'? x-'0' : \
                  x >= 'a' && x <= 'f'? x-'a'+0xa : x-'A'+0xA)
      *pack++ = (HEXIT(hmac[2*i])<<4) | HEXIT(hmac[2*i+1]);
#undef HEXIT
    }
    //Copy name into packet.
    strncpy((char*)pack, name, MAX_NAME_LENGTH);
    pack[MAX_NAME_LENGTH] = 0;

    //Set packet size
    connectPacketSize = (pack - connectPacket) + strlen(name)+1;

    //Done, send the first packet immediately
    sendConnectPacket();
  }

  static void sendConnectPacket() {
    debug(">> CONNECT (send)");
    if (hasv4 && !isConnected4)
      antenna.send(server4, connectPacket, connectPacketSize);
    if (hasv6 && !isConnected6)
      antenna.send(server6, connectPacket, connectPacketSize);

    ++connectionAttempts;
    if (connectionAttempts > MAX_CONNECT_ATTEMPTS) {
      //Give up, the server probably is not reachable on one or both protocols
      hasv4 &= isConnected4;
      hasv6 &= isConnected6;
      isConnecting = false;
    }

    //If we have not given up or connected yet, try again in a little bit
    timeUntilConnectXmit = TIME_BETWEEN_CONNECT;
  }

  void ensureRegistered() {
    class PP: public PacketProcessor {
    public:
      bool v6;
      PP(bool v) : v6(v) {}
      virtual void process(const Antenna::endpoint&, Antenna*, Tuner*,
                           const byte* data, unsigned len) noth {
        processPacket(v6, data, len);
      }
    } static ppv4(false), ppv6(true);

    if (antenna.tuner) {
      if (hasv4)
        antenna.tuner->connect(server4, &ppv4);
      if (hasv6)
        antenna.tuner->connect(server6, &ppv6);
    }
  }

  void bye() {
    debug(">> BYE");
    byte pack = BYE;
    if (hasv4)
      antenna.send(server4, &pack, 1);
    if (hasv6)
      antenna.send(server6, &pack, 1);

    isConnecting = isConnected4 = isConnected6 = false;
  }

  void post(bool v6, const byte* dat, unsigned len) {
    debug(">> POST");
    vector<byte> pack(1 + len);
    pack[0] = POST;
    memcpy(&pack[1], dat, len);

    if (isConnected4 && !v6)
      antenna.send(server4, &pack[0], pack.size());
    if (isConnected6 && v6)
      antenna.send(server6, &pack[0], pack.size());
  }

  void list() {
    debug(">> LIST");

    byte pack = LIST;
    if (isConnected4)
      antenna.send(server4, &pack, 1);
    if (isConnected6)
      antenna.send(server6, &pack, 1);
  }

  void stopList() {
  }

  void proxy(const Antenna::endpoint& dst,
             const byte* payload, unsigned len) {
    debug(">> PROXY");
    vector<byte> pack(1 + (dst.address().is_v4()? 4 : 2*8) + 2 + len);
    pack[0] = PROXY;
    byte* dat = &pack[1];
    if (dst.address().is_v4()) {
      asio::ip::address_v4::bytes_type b(dst.address().to_v4().to_bytes());
      memcpy(dat, &b[0], 4);
      dat += 4;
    } else {
      asio::ip::address_v6::bytes_type b(dst.address().to_v6().to_bytes());
      io::a6fromlbo(dat, &b[0]);
      dat += 16;
    }
    io::write(dat, dst.port());
    memcpy(dat, payload, len);

    if (dst.address().is_v4() && isConnected4)
      antenna.send(server4, &pack[0], pack.size());
    else if (dst.address().is_v6() && isConnected6)
      antenna.send(server6, &pack[0], pack.size());
    else
      cerr << "warn: Attempt to proxy via unavailable IP version." << endl;
  }

  bool ready() {
    return hasInit &&
           (!hasv4 || (knowIpv4Address && isConnected4)) &&
           (!hasv6 || (knowIpv6Address && isConnected6));
  }

  void update(unsigned et) {
    if (isConnecting) {
      //Move to non-connecting state if both IP versions we support are
      //connected
      if ((!hasv4 || isConnected4) && (!hasv6 || isConnected6))
        isConnecting = true;
      //Otherwise, retransmit connect packet if necessary
      else if (timeUntilConnectXmit <= et)
        sendConnectPacket();
      else
        timeUntilConnectXmit -= et;
    } else if (isConnected4 || isConnected6) {
      //Send PING if needed
      if (timeUntilPing < et) {
        bool whoAmI = (hasv4 && !knowIpv4Address) ||
                      (hasv6 && !knowIpv6Address);
        byte pack[2] = { PING, (byte)whoAmI };
        if (hasv4)
          antenna.send(server4, pack, 2);
        if (hasv6)
          antenna.send(server6, pack, 2);

        unsigned lower = whoAmI? MIN_TIME_BETWEEN_WHOAMI:MIN_TIME_BETWEEN_PING;
        unsigned upper = whoAmI? MAX_TIME_BETWEEN_WHOAMI:MAX_TIME_BETWEEN_PING;
        timeUntilPing = lower + rand()%(upper-lower);
      } else {
        timeUntilPing -= et;
      }
    }
  }

  static void processYouAre(bool, const byte*, unsigned);
  static void processPong(bool, const byte*, unsigned);
  static void processFromOther(bool, const byte*, unsigned);
  static void processAdvert(bool, const byte*, unsigned);
  static void (*const packetTypes[256])(bool, const byte*, unsigned) = {
    processYouAre,
    processPong,
    processFromOther,
    processAdvert,
    NULL,
    /* processSignature, */
    /* rest of array is NULL implicitly */
  };

  static void processPacket(bool v6, const byte* dat, unsigned len) {
    if (packetTypes[dat[0]])
      packetTypes[dat[0]](v6, dat+1, len-1);
    else {
#ifdef DEBUG
      cerr << "WARN: Dropping unknown abuhops packet type " << (unsigned)dat[0]
           << endl;
#endif
    }
  }

  static void processYouAre(bool v6, const byte* dat, unsigned len) {
    debug("<< YOU-ARE");
    if (v6) {
      GlobalID& gid(*antenna.getGlobalID6());
      if (len != 8*2 + 2) {
#ifdef DEBUG
        cerr << "WARN: Dropping IPv6 YOU-ARE packet of length " << len << endl;
#endif
      } else {
        for (unsigned i = 0; i < 8; ++i)
          io::read(dat, gid.ia6[i]);
        io::read(dat, gid.iport);

        knowIpv6Address = true;
        isConnected6 = true;

        cout << "Our IPv6 GlobalID is " << gid.toString() << endl;
      }
    } else {
      GlobalID& gid(*antenna.getGlobalID4());
      if (len != 4 + 2) {
#ifdef DEBUG
        cerr << "WARN: Dropping IPv4 YOU-ARE packet of length " << len << endl;
#endif
      } else {
        memcpy(gid.ia4, dat, 4);
        dat += 4;
        io::read(dat, gid.iport);

        knowIpv4Address = true;
        isConnected4 = true;

        cout << "Our IPv4 GlobalID is " << gid.toString() << endl;
      }
    }
  }

  static void processPong(bool v6, const byte* dat, unsigned len) {
    //Nothing to do
    debug("<< PONG");
  }

  static void processFromOther(bool v6, const byte* dat, unsigned len) {
    debug("<< FROM-OTHER");
    if (!len) {
#ifdef DEBUG
      cerr << "WARN: Dropping FROM-OTHER with empty payload." << endl;
#endif
      return;
    }

    //The default endpoint is used to tell the NetworkGame that it must get the
    //Internet IP address from the STX itself
    Antenna::endpoint defaultEndpoint;
    if (antenna.tuner)
      antenna.tuner->receivePacket(defaultEndpoint, &antenna, dat, len);
  }

  static const char requiredAdvertHeader[] = "Abendspiel";
  #define ADVERT_IPV_OFF (sizeof(requiredAdvertHeader)-1 + 4 + 1)
  static void processAdvert(bool v6, const byte* dat, unsigned len) {
    debug("<< ADVERT");
    Antenna::endpoint defaultEndpoint;
    if (len < ADVERT_IPV_OFF ||
        memcmp(dat, requiredAdvertHeader, sizeof(requiredAdvertHeader)-1)) {
#ifdef DEBUG
      cerr << "WARN: Dropping non-Abendspiel ADVERT" << endl;
#endif
      return;
    }

    //Ensure that the reported IP version of the advert matches the Abuhops
    //realm it is comming from
    if ((unsigned)v6 != dat[ADVERT_IPV_OFF]) {
      /*
       * This warning is meaningless, since the Abendstern abuhops client
       * always posts to both realms.
#ifdef DEBUG
      cerr << "WARN: Dropping ADVERT for wrong IP version" << endl;
#endif
      */
      return;
    }

    if (antenna.tuner)
      antenna.tuner->receivePacket(defaultEndpoint, &antenna, dat, len);
  }
}
<commit_msg>Fix Abuhops client not PINGing.<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <asio.hpp>

#include <cstring>
#include <cstdlib>
#include <iostream>
#include <vector>

#include "antenna.hxx"
#include "tuner.hxx"
#include "io.hxx"
#include "packet_processor.hxx"
#include "abuhops.hxx"

using namespace std;

namespace abuhops {
  #define MIN_TIME_BETWEEN_WHOAMI 1024
  #define MAX_TIME_BETWEEN_WHOAMI 4096
  #define MIN_TIME_BETWEEN_PING 16384
  #define MAX_TIME_BETWEEN_PING 32768
  #define TIME_BETWEEN_CONNECT 1024
  #define MAX_CONNECT_ATTEMPTS 16

  #define CONNECT 0
  #define PING 1
  #define PROXY 2
  #define POST 3
  #define LIST 4
  #define SIGN 5
  #define BYE 6

  #define YOUARE 0
  #define PONG 1
  #define FROMOTHER 2
  #define ADVERT 3
  #define SIGNATURE 5

  #define IPV4PORT 12545
  #define IPV6PORT 12546
  #define SERVER "ABENDSTERN.SERVEGAME.COM."

  #define HMAC_SIZE 32
  #define MAX_NAME_LENGTH 128

  #ifdef DEBUG
  #define debug(x) cout << "abuhops: " << x << endl;
  #else
  #define debug(x)
  #endif

  static unsigned timeUntilPing = 0;

  static bool isConnected4 = false,  isConnected6 = false, isConnecting = true;
  static unsigned timeUntilConnectXmit = 0;
  static byte connectPacket[1+4+4+HMAC_SIZE+MAX_NAME_LENGTH+1];
  static unsigned connectPacketSize;
  static unsigned connectionAttempts = 0;

  static bool knowIpv4Address = false, knowIpv6Address = false;

  static Antenna::endpoint server4, server6;
  static bool hasv4 = false, hasv6 = false;
  static bool hasInit = false;

  static void sendConnectPacket();
  static void processPacket(bool v6, const byte* data, unsigned len);

  void connect(unsigned id, const char* name,
               unsigned timestamp, const char* hmac) {
    debug(">> CONNECT");
    if (!hasInit) {
      hasInit = true;

      try {
        //Look server IP address up
        asio::io_service svc;
        asio::ip::udp::resolver resolver(svc);
        asio::ip::udp::resolver::query query(SERVER, "0");
        asio::ip::udp::resolver::iterator it(resolver.resolve(query)), end;
        while (it != end && (!hasv4 || !hasv6)) {
          asio::ip::address addr(it++->endpoint().address());
          if (addr.is_v4() && !hasv4) {
            hasv4 = true;
            server4 = Antenna::endpoint(addr, IPV4PORT);
            cout << "Resolved " << SERVER << " ipv4 to " << addr.to_string()
                 << endl;
          } else if (addr.is_v6() && !hasv6) {
            hasv6 = true;
            server6 = Antenna::endpoint(addr, IPV6PORT);
            cout << "Resolved " << SERVER << " ipv6 to " << addr.to_string()
                 << endl;
          }
        }
      } catch (const asio::system_error& err) {
        cerr << "Error resolving " << SERVER << ": " << err.what() << endl;
      }

      //Even if we did get a result for a certain protocol, we can't use it
      //if it is not available
      hasv4 &= antenna.hasV4();
      hasv6 &= antenna.hasV6();

      ensureRegistered();
    }

    //Set initial conditions
    isConnected4 = isConnected6 = false;
    isConnecting = true;
    timeUntilConnectXmit = 0;
    connectionAttempts = 0;

    //Write the connection packet
    byte* pack = connectPacket;
    *pack++ = CONNECT;
    io::write(pack, id);
    io::write(pack, timestamp);
    //Convert HMAC from hex
    for (unsigned i = 0; i < HMAC_SIZE; ++i) {
#define HEXIT(x) (x >= '0' && x <= '9'? x-'0' : \
                  x >= 'a' && x <= 'f'? x-'a'+0xa : x-'A'+0xA)
      *pack++ = (HEXIT(hmac[2*i])<<4) | HEXIT(hmac[2*i+1]);
#undef HEXIT
    }
    //Copy name into packet.
    strncpy((char*)pack, name, MAX_NAME_LENGTH);
    pack[MAX_NAME_LENGTH] = 0;

    //Set packet size
    connectPacketSize = (pack - connectPacket) + strlen(name)+1;

    //Done, send the first packet immediately
    sendConnectPacket();
  }

  static void sendConnectPacket() {
    debug(">> CONNECT (send)");
    if (hasv4 && !isConnected4)
      antenna.send(server4, connectPacket, connectPacketSize);
    if (hasv6 && !isConnected6)
      antenna.send(server6, connectPacket, connectPacketSize);

    ++connectionAttempts;
    if (connectionAttempts > MAX_CONNECT_ATTEMPTS) {
      //Give up, the server probably is not reachable on one or both protocols
      hasv4 &= isConnected4;
      hasv6 &= isConnected6;
      isConnecting = false;
    }

    //If we have not given up or connected yet, try again in a little bit
    timeUntilConnectXmit = TIME_BETWEEN_CONNECT;
  }

  void ensureRegistered() {
    class PP: public PacketProcessor {
    public:
      bool v6;
      PP(bool v) : v6(v) {}
      virtual void process(const Antenna::endpoint&, Antenna*, Tuner*,
                           const byte* data, unsigned len) noth {
        processPacket(v6, data, len);
      }
    } static ppv4(false), ppv6(true);

    if (antenna.tuner) {
      if (hasv4)
        antenna.tuner->connect(server4, &ppv4);
      if (hasv6)
        antenna.tuner->connect(server6, &ppv6);
    }
  }

  void bye() {
    debug(">> BYE");
    byte pack = BYE;
    if (hasv4)
      antenna.send(server4, &pack, 1);
    if (hasv6)
      antenna.send(server6, &pack, 1);

    isConnecting = isConnected4 = isConnected6 = false;
  }

  void post(bool v6, const byte* dat, unsigned len) {
    debug(">> POST");
    vector<byte> pack(1 + len);
    pack[0] = POST;
    memcpy(&pack[1], dat, len);

    if (isConnected4 && !v6)
      antenna.send(server4, &pack[0], pack.size());
    if (isConnected6 && v6)
      antenna.send(server6, &pack[0], pack.size());
  }

  void list() {
    debug(">> LIST");

    byte pack = LIST;
    if (isConnected4)
      antenna.send(server4, &pack, 1);
    if (isConnected6)
      antenna.send(server6, &pack, 1);
  }

  void stopList() {
  }

  void proxy(const Antenna::endpoint& dst,
             const byte* payload, unsigned len) {
    debug(">> PROXY");
    vector<byte> pack(1 + (dst.address().is_v4()? 4 : 2*8) + 2 + len);
    pack[0] = PROXY;
    byte* dat = &pack[1];
    if (dst.address().is_v4()) {
      asio::ip::address_v4::bytes_type b(dst.address().to_v4().to_bytes());
      memcpy(dat, &b[0], 4);
      dat += 4;
    } else {
      asio::ip::address_v6::bytes_type b(dst.address().to_v6().to_bytes());
      io::a6fromlbo(dat, &b[0]);
      dat += 16;
    }
    io::write(dat, dst.port());
    memcpy(dat, payload, len);

    if (dst.address().is_v4() && isConnected4)
      antenna.send(server4, &pack[0], pack.size());
    else if (dst.address().is_v6() && isConnected6)
      antenna.send(server6, &pack[0], pack.size());
    else
      cerr << "warn: Attempt to proxy via unavailable IP version." << endl;
  }

  bool ready() {
    return hasInit &&
           (!hasv4 || (knowIpv4Address && isConnected4)) &&
           (!hasv6 || (knowIpv6Address && isConnected6));
  }

  void update(unsigned et) {
    if (isConnecting) {
      //Move to non-connecting state if both IP versions we support are
      //connected
      if ((!hasv4 || isConnected4) && (!hasv6 || isConnected6))
        isConnecting = false;
      //Otherwise, retransmit connect packet if necessary
      else if (timeUntilConnectXmit <= et)
        sendConnectPacket();
      else
        timeUntilConnectXmit -= et;
    } else if (isConnected4 || isConnected6) {
      //Send PING if needed
      if (timeUntilPing < et) {
        bool whoAmI = (hasv4 && !knowIpv4Address) ||
                      (hasv6 && !knowIpv6Address);
        debug(">> PING " << whoAmI);
        byte pack[2] = { PING, (byte)whoAmI };
        if (hasv4)
          antenna.send(server4, pack, 2);
        if (hasv6)
          antenna.send(server6, pack, 2);

        unsigned lower = whoAmI? MIN_TIME_BETWEEN_WHOAMI:MIN_TIME_BETWEEN_PING;
        unsigned upper = whoAmI? MAX_TIME_BETWEEN_WHOAMI:MAX_TIME_BETWEEN_PING;
        timeUntilPing = lower + rand()%(upper-lower);
      } else {
        timeUntilPing -= et;
      }
    }
  }

  static void processYouAre(bool, const byte*, unsigned);
  static void processPong(bool, const byte*, unsigned);
  static void processFromOther(bool, const byte*, unsigned);
  static void processAdvert(bool, const byte*, unsigned);
  static void (*const packetTypes[256])(bool, const byte*, unsigned) = {
    processYouAre,
    processPong,
    processFromOther,
    processAdvert,
    NULL,
    /* processSignature, */
    /* rest of array is NULL implicitly */
  };

  static void processPacket(bool v6, const byte* dat, unsigned len) {
    if (packetTypes[dat[0]])
      packetTypes[dat[0]](v6, dat+1, len-1);
    else {
#ifdef DEBUG
      cerr << "WARN: Dropping unknown abuhops packet type " << (unsigned)dat[0]
           << endl;
#endif
    }
  }

  static void processYouAre(bool v6, const byte* dat, unsigned len) {
    debug("<< YOU-ARE");
    if (v6) {
      GlobalID& gid(*antenna.getGlobalID6());
      if (len != 8*2 + 2) {
#ifdef DEBUG
        cerr << "WARN: Dropping IPv6 YOU-ARE packet of length " << len << endl;
#endif
      } else {
        for (unsigned i = 0; i < 8; ++i)
          io::read(dat, gid.ia6[i]);
        io::read(dat, gid.iport);

        knowIpv6Address = true;
        isConnected6 = true;

        cout << "Our IPv6 GlobalID is " << gid.toString() << endl;
      }
    } else {
      GlobalID& gid(*antenna.getGlobalID4());
      if (len != 4 + 2) {
#ifdef DEBUG
        cerr << "WARN: Dropping IPv4 YOU-ARE packet of length " << len << endl;
#endif
      } else {
        memcpy(gid.ia4, dat, 4);
        dat += 4;
        io::read(dat, gid.iport);

        knowIpv4Address = true;
        isConnected4 = true;

        cout << "Our IPv4 GlobalID is " << gid.toString() << endl;
      }
    }
  }

  static void processPong(bool v6, const byte* dat, unsigned len) {
    //Nothing to do
    debug("<< PONG");
  }

  static void processFromOther(bool v6, const byte* dat, unsigned len) {
    debug("<< FROM-OTHER");
    if (!len) {
#ifdef DEBUG
      cerr << "WARN: Dropping FROM-OTHER with empty payload." << endl;
#endif
      return;
    }

    //The default endpoint is used to tell the NetworkGame that it must get the
    //Internet IP address from the STX itself
    Antenna::endpoint defaultEndpoint;
    if (antenna.tuner)
      antenna.tuner->receivePacket(defaultEndpoint, &antenna, dat, len);
  }

  static const char requiredAdvertHeader[] = "Abendspiel";
  #define ADVERT_IPV_OFF (sizeof(requiredAdvertHeader)-1 + 4 + 1)
  static void processAdvert(bool v6, const byte* dat, unsigned len) {
    debug("<< ADVERT");
    Antenna::endpoint defaultEndpoint;
    if (len < ADVERT_IPV_OFF ||
        memcmp(dat, requiredAdvertHeader, sizeof(requiredAdvertHeader)-1)) {
#ifdef DEBUG
      cerr << "WARN: Dropping non-Abendspiel ADVERT" << endl;
#endif
      return;
    }

    //Ensure that the reported IP version of the advert matches the Abuhops
    //realm it is comming from
    if ((unsigned)v6 != dat[ADVERT_IPV_OFF]) {
      /*
       * This warning is meaningless, since the Abendstern abuhops client
       * always posts to both realms.
#ifdef DEBUG
      cerr << "WARN: Dropping ADVERT for wrong IP version" << endl;
#endif
      */
      return;
    }

    if (antenna.tuner)
      antenna.tuner->receivePacket(defaultEndpoint, &antenna, dat, len);
  }
}
<|endoftext|>


<commit_before>#include "osm2nav.h"
#include <stdio.h>

#include <iostream>
#include <boost/lexical_cast.hpp>
#include "type/data.h"
#include "third_party/osmpbfreader/osmpbfreader.h"
#include "osm_tags_reader.h"
#include "georef/georef.h"
#include "utils/functions.h"

namespace navitia { namespace georef {

struct OSMHouseNumber{
    type::GeographicalCoord coord;
    int number;

    OSMHouseNumber(): number(-1){}

};

struct Node {
public:
    double lon() const {return static_cast<double>(this->lon_m) / precision;}
    double lat() const {return static_cast<double>(this->lat_m) / precision;}
    uint32_t uses;
    int32_t idx;

    Node(double lon = 0, double lat = 0) : uses(0), idx(-1), lon_m(lon * precision), lat_m(lat * precision){}
    bool increment_use(int idx){
        uses++;
        if(this->idx == -1 && uses > 1){
            this->idx = idx;
            return true;
        } else {
            return false;
        }
    }

private:
    int32_t lon_m;
    int32_t lat_m;
    static constexpr double precision = 10e6;
};

struct OSMWay {
    const static uint8_t CYCLE_FWD = 0;
    const static uint8_t CYCLE_BWD = 1;
    const static uint8_t CAR_FWD = 2;
    const static uint8_t CAR_BWD = 3;
    const static uint8_t FOOT_FWD = 4;
    const static uint8_t FOOT_BWD = 5;
    std::vector<uint64_t> refs;
    uint64_t id;
    std::bitset<8> properties;
    type::idx_t idx;
};

using namespace CanalTP;

struct Visitor{
    std::unordered_map<uint64_t, Node> nodes;
    std::unordered_map<uint64_t, OSMHouseNumber> housenumbers;
    int total_ways;
    int total_house_number;

    std::vector<OSMWay> ways;
    georef::GeoRef & geo_ref;

    Visitor(GeoRef & to_fill) : total_ways(0), total_house_number(0), geo_ref(to_fill){}

    void add_osm_housenumber(uint64_t osmid, const Tags & tags){
        if(tags.find("addr:housenumber") != tags.end()){
            OSMHouseNumber osm_hn;
            osm_hn.number = str_to_int(tags.at("addr:housenumber"));
            if (osm_hn.number > 0 ){
                this->housenumbers[osmid] = osm_hn;
            }
        }
    }

    void node_callback(uint64_t osmid, double lon, double lat, const Tags & tags){
        this->nodes[osmid] = Node(lon, lat);
        add_osm_housenumber(osmid, tags);
    }

    void way_callback(uint64_t osmid, const Tags &tags, const std::vector<uint64_t> &refs){
        total_ways++;
        std::bitset<8> properties = parse_way_tags(tags);
        if(properties.any()){
            OSMWay w;
            w.idx = ways.size();
            w.refs = refs;
            w.id = osmid;
            ways.push_back(w);

            georef::Way gr_way;
            gr_way.idx = w.idx;
            gr_way.external_code = std::to_string(w.idx);
            gr_way.city_idx = type::invalid_idx;
            if(tags.find("name") != tags.end())
                gr_way.name = tags.at("name");
            geo_ref.ways.push_back(gr_way);
        }else{
             add_osm_housenumber(refs.front(), tags);
        }
    }

    // Once all the ways and nodes are read, we count how many times a node is used to detect intersections
    void count_nodes_uses() {
        int count = 0;
        for(auto w : ways){
            for(uint64_t ref : w.refs){
                if(nodes[ref].increment_use(count)){
                    Vertex v;
                    count++;
                    v.coord = type::GeographicalCoord( nodes[ref].lon(), nodes[ref].lat());
                    boost::add_vertex(v, geo_ref.graph);
                }
            }
            // make sure that the last node is considered as an extremity
            if(nodes[w.refs.front()].increment_use(count)){
                count++;
                Vertex v;
                v.coord = type::GeographicalCoord(nodes[w.refs.front()].lon(), nodes[w.refs.front()].lat());
                boost::add_vertex(v, geo_ref.graph);
            }
            if(nodes[w.refs.back()].increment_use(count)){
                count++;
                Vertex v;
                v.coord = type::GeographicalCoord(nodes[w.refs.back()].lon(), nodes[w.refs.back()].lat());
                boost::add_vertex(v, geo_ref.graph);
            }
        }
        std::cout << "On a : " << boost::num_vertices(geo_ref.graph) << " nœuds" << std::endl;
    }

    // Returns the source and target node of the edges
    void edges(){
        for(OSMWay w : ways){
            if(w.refs.size() > 0){
                Node n = nodes[w.refs[0]];
                type::idx_t source = n.idx;
                type::GeographicalCoord prev(n.lon(), n.lat());
                float length = 0;
                for(size_t i = 1; i < w.refs.size(); ++i){
                    Node current_node = nodes[w.refs[i]];
                    type::GeographicalCoord current(current_node.lon(), current_node.lat());
                    length += current.distance_to(prev);
                    prev = current;
                    // If a node is used more than once, it is an intersection, hence it's a node of the road network graph
                    if(current_node.uses > 1){
                        type::idx_t target = current_node.idx;
                        georef::Edge e;
                        e.length = length;
                        e.way_idx = w.idx;
                        e.cyclable = w.properties[CYCLE_FWD];
                        boost::add_edge(source, target, e, geo_ref.graph);
                        e.cyclable = w.properties[CYCLE_BWD];
                        boost::add_edge(target, source, e, geo_ref.graph);
                        source = target;
                        length = 0;
                    }
                }
            }
        }
        std::cout << "On a " << boost::num_edges(geo_ref.graph) << " arcs" << std::endl;
    }

    void HouseNumbers(){
        type::idx_t idx;
        georef::HouseNumber gr_hn;
        geo_ref.build_proximity_list();
        for(auto hn : housenumbers){
            try{
                Node n = nodes[hn.first];
                gr_hn.number = hn.second.number;
                gr_hn.coord.set_lon(n.lon());
                gr_hn.coord.set_lat(n.lat());
                idx = geo_ref.graph[geo_ref.nearest_edge(gr_hn.coord)].way_idx;
                geo_ref.ways[idx].add_house_number(gr_hn);
                total_house_number ++;
            } catch(navitia::proximitylist::NotFound) {
                std::cout << "Attention, l'adresse n'est pas importée dont le numéro et les coordonnées sont : [" << gr_hn.number<<";"<< gr_hn.coord.lon()<< ";"<< gr_hn.coord.lat()<< "] Impossible de trouver le segment le plus proche.  " << std::endl;
            }catch(...){
                std::cout << "Attention, l'adresse n'est pas importée dont le numéro et les coordonnées sont : [" << gr_hn.number<<";"<< gr_hn.coord.lon()<< ";"<< gr_hn.coord.lat()<< "].  " << std::endl;
            }
        }
    }
    // We don't care about relations
    void relation_callback(uint64_t /*osmid*/, const Tags &/*tags*/, const References & /*refs*/){}
};

void fill_from_osm(GeoRef & geo_ref_to_fill, const std::string & osm_pbf_filename){
    Visitor v(geo_ref_to_fill);
    CanalTP::read_osm_pbf(osm_pbf_filename, v);
    std::cout << v.nodes.size() << " nodes, " << v.ways.size() << " ways/" << v.total_ways << std::endl;
    v.count_nodes_uses();
    v.edges();
    v.HouseNumbers();
    std::cout << "On a " << v.total_house_number << " adresses" << std::endl;
}
}}

<commit_msg>georef : Ajout des edges au ways<commit_after>#include "osm2nav.h"
#include <stdio.h>

#include <iostream>
#include <boost/lexical_cast.hpp>
#include "type/data.h"
#include "third_party/osmpbfreader/osmpbfreader.h"
#include "osm_tags_reader.h"
#include "georef/georef.h"
#include "utils/functions.h"

namespace navitia { namespace georef {

struct OSMHouseNumber{
    type::GeographicalCoord coord;
    int number;

    OSMHouseNumber(): number(-1){}

};

struct Node {
public:
    double lon() const {return static_cast<double>(this->lon_m) / precision;}
    double lat() const {return static_cast<double>(this->lat_m) / precision;}
    uint32_t uses;
    int32_t idx;

    Node(double lon = 0, double lat = 0) : uses(0), idx(-1), lon_m(lon * precision), lat_m(lat * precision){}
    bool increment_use(int idx){
        uses++;
        if(this->idx == -1 && uses > 1){
            this->idx = idx;
            return true;
        } else {
            return false;
        }
    }

private:
    int32_t lon_m;
    int32_t lat_m;
    static constexpr double precision = 10e6;
};

struct OSMWay {
    const static uint8_t CYCLE_FWD = 0;
    const static uint8_t CYCLE_BWD = 1;
    const static uint8_t CAR_FWD = 2;
    const static uint8_t CAR_BWD = 3;
    const static uint8_t FOOT_FWD = 4;
    const static uint8_t FOOT_BWD = 5;
    std::vector<uint64_t> refs;
    uint64_t id;
    std::bitset<8> properties;
    type::idx_t idx;
};

using namespace CanalTP;

struct Visitor{
    std::unordered_map<uint64_t, Node> nodes;
    std::unordered_map<uint64_t, OSMHouseNumber> housenumbers;
    int total_ways;
    int total_house_number;

    std::vector<OSMWay> ways;
    georef::GeoRef & geo_ref;

    Visitor(GeoRef & to_fill) : total_ways(0), total_house_number(0), geo_ref(to_fill){}

    void add_osm_housenumber(uint64_t osmid, const Tags & tags){
        if(tags.find("addr:housenumber") != tags.end()){
            OSMHouseNumber osm_hn;
            osm_hn.number = str_to_int(tags.at("addr:housenumber"));
            if (osm_hn.number > 0 ){
                this->housenumbers[osmid] = osm_hn;
            }
        }
    }

    void node_callback(uint64_t osmid, double lon, double lat, const Tags & tags){
        this->nodes[osmid] = Node(lon, lat);
        add_osm_housenumber(osmid, tags);
    }

    void way_callback(uint64_t osmid, const Tags &tags, const std::vector<uint64_t> &refs){
        total_ways++;
        std::bitset<8> properties = parse_way_tags(tags);
        if(properties.any()){
            OSMWay w;
            w.idx = ways.size();
            w.refs = refs;
            w.id = osmid;
            ways.push_back(w);

            georef::Way gr_way;
            gr_way.idx = w.idx;
            gr_way.external_code = std::to_string(w.idx);
            gr_way.city_idx = type::invalid_idx;
            if(tags.find("name") != tags.end())
                gr_way.name = tags.at("name");
            geo_ref.ways.push_back(gr_way);
        }else{
             add_osm_housenumber(refs.front(), tags);
        }
    }

    // Once all the ways and nodes are read, we count how many times a node is used to detect intersections
    void count_nodes_uses() {
        int count = 0;
        for(auto w : ways){
            for(uint64_t ref : w.refs){
                if(nodes[ref].increment_use(count)){
                    Vertex v;
                    count++;
                    v.coord = type::GeographicalCoord( nodes[ref].lon(), nodes[ref].lat());
                    boost::add_vertex(v, geo_ref.graph);
                }
            }
            // make sure that the last node is considered as an extremity
            if(nodes[w.refs.front()].increment_use(count)){
                count++;
                Vertex v;
                v.coord = type::GeographicalCoord(nodes[w.refs.front()].lon(), nodes[w.refs.front()].lat());
                boost::add_vertex(v, geo_ref.graph);
            }
            if(nodes[w.refs.back()].increment_use(count)){
                count++;
                Vertex v;
                v.coord = type::GeographicalCoord(nodes[w.refs.back()].lon(), nodes[w.refs.back()].lat());
                boost::add_vertex(v, geo_ref.graph);
            }
        }
        std::cout << "On a : " << boost::num_vertices(geo_ref.graph) << " nœuds" << std::endl;
    }

    // Returns the source and target node of the edges
    void edges(){
        for(OSMWay w : ways){
            if(w.refs.size() > 0){
                Node n = nodes[w.refs[0]];
                type::idx_t source = n.idx;
                type::GeographicalCoord prev(n.lon(), n.lat());
                float length = 0;
                for(size_t i = 1; i < w.refs.size(); ++i){
                    Node current_node = nodes[w.refs[i]];
                    type::GeographicalCoord current(current_node.lon(), current_node.lat());
                    length += current.distance_to(prev);
                    prev = current;
                    // If a node is used more than once, it is an intersection, hence it's a node of the road network graph
                    if(current_node.uses > 1){
                        type::idx_t target = current_node.idx;
                        georef::Edge e;
                        e.length = length;
                        e.way_idx = w.idx;

                        e.cyclable = w.properties[CYCLE_FWD];
                        boost::add_edge(source, target, e, geo_ref.graph);
                        geo_ref.ways[w.idx].edges.push_back(std::make_pair(source, target));

                        e.cyclable = w.properties[CYCLE_BWD];
                        boost::add_edge(target, source, e, geo_ref.graph);
                        geo_ref.ways[w.idx].edges.push_back(std::make_pair(target, source));
                        source = target;
                        length = 0;
                    }
                }
            }
        }
        std::cout << "On a " << boost::num_edges(geo_ref.graph) << " arcs" << std::endl;
    }

    void HouseNumbers(){
        type::idx_t idx;
        georef::HouseNumber gr_hn;
        geo_ref.build_proximity_list();
        for(auto hn : housenumbers){
            try{
                Node n = nodes[hn.first];
                gr_hn.number = hn.second.number;
                gr_hn.coord.set_lon(n.lon());
                gr_hn.coord.set_lat(n.lat());
                idx = geo_ref.graph[geo_ref.nearest_edge(gr_hn.coord)].way_idx;
                geo_ref.ways[idx].add_house_number(gr_hn);
                total_house_number ++;
            } catch(navitia::proximitylist::NotFound) {
                std::cout << "Attention, l'adresse n'est pas importée dont le numéro et les coordonnées sont : [" << gr_hn.number<<";"<< gr_hn.coord.lon()<< ";"<< gr_hn.coord.lat()<< "] Impossible de trouver le segment le plus proche.  " << std::endl;
            }catch(...){
                std::cout << "Attention, l'adresse n'est pas importée dont le numéro et les coordonnées sont : [" << gr_hn.number<<";"<< gr_hn.coord.lon()<< ";"<< gr_hn.coord.lat()<< "].  " << std::endl;
            }
        }
    }
    // We don't care about relations
    void relation_callback(uint64_t /*osmid*/, const Tags &/*tags*/, const References & /*refs*/){}
};

void fill_from_osm(GeoRef & geo_ref_to_fill, const std::string & osm_pbf_filename){
    Visitor v(geo_ref_to_fill);
    CanalTP::read_osm_pbf(osm_pbf_filename, v);
    std::cout << v.nodes.size() << " nodes, " << v.ways.size() << " ways/" << v.total_ways << std::endl;
    v.count_nodes_uses();
    v.edges();
    v.HouseNumbers();
    std::cout << "On a " << v.total_house_number << " adresses" << std::endl;
}
}}

<|endoftext|>


<commit_before>/*
 * Copyright 2016 - 2019 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "addresses.hpp"

#include <ox/std/assert.hpp>
#include <ox/std/bit.hpp>

// this warning is too dumb to realize that it can actually confirm the hard
// coded address aligns with the requirement of HeapSegment, so it must be
// suppressed
#pragma GCC diagnostic ignored "-Wcast-align"

#define HEAP_BEGIN reinterpret_cast<HeapSegment*>(MEM_WRAM_BEGIN)
// set size to half of WRAM
#define HEAP_SIZE ((MEM_WRAM_END - MEM_WRAM_BEGIN) / 2)
#define HEAP_END reinterpret_cast<HeapSegment*>(MEM_WRAM_BEGIN + HEAP_SIZE)

namespace nostalgia::core {

static class HeapSegment *volatile g_heapBegin = nullptr;
static class HeapSegment *volatile g_heapEnd = nullptr;
static class HeapSegment *volatile heapIdx = nullptr;

static constexpr std::size_t alignedSize(std::size_t sz) {
	return sz + (sz & 7);
}

template<typename T>
static constexpr std::size_t alignedSize(T = {}) {
	return alignedSize(sizeof(T));
}

struct HeapSegment {
	std::size_t size;
	uint8_t inUse;

	void init(std::size_t maxSize = ox::bit_cast<std::size_t>(g_heapEnd)) {
		this->size = maxSize - ox::bit_cast<std::size_t>(this);
		this->inUse = false;
	}

	template<typename T>
	T *data() {
		return ox::bit_cast<T*>(ox::bit_cast<uint8_t*>(this) + alignedSize(this));
	}

	template<typename T = uint8_t>
	T *end() {
		const auto size = alignedSize(this) + alignedSize(this->size);
		auto e = ox::bit_cast<uintptr_t>(ox::bit_cast<uint8_t*>(this) + size);
		return ox::bit_cast<T*>(e);
	}

};

void initHeap(char *heapBegin, char *heapEnd) {
	g_heapBegin = ox::bit_cast<HeapSegment*>(heapBegin);
	g_heapEnd = ox::bit_cast<HeapSegment*>(heapEnd);
	heapIdx = g_heapBegin;
	heapIdx->size = ox::bit_cast<std::size_t>(heapEnd) - ox::bit_cast<std::size_t>(heapIdx);
	heapIdx->inUse = false;
}

void initHeap() {
	initHeap(ox::bit_cast<char*>(HEAP_BEGIN), ox::bit_cast<char*>(HEAP_END));
}

struct SegmentPair {
	HeapSegment *anteSegment = nullptr;
	HeapSegment *segment = nullptr;
};

static SegmentPair findSegmentOf(void *ptr) {
	HeapSegment *prev = nullptr;
	for (auto seg = HEAP_BEGIN; seg < HEAP_END;) {
		if (seg->data<void>() == ptr) {
			return {prev, seg};
		}
		prev = seg;
		seg = seg->end<HeapSegment>();
	}
	return {};
}

static HeapSegment *findSegmentFor(std::size_t sz) {
	for (auto s = g_heapBegin; s <= g_heapEnd; s = s->end<HeapSegment>()) {
		if (s->size >= sz && !s->inUse) {
			return s;
		}
	}
	oxPanic(OxError(1), "malloc: could not find segment");
	return nullptr;
}

[[nodiscard]] void *malloc(std::size_t allocSize) {
	const auto targetSize = alignedSize(sizeof(HeapSegment)) + alignedSize(allocSize);
	auto seg = findSegmentFor(targetSize);
	if (seg == nullptr) {
		return nullptr;
	}
	const auto bytesRemaining = seg->size - targetSize;
	seg->size = targetSize;
	seg->inUse = true;
	seg->end<HeapSegment>()->init(bytesRemaining);
	return seg->data<void>();
}

void free(void *ptr) {
	auto p = findSegmentOf(ptr);
	if (p.anteSegment) {
		p.anteSegment->size += p.segment->size;
	} else if (p.segment) {
		p.segment->inUse = false;
	} else {
		oxPanic(OxError(1), "Bad heap free");
	}
}

}

#ifndef OX_USE_STDLIB

using namespace nostalgia;

void *operator new(std::size_t allocSize) {
	return core::malloc(allocSize);
}

void *operator new[](std::size_t allocSize) {
	return core::malloc(allocSize);
}

void operator delete(void *ptr) {
	core::free(ptr);
}

void operator delete[](void *ptr) {
	core::free(ptr);
}

void operator delete(void *ptr, unsigned) {
	core::free(ptr);
}

void operator delete[](void *ptr, unsigned) {
	core::free(ptr);
}

void operator delete(void *ptr, unsigned long int) {
	core::free(ptr);
}

void operator delete[](void *ptr, unsigned long int) {
	core::free(ptr);
}

#endif
<commit_msg>[nostalgia/core/gba] Cleanup class/struct inconsistency<commit_after>/*
 * Copyright 2016 - 2019 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "addresses.hpp"

#include <ox/std/assert.hpp>
#include <ox/std/bit.hpp>

// this warning is too dumb to realize that it can actually confirm the hard
// coded address aligns with the requirement of HeapSegment, so it must be
// suppressed
#pragma GCC diagnostic ignored "-Wcast-align"

#define HEAP_BEGIN reinterpret_cast<HeapSegment*>(MEM_WRAM_BEGIN)
// set size to half of WRAM
#define HEAP_SIZE ((MEM_WRAM_END - MEM_WRAM_BEGIN) / 2)
#define HEAP_END reinterpret_cast<HeapSegment*>(MEM_WRAM_BEGIN + HEAP_SIZE)

namespace nostalgia::core {

static struct HeapSegment *volatile g_heapBegin = nullptr;
static struct HeapSegment *volatile g_heapEnd = nullptr;
static struct HeapSegment *volatile heapIdx = nullptr;

static constexpr std::size_t alignedSize(std::size_t sz) {
	return sz + (sz & 7);
}

template<typename T>
static constexpr std::size_t alignedSize(T = {}) {
	return alignedSize(sizeof(T));
}

struct HeapSegment {
	std::size_t size;
	uint8_t inUse;

	void init(std::size_t maxSize = ox::bit_cast<std::size_t>(g_heapEnd)) {
		this->size = maxSize - ox::bit_cast<std::size_t>(this);
		this->inUse = false;
	}

	template<typename T>
	T *data() {
		return ox::bit_cast<T*>(ox::bit_cast<uint8_t*>(this) + alignedSize(this));
	}

	template<typename T = uint8_t>
	T *end() {
		const auto size = alignedSize(this) + alignedSize(this->size);
		auto e = ox::bit_cast<uintptr_t>(ox::bit_cast<uint8_t*>(this) + size);
		return ox::bit_cast<T*>(e);
	}

};

void initHeap(char *heapBegin, char *heapEnd) {
	g_heapBegin = ox::bit_cast<HeapSegment*>(heapBegin);
	g_heapEnd = ox::bit_cast<HeapSegment*>(heapEnd);
	heapIdx = g_heapBegin;
	heapIdx->size = ox::bit_cast<std::size_t>(heapEnd) - ox::bit_cast<std::size_t>(heapIdx);
	heapIdx->inUse = false;
}

void initHeap() {
	initHeap(ox::bit_cast<char*>(HEAP_BEGIN), ox::bit_cast<char*>(HEAP_END));
}

struct SegmentPair {
	HeapSegment *anteSegment = nullptr;
	HeapSegment *segment = nullptr;
};

static SegmentPair findSegmentOf(void *ptr) {
	HeapSegment *prev = nullptr;
	for (auto seg = HEAP_BEGIN; seg < HEAP_END;) {
		if (seg->data<void>() == ptr) {
			return {prev, seg};
		}
		prev = seg;
		seg = seg->end<HeapSegment>();
	}
	return {};
}

static HeapSegment *findSegmentFor(std::size_t sz) {
	for (auto s = g_heapBegin; s <= g_heapEnd; s = s->end<HeapSegment>()) {
		if (s->size >= sz && !s->inUse) {
			return s;
		}
	}
	oxPanic(OxError(1), "malloc: could not find segment");
	return nullptr;
}

[[nodiscard]] void *malloc(std::size_t allocSize) {
	const auto targetSize = alignedSize(sizeof(HeapSegment)) + alignedSize(allocSize);
	auto seg = findSegmentFor(targetSize);
	if (seg == nullptr) {
		return nullptr;
	}
	const auto bytesRemaining = seg->size - targetSize;
	seg->size = targetSize;
	seg->inUse = true;
	seg->end<HeapSegment>()->init(bytesRemaining);
	return seg->data<void>();
}

void free(void *ptr) {
	auto p = findSegmentOf(ptr);
	if (p.anteSegment) {
		p.anteSegment->size += p.segment->size;
	} else if (p.segment) {
		p.segment->inUse = false;
	} else {
		oxPanic(OxError(1), "Bad heap free");
	}
}

}

#ifndef OX_USE_STDLIB

using namespace nostalgia;

void *operator new(std::size_t allocSize) {
	return core::malloc(allocSize);
}

void *operator new[](std::size_t allocSize) {
	return core::malloc(allocSize);
}

void operator delete(void *ptr) {
	core::free(ptr);
}

void operator delete[](void *ptr) {
	core::free(ptr);
}

void operator delete(void *ptr, unsigned) {
	core::free(ptr);
}

void operator delete[](void *ptr, unsigned) {
	core::free(ptr);
}

void operator delete(void *ptr, unsigned long int) {
	core::free(ptr);
}

void operator delete[](void *ptr, unsigned long int) {
	core::free(ptr);
}

#endif
<|endoftext|>


<commit_before>#ifndef CXX_CONVERSIONS_HXX
# define CXX_CONVERSIONS_HXX

# include <libport/symbol.hh>

# include <object/cxx-object.hh>
# include <object/float-class.hh>
# include <object/string-class.hh>
# include <scheduler/tag.hh>

namespace object
{
  // Nothing to do for objects
  template <>
  class CxxConvert<libport::shared_ptr<Object, true> >
  {
  public:
    static rObject
    to(const rObject& o, const libport::Symbol&)
    {
      return o;
    }

    static rObject
    from(rObject o,  const libport::Symbol&)
    {
      if (!o)
        return void_class;
      return o;
    }
  };

 // Convert between Urbi types
  template <typename Urbi>
  struct CxxConvert<libport::shared_ptr<Urbi, true> >
  {
    typedef libport::shared_ptr<Urbi, true> T;

    static T
    to(const rObject& o, const libport::Symbol& name)
    {
      type_check<Urbi>(o, name);
      return o->as<Urbi>();
    }

    static rObject
    from(const T& v,  const libport::Symbol&)
    {
      return v;
    }
  };

  // Conversion with prio_type
  template<>
  struct CxxConvert<scheduler::prio_type>
  {
    static scheduler::prio_type
    to(const rObject& o, const libport::Symbol& name)
      {
	type_check<Float>(o, name);
	rFloat f = o->as<Float>();
	int res = f->to_int(name);
	if (res < 0)
	  throw BadInteger(f->value_get(), name);
	return res;
      }

    static rObject
    from(const scheduler::prio_type& v, const libport::Symbol&)
      {
	return new Float(v);
      }
  };

  // Conversion with std::strings
  template <>
  struct CxxConvert<std::string>
  {
    static std::string
    to(const rObject& o, const libport::Symbol& name)
    {
      type_check<String>(o, name);
      return o->as<String>()->value_get().name_get();
    }

    static rObject
    from(const std::string& v,  const libport::Symbol&)
    {
      return new String(libport::Symbol(v));
    }
  };

  // Conversion with libport::Symbols
  template <>
  struct CxxConvert<libport::Symbol>
  {
    static libport::Symbol
    to(const rObject& o, const libport::Symbol& name)
    {
      type_check<String>(o, name);
      return o->as<String>()->value_get();
    }

    static rObject
    from(const libport::Symbol& v,  const libport::Symbol&)
    {
      return new String(v);
    }
  };

  // Conversion with bools
  template <>
  struct CxxConvert<bool>
  {
    static bool
    to(const rObject& o, const libport::Symbol& name)
    {
      return is_true(o, name);
    }

    static rObject
    from(bool v,  const libport::Symbol&)
    {
      return v ? true_class : false_class;
    }
  };

}

#endif
<commit_msg>Generalize the conversion to unsigned int.<commit_after>#ifndef CXX_CONVERSIONS_HXX
# define CXX_CONVERSIONS_HXX

# include <libport/symbol.hh>

# include <object/cxx-object.hh>
# include <object/float-class.hh>
# include <object/string-class.hh>
# include <scheduler/tag.hh>

namespace object
{
  // Nothing to do for objects
  template <>
  class CxxConvert<libport::shared_ptr<Object, true> >
  {
  public:
    static rObject
    to(const rObject& o, const libport::Symbol&)
    {
      return o;
    }

    static rObject
    from(rObject o,  const libport::Symbol&)
    {
      if (!o)
        return void_class;
      return o;
    }
  };

 // Convert between Urbi types
  template <typename Urbi>
  struct CxxConvert<libport::shared_ptr<Urbi, true> >
  {
    typedef libport::shared_ptr<Urbi, true> T;

    static T
    to(const rObject& o, const libport::Symbol& name)
    {
      type_check<Urbi>(o, name);
      return o->as<Urbi>();
    }

    static rObject
    from(const T& v,  const libport::Symbol&)
    {
      return v;
    }
  };

  // Conversion with unsigned int
  template<>
  struct CxxConvert<unsigned int>
  {
    static unsigned int
    to(const rObject& o, const libport::Symbol& name)
      {
	type_check<Float>(o, name);
	return o->as<Float>()->to_unsigned_int(name);
      }

    static rObject
    from(const unsigned int& v, const libport::Symbol&)
      {
	return new Float(v);
      }
  };

  // Conversion with std::strings
  template <>
  struct CxxConvert<std::string>
  {
    static std::string
    to(const rObject& o, const libport::Symbol& name)
    {
      type_check<String>(o, name);
      return o->as<String>()->value_get().name_get();
    }

    static rObject
    from(const std::string& v,  const libport::Symbol&)
    {
      return new String(libport::Symbol(v));
    }
  };

  // Conversion with libport::Symbols
  template <>
  struct CxxConvert<libport::Symbol>
  {
    static libport::Symbol
    to(const rObject& o, const libport::Symbol& name)
    {
      type_check<String>(o, name);
      return o->as<String>()->value_get();
    }

    static rObject
    from(const libport::Symbol& v,  const libport::Symbol&)
    {
      return new String(v);
    }
  };

  // Conversion with bools
  template <>
  struct CxxConvert<bool>
  {
    static bool
    to(const rObject& o, const libport::Symbol& name)
    {
      return is_true(o, name);
    }

    static rObject
    from(bool v,  const libport::Symbol&)
    {
      return v ? true_class : false_class;
    }
  };

}

#endif
<|endoftext|>


<commit_before>#include <node.h>
#include <v8.h>

#include "Application.h"
#include "SpotifyService/SpotifyService.h"
#include "NodeCallback.h"

#include "objects/node/StaticCallbackSetter.h"
#include "objects/spotify/PlaylistContainer.h"
#include "objects/node/NodePlaylist.h"
#include "objects/node/NodeTrack.h"
#include "objects/node/NodePlayer.h"
#include "objects/node/NodeAlbum.h"
#include "objects/node/NodeArtist.h"
#include "objects/node/NodeSearch.h"

extern "C" {
  #include "audio/audio.h"
}

using namespace v8;

Application* application;

Handle<Value> login(const Arguments& args) {
  HandleScope scope;
  String::Utf8Value v8User(args[0]->ToString());
  String::Utf8Value v8Password(args[1]->ToString());
  bool rememberMe = args[2]->ToBoolean()->Value();
  bool withRemembered = args[3]->ToBoolean()->Value();
  std::string user(*v8User);
  std::string password(*v8Password);
  application->spotifyService->login(user, password, rememberMe, withRemembered);
  return scope.Close(Undefined());
}

Handle<Value> logout(const Arguments& args) {
  HandleScope scope;
  auto callback = [] () { application->spotifyService->logout(); };
  application->spotifyService->executeSpotifyAPIcall(callback);
  return scope.Close(Undefined());
}

Handle<Value> ready(const Arguments& args) {
  HandleScope scope;
  Handle<Function> fun = Handle<Function>::Cast(args[0]);
  Persistent<Function> p = Persistent<Function>::New(fun);
  application->loginCallback = p;
  return scope.Close(Undefined());
}

Handle<Value> getPlaylists(const Arguments& args) {
  HandleScope scope;
  std::vector<std::shared_ptr<Playlist>> playlists = application->playlistContainer->getPlaylists();
  Local<Array> nPlaylists = Array::New(playlists.size());
  for(int i = 0; i < (int)playlists.size(); i++) {
    NodePlaylist* nodePlaylist = new NodePlaylist(playlists[i]);
    nPlaylists->Set(Number::New(i), nodePlaylist->getV8Object());
  }
  return scope.Close(nPlaylists);
}

Handle<Value> getStarred(const Arguments& args) {
  HandleScope scope;
  NodePlaylist* starredPlaylist = new NodePlaylist(application->playlistContainer->starredPlaylist);
  return scope.Close(starredPlaylist->getV8Object());
}

/**
 * Handle a NodeCallback sent to this thread.
 * The handle should contain a NodeCallback struct
 **/
void resolveCallback(uv_async_t* handle, int status) {
  HandleScope scope;
  NodeCallback* nodeCallback = (NodeCallback*)handle->data;
  Handle<Function>* fun = nodeCallback->function;

  const unsigned int argc = 0;
  Local<Value> argv[argc] = { };
  if(!(*fun).IsEmpty() && (*fun)->IsCallable()) {
    //Check if an object is attached to the struct and if, use it as the scope.
    if(nodeCallback->object == 0 || nodeCallback->object->getV8Object().IsEmpty())
      (*fun)->Call(Context::GetCurrent()->Global(), argc, argv);
    else
      (*fun)->Call(nodeCallback->object->getV8Object(), argc, argv);
  }
  scope.Close(Undefined());
}

Handle<Value> rememberedUser(const Arguments& args) {
  HandleScope scope;
  if(application->spotifyService->rememberedUser != 0) {
    return scope.Close(String::New(application->spotifyService->rememberedUser));
  } else {
    return scope.Close(Undefined());
  }
}

void init(Handle<Object> target) {
  NodePlaylist::init();
  NodeTrack::init();
  NodeArtist::init();
  NodePlayer::init();
  NodeAlbum::init();
  NodeSearch::init(target);
  StaticCallbackSetter<NodePlaylist>::init(target, "playlists");
  application = new Application();
  application->spotifyService = std::unique_ptr<SpotifyService>(new SpotifyService());
  audio_init(&application->audio_fifo);

  target->Set(String::NewSymbol("login"),
              FunctionTemplate::New(login)->GetFunction());
  target->Set(String::NewSymbol("logout"),
              FunctionTemplate::New(logout)->GetFunction());
  target->Set(String::NewSymbol("getPlaylists"),
              FunctionTemplate::New(getPlaylists)->GetFunction());
  target->Set(String::NewSymbol("getStarred"),
              FunctionTemplate::New(getStarred)->GetFunction());
  target->Set(String::NewSymbol("ready"),
              FunctionTemplate::New(ready)->GetFunction());
  target->Set(String::NewSymbol("player"), NodePlayer::getInstance().getV8Object());
  target->Set(String::NewSymbol("rememberedUser"),
              FunctionTemplate::New(rememberedUser)->GetFunction());

  //Initialize waiting for callbacks from the spotify thread
  uv_async_init(uv_default_loop(), &application->asyncHandle, resolveCallback);
}
NODE_MODULE(spotify, init)
<commit_msg>Callbacks are now called in the fashion of function(err, object) instead of mutating this<commit_after>#include <node.h>
#include <v8.h>

#include "Application.h"
#include "SpotifyService/SpotifyService.h"
#include "NodeCallback.h"

#include "objects/node/StaticCallbackSetter.h"
#include "objects/spotify/PlaylistContainer.h"
#include "objects/node/NodePlaylist.h"
#include "objects/node/NodeTrack.h"
#include "objects/node/NodePlayer.h"
#include "objects/node/NodeAlbum.h"
#include "objects/node/NodeArtist.h"
#include "objects/node/NodeSearch.h"

extern "C" {
  #include "audio/audio.h"
}

using namespace v8;

Application* application;

Handle<Value> login(const Arguments& args) {
  HandleScope scope;
  String::Utf8Value v8User(args[0]->ToString());
  String::Utf8Value v8Password(args[1]->ToString());
  bool rememberMe = args[2]->ToBoolean()->Value();
  bool withRemembered = args[3]->ToBoolean()->Value();
  std::string user(*v8User);
  std::string password(*v8Password);
  application->spotifyService->login(user, password, rememberMe, withRemembered);
  return scope.Close(Undefined());
}

Handle<Value> logout(const Arguments& args) {
  HandleScope scope;
  auto callback = [] () { application->spotifyService->logout(); };
  application->spotifyService->executeSpotifyAPIcall(callback);
  return scope.Close(Undefined());
}

Handle<Value> ready(const Arguments& args) {
  HandleScope scope;
  Handle<Function> fun = Handle<Function>::Cast(args[0]);
  Persistent<Function> p = Persistent<Function>::New(fun);
  application->loginCallback = p;
  return scope.Close(Undefined());
}

Handle<Value> getPlaylists(const Arguments& args) {
  HandleScope scope;
  std::vector<std::shared_ptr<Playlist>> playlists = application->playlistContainer->getPlaylists();
  Local<Array> nPlaylists = Array::New(playlists.size());
  for(int i = 0; i < (int)playlists.size(); i++) {
    NodePlaylist* nodePlaylist = new NodePlaylist(playlists[i]);
    nPlaylists->Set(Number::New(i), nodePlaylist->getV8Object());
  }
  return scope.Close(nPlaylists);
}

Handle<Value> getStarred(const Arguments& args) {
  HandleScope scope;
  NodePlaylist* starredPlaylist = new NodePlaylist(application->playlistContainer->starredPlaylist);
  return scope.Close(starredPlaylist->getV8Object());
}

/**
 * Handle a NodeCallback sent to this thread.
 * The handle should contain a NodeCallback struct
 **/
void resolveCallback(uv_async_t* handle, int status) {
  HandleScope scope;
  NodeCallback* callbackStruct = (NodeCallback*)handle->data;
  Handle<Function>* callback = callbackStruct->function;

  //only execute if a callback is attached
  if(!(*callback).IsEmpty() && (*callback)->IsCallable()) {
    unsigned int argc;
    Handle<Value>* argv;
    //if the callback has a V8 object attach use it as the second argument for the callback
    //TODO: atm error is constantly undefined.
    if(callbackStruct->object != nullptr && !callbackStruct->object->getV8Object().IsEmpty()) {
      argc = 2;
      argv = new Handle<Value>[2];
      argv[0] = Undefined();
      argv[1] = callbackStruct->object->getV8Object();
    } else {
      argc = 1;
      argv = new Handle<Value>[1];
      argv[0] = Undefined();
    }

    (*callback)->Call(Context::GetCurrent()->Global(), argc, argv);
    delete[] argv;
  }
  scope.Close(Undefined());
}

Handle<Value> rememberedUser(const Arguments& args) {
  HandleScope scope;
  if(application->spotifyService->rememberedUser != 0) {
    return scope.Close(String::New(application->spotifyService->rememberedUser));
  } else {
    return scope.Close(Undefined());
  }
}

void init(Handle<Object> target) {
  NodePlaylist::init();
  NodeTrack::init();
  NodeArtist::init();
  NodePlayer::init();
  NodeAlbum::init();
  NodeSearch::init(target);
  StaticCallbackSetter<NodePlaylist>::init(target, "playlists");
  application = new Application();
  application->spotifyService = std::unique_ptr<SpotifyService>(new SpotifyService());
  audio_init(&application->audio_fifo);

  target->Set(String::NewSymbol("login"),
              FunctionTemplate::New(login)->GetFunction());
  target->Set(String::NewSymbol("logout"),
              FunctionTemplate::New(logout)->GetFunction());
  target->Set(String::NewSymbol("getPlaylists"),
              FunctionTemplate::New(getPlaylists)->GetFunction());
  target->Set(String::NewSymbol("getStarred"),
              FunctionTemplate::New(getStarred)->GetFunction());
  target->Set(String::NewSymbol("ready"),
              FunctionTemplate::New(ready)->GetFunction());
  target->Set(String::NewSymbol("player"), NodePlayer::getInstance().getV8Object());
  target->Set(String::NewSymbol("rememberedUser"),
              FunctionTemplate::New(rememberedUser)->GetFunction());

  //Initialize waiting for callbacks from the spotify thread
  uv_async_init(uv_default_loop(), &application->asyncHandle, resolveCallback);
}
NODE_MODULE(spotify, init)
<|endoftext|>


<commit_before>#include <BRepBuilderAPI_MakeShape.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <StlAPI_Writer.hxx>
#include <rice/Class.hpp>

using namespace Rice;

void shape_write_stl(Object self, const char *path)
{
    Data_Object<TopoDS_Shape> shape = self.call("render");

    StlAPI_Writer writer;
    writer.ASCIIMode() = false;
    writer.RelativeMode() = false;
    writer.SetDeflection(0.05);     // TODO: deflection param
    writer.Write(*shape, path);
}

void box_initialize(Object self, double xsize, double ysize, double zsize)
{
    self.iv_set("@xsize", xsize);
    self.iv_set("@ysize", ysize);
    self.iv_set("@zsize", zsize);

    self.iv_set("@shape",
        BRepPrimAPI_MakeBox(xsize, ysize, zsize).Shape());
}

void union_initialize(Object self, Object a, Object b)
{
    self.iv_set("@a", a);
    self.iv_set("@b", b);
}

extern "C"
void Init__yrcad()
{
    Data_Type<TopoDS_Shape> rb_cRenderedShape =
        define_class<TopoDS_Shape>("RenderedShape");

    Class rb_cShape = define_class("Shape")
        .define_method("write_stl", &shape_write_stl);

    Class rb_cBox = define_class("Box", rb_cShape)
        .define_method("initialize", &box_initialize);

    Class rb_cUnion = define_class("Union", rb_cShape)
        .define_method("initialize", &union_initialize);
}
<commit_msg>Accept String param correctly in shape_write_stl.<commit_after>#include <BRepPrimAPI_MakeBox.hxx>
#include <StlAPI_Writer.hxx>
#include <rice/Class.hpp>

using namespace Rice;

void shape_write_stl(Object self, String path)
{
    Data_Object<TopoDS_Shape> shape = self.call("render");

    StlAPI_Writer writer;
    writer.ASCIIMode() = false;
    writer.RelativeMode() = false;
    writer.SetDeflection(0.05);     // TODO: deflection param
    writer.Write(*shape, path.c_str());
}

void box_initialize(Object self, double xsize, double ysize, double zsize)
{
    self.iv_set("@xsize", xsize);
    self.iv_set("@ysize", ysize);
    self.iv_set("@zsize", zsize);

    self.iv_set("@shape",
        BRepPrimAPI_MakeBox(xsize, ysize, zsize).Shape());
}

void union_initialize(Object self, Object a, Object b)
{
    self.iv_set("@a", a);
    self.iv_set("@b", b);
}

extern "C"
void Init__yrcad()
{
    Data_Type<TopoDS_Shape> rb_cRenderedShape =
        define_class<TopoDS_Shape>("RenderedShape");

    Class rb_cShape = define_class("Shape")
        .define_method("write_stl", &shape_write_stl);

    Class rb_cBox = define_class("Box", rb_cShape)
        .define_method("initialize", &box_initialize);

    Class rb_cUnion = define_class("Union", rb_cShape)
        .define_method("initialize", &union_initialize);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "JNIHelp"

#include "JNIHelp.h"

#include "log_compat.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

/**
 * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
 */
template<typename T>
class scoped_local_ref {
public:
    scoped_local_ref(JNIEnv* env, T localRef = NULL)
    : mEnv(env), mLocalRef(localRef)
    {
    }

    ~scoped_local_ref() {
        reset();
    }

    void reset(T localRef = NULL) {
        if (mLocalRef != NULL) {
            mEnv->DeleteLocalRef(mLocalRef);
            mLocalRef = localRef;
        }
    }

    T get() const {
        return mLocalRef;
    }

private:
    JNIEnv* mEnv;
    T mLocalRef;

    // Disallow copy and assignment.
    scoped_local_ref(const scoped_local_ref&);
    void operator=(const scoped_local_ref&);
};

static jclass findClass(JNIEnv* env, const char* className) {
    return env->FindClass(className);
}

extern "C" int jniRegisterNativeMethods(JNIEnv* env, const char* className,
    const JNINativeMethod* gMethods, int numMethods)
{
    ALOGV("Registering %s's %d native methods...", className, numMethods);

    scoped_local_ref<jclass> c(env, findClass(env, className));
    if (c.get() == NULL) {
        char* msg;
        (void)asprintf(&msg, "Native registration unable to find class '%s'; aborting...",
                       className);
        env->FatalError(msg);
    }

    if (env->RegisterNatives(c.get(), gMethods, numMethods) < 0) {
        char* msg;
        (void)asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className);
        env->FatalError(msg);
    }

    return 0;
}

#ifdef __cplusplus
extern "C"
#endif
int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
    jclass exceptionClass = env->FindClass(className);

    if (exceptionClass == NULL) {
        ALOGD("Unable to find exception class %s", className);
        /* ClassNotFoundException now pending */
        return -1;
    }

    if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
        ALOGD("Failed throwing '%s' '%s'", className, msg);
        /* an exception, most likely OOM, will now be pending */
        return -1;
    }

    env->DeleteLocalRef(exceptionClass);
    return 0;
}

int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt, va_list args) {
    char msgBuf[512];
    vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
    return jniThrowException(env, className, msgBuf);
}

int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
    return jniThrowException(env, "java/lang/NullPointerException", msg);
}

int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
    return jniThrowException(env, "java/lang/RuntimeException", msg);
}

int jniThrowIOException(JNIEnv* env, int errnum) {
    char buffer[80];
    const char* message = jniStrError(errnum, buffer, sizeof(buffer));
    return jniThrowException(env, "java/io/IOException", message);
}

const char* jniStrError(int errnum, char* buf, size_t buflen) {
#if __GLIBC__
    // Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
    // char *strerror_r(int errnum, char *buf, size_t n);
    return strerror_r(errnum, buf, buflen);
#else
    int rc = strerror_r(errnum, buf, buflen);
    if (rc != 0) {
        // (POSIX only guarantees a value other than 0. The safest
        // way to implement this function is to use C++ and overload on the
        // type of strerror_r to accurately distinguish GNU from POSIX.)
        snprintf(buf, buflen, "errno %d", errnum);
    }
    return buf;
#endif
}

int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
    scoped_local_ref<jclass> localClass(env, env->FindClass("java/io/FileDescriptor"));
    static jfieldID fid = env->GetFieldID(localClass.get(), "descriptor", "I");
    if (fileDescriptor != NULL) {
        return env->GetIntField(fileDescriptor, fid);
    } else {
        return -1;
    }
}
<commit_msg>Properly select file-descriptor field on non-Android VMs for TLS ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=122108670 am: 271dc367ef am: 448f388951<commit_after>/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "JNIHelp"

#include "JNIHelp.h"

#include "log_compat.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

/**
 * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
 */
template<typename T>
class scoped_local_ref {
public:
    scoped_local_ref(JNIEnv* env, T localRef = NULL)
    : mEnv(env), mLocalRef(localRef)
    {
    }

    ~scoped_local_ref() {
        reset();
    }

    void reset(T localRef = NULL) {
        if (mLocalRef != NULL) {
            mEnv->DeleteLocalRef(mLocalRef);
            mLocalRef = localRef;
        }
    }

    T get() const {
        return mLocalRef;
    }

private:
    JNIEnv* mEnv;
    T mLocalRef;

    // Disallow copy and assignment.
    scoped_local_ref(const scoped_local_ref&);
    void operator=(const scoped_local_ref&);
};

static jclass findClass(JNIEnv* env, const char* className) {
    return env->FindClass(className);
}

extern "C" int jniRegisterNativeMethods(JNIEnv* env, const char* className,
    const JNINativeMethod* gMethods, int numMethods)
{
    ALOGV("Registering %s's %d native methods...", className, numMethods);

    scoped_local_ref<jclass> c(env, findClass(env, className));
    if (c.get() == NULL) {
        char* msg;
        (void)asprintf(&msg, "Native registration unable to find class '%s'; aborting...",
                       className);
        env->FatalError(msg);
    }

    if (env->RegisterNatives(c.get(), gMethods, numMethods) < 0) {
        char* msg;
        (void)asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className);
        env->FatalError(msg);
    }

    return 0;
}

#ifdef __cplusplus
extern "C"
#endif
int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
    jclass exceptionClass = env->FindClass(className);

    if (exceptionClass == NULL) {
        ALOGD("Unable to find exception class %s", className);
        /* ClassNotFoundException now pending */
        return -1;
    }

    if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
        ALOGD("Failed throwing '%s' '%s'", className, msg);
        /* an exception, most likely OOM, will now be pending */
        return -1;
    }

    env->DeleteLocalRef(exceptionClass);
    return 0;
}

int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt, va_list args) {
    char msgBuf[512];
    vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
    return jniThrowException(env, className, msgBuf);
}

int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
    return jniThrowException(env, "java/lang/NullPointerException", msg);
}

int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
    return jniThrowException(env, "java/lang/RuntimeException", msg);
}

int jniThrowIOException(JNIEnv* env, int errnum) {
    char buffer[80];
    const char* message = jniStrError(errnum, buffer, sizeof(buffer));
    return jniThrowException(env, "java/io/IOException", message);
}

const char* jniStrError(int errnum, char* buf, size_t buflen) {
#if __GLIBC__
    // Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
    // char *strerror_r(int errnum, char *buf, size_t n);
    return strerror_r(errnum, buf, buflen);
#else
    int rc = strerror_r(errnum, buf, buflen);
    if (rc != 0) {
        // (POSIX only guarantees a value other than 0. The safest
        // way to implement this function is to use C++ and overload on the
        // type of strerror_r to accurately distinguish GNU from POSIX.)
        snprintf(buf, buflen, "errno %d", errnum);
    }
    return buf;
#endif
}

int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
    scoped_local_ref<jclass> localClass(env, env->FindClass("java/io/FileDescriptor"));
    static jfieldID fid = env->GetFieldID(localClass.get(), "fd", "I");
    if (fileDescriptor != NULL) {
        return env->GetIntField(fileDescriptor, fid);
    } else {
        return -1;
    }
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.

#include "util/sync_point.h"

#ifndef NDEBUG
namespace rocksdb {

SyncPoint* SyncPoint::GetInstance() {
  static SyncPoint sync_point;
  return &sync_point;
}

void SyncPoint::LoadDependency(const std::vector<Dependency>& dependencies) {
  successors_.clear();
  predecessors_.clear();
  cleared_points_.clear();
  for (const auto& dependency : dependencies) {
    successors_[dependency.predecessor].push_back(dependency.successor);
    predecessors_[dependency.successor].push_back(dependency.predecessor);
  }
}

bool SyncPoint::PredecessorsAllCleared(const std::string& point) {
  for (const auto& pred : predecessors_[point]) {
    if (cleared_points_.count(pred) == 0) {
      return false;
    }
  }
  return true;
}

void SyncPoint::EnableProcessing() {
  std::unique_lock<std::mutex> lock(mutex_);
  enabled_ = true;
}

void SyncPoint::DisableProcessing() {
  std::unique_lock<std::mutex> lock(mutex_);
  enabled_ = false;
}

void SyncPoint::ClearTrace() {
  std::unique_lock<std::mutex> lock(mutex_);
  cleared_points_.clear();
}

void SyncPoint::Process(const std::string& point) {
  std::unique_lock<std::mutex> lock(mutex_);

  if (!enabled_) return;

  while (!PredecessorsAllCleared(point)) {
    cv_.wait(lock);
  }

  cleared_points_.insert(point);
  cv_.notify_all();
}

}  // namespace rocksdb
#endif  // NDEBUG
<commit_msg>Fix race in sync point.<commit_after>//  Copyright (c) 2014, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.

#include "util/sync_point.h"

#ifndef NDEBUG
namespace rocksdb {

SyncPoint* SyncPoint::GetInstance() {
  static SyncPoint sync_point;
  return &sync_point;
}

void SyncPoint::LoadDependency(const std::vector<Dependency>& dependencies) {
  std::unique_lock<std::mutex> lock(mutex_);
  successors_.clear();
  predecessors_.clear();
  cleared_points_.clear();
  for (const auto& dependency : dependencies) {
    successors_[dependency.predecessor].push_back(dependency.successor);
    predecessors_[dependency.successor].push_back(dependency.predecessor);
  }
  cv_.notify_all();
}

bool SyncPoint::PredecessorsAllCleared(const std::string& point) {
  for (const auto& pred : predecessors_[point]) {
    if (cleared_points_.count(pred) == 0) {
      return false;
    }
  }
  return true;
}

void SyncPoint::EnableProcessing() {
  std::unique_lock<std::mutex> lock(mutex_);
  enabled_ = true;
}

void SyncPoint::DisableProcessing() {
  std::unique_lock<std::mutex> lock(mutex_);
  enabled_ = false;
}

void SyncPoint::ClearTrace() {
  std::unique_lock<std::mutex> lock(mutex_);
  cleared_points_.clear();
}

void SyncPoint::Process(const std::string& point) {
  std::unique_lock<std::mutex> lock(mutex_);

  if (!enabled_) return;

  while (!PredecessorsAllCleared(point)) {
    cv_.wait(lock);
  }

  cleared_points_.insert(point);
  cv_.notify_all();
}

}  // namespace rocksdb
#endif  // NDEBUG
<|endoftext|>