<commit_before>	#include "net/resolve.h"

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

#ifndef _WIN32
#include <arpa/inet.h>
#include <netdb.h>	// gethostbyname
#include <sys/socket.h>
#else
#include <WinSock2.h>
#include <Ws2tcpip.h>
#undef min
#undef max
#endif

namespace net {

void Init()
{
#ifdef _WIN32
	WSADATA wsaData = {0};
	WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
}

void Shutdown()
{
#ifdef _WIN32
	WSACleanup();
#endif
}

char *DNSResolveTry(const char *host, const char **err)
{
	struct hostent *hent;
	if((hent = gethostbyname(host)) == NULL)
	{
		*err = "Can't get IP";
		return NULL;
	}
	int iplen = 15; //XXX.XXX.XXX.XXX
	char *ip = (char *)malloc(iplen+1);
	memset(ip, 0, iplen+1);
	char *iptoa = inet_ntoa(*(in_addr *)hent->h_addr_list[0]);
	if (iptoa == NULL)
	{
		*err = "Can't resolve host";
		return NULL;
	}
	strncpy(ip, iptoa, iplen);
	return ip;
}

char *DNSResolve(const char *host)
{
	const char *err;
	char *ip = DNSResolveTry(host, &err);
	if (ip == NULL)
	{
		perror(err);
		exit(1);
	}
	return ip;
}

int inet_pton(int af, const char* src, void* dst)
{
	if (af == AF_INET)
	{
		BYTE *ip = (BYTE *)dst;
		int k = 0, x = 0;
		char ch;
		for (int i = 0; (ch = src[i]) != 0; i++)
		{
			if (ch == '.')
			{
				ip[k++] = x;
				if (k == 4)
					return 0;
				x = 0;
			}
			else if (ch < '0' || ch > '9')
				return 0;
			else
				x = x * 10 + ch - '0';
			if (x > 255)
				return 0;
		}
		ip[k++] = x;
		if (k != 4)
			return 0;
	}
	else if (af == AF_INET6)
	{
		unsigned short* ip = ( unsigned short* )dst;
		int i;
		for (i = 0; i < 8; i++) ip[i] = 0;
		int k = 0;
		unsigned int x = 0;
		char ch;
		int marknum = 0;
		for (i = 0; src[i] != 0; i++)
		{
			if (src[i] == ':')
				marknum++;
		}
		for (i = 0; (ch = src[i]) != 0; i++)
		{
			if (ch == ':')
			{
				x = ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8);
				ip[k++] = x;
				if (k == 8)
					return 0;
				x = 0;
				if (i > 0 && src[i - 1] == ':')
					k += 7 - marknum;
			}
			else if (ch >= '0' && ch <= '9')
				x = x * 16 + ch - '0';
			else if (ch >= 'a' && ch <= 'f')
				x = x * 16 + ch - 'a' + 10;
			else if (ch >= 'A' && ch <= 'F')
				x = x * 16 + ch - 'A' + 10;
			else
				return 0;
			if (x > 0xFFFF)
				return 0;
		}
		x = ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8);
		ip[k++] = x;
		if (k != 8)
			return 0;
	}
	return 1;
}

}
<commit_msg>Buildfix.<commit_after>	#include "net/resolve.h"

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

#ifndef _WIN32
#include <arpa/inet.h>
#include <netdb.h>	// gethostbyname
#include <sys/socket.h>
#else
#include <WinSock2.h>
#include <Ws2tcpip.h>
#undef min
#undef max
#endif

namespace net {

void Init()
{
#ifdef _WIN32
	WSADATA wsaData = {0};
	WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
}

void Shutdown()
{
#ifdef _WIN32
	WSACleanup();
#endif
}

char *DNSResolveTry(const char *host, const char **err)
{
	struct hostent *hent;
	if((hent = gethostbyname(host)) == NULL)
	{
		*err = "Can't get IP";
		return NULL;
	}
	int iplen = 15; //XXX.XXX.XXX.XXX
	char *ip = (char *)malloc(iplen+1);
	memset(ip, 0, iplen+1);
	char *iptoa = inet_ntoa(*(in_addr *)hent->h_addr_list[0]);
	if (iptoa == NULL)
	{
		*err = "Can't resolve host";
		return NULL;
	}
	strncpy(ip, iptoa, iplen);
	return ip;
}

char *DNSResolve(const char *host)
{
	const char *err;
	char *ip = DNSResolveTry(host, &err);
	if (ip == NULL)
	{
		perror(err);
		exit(1);
	}
	return ip;
}

int inet_pton(int af, const char* src, void* dst)
{
	if (af == AF_INET)
	{
		unsigned char *ip = (unsigned char *)dst;
		int k = 0, x = 0;
		char ch;
		for (int i = 0; (ch = src[i]) != 0; i++)
		{
			if (ch == '.')
			{
				ip[k++] = x;
				if (k == 4)
					return 0;
				x = 0;
			}
			else if (ch < '0' || ch > '9')
				return 0;
			else
				x = x * 10 + ch - '0';
			if (x > 255)
				return 0;
		}
		ip[k++] = x;
		if (k != 4)
			return 0;
	}
	else if (af == AF_INET6)
	{
		unsigned short* ip = ( unsigned short* )dst;
		int i;
		for (i = 0; i < 8; i++) ip[i] = 0;
		int k = 0;
		unsigned int x = 0;
		char ch;
		int marknum = 0;
		for (i = 0; src[i] != 0; i++)
		{
			if (src[i] == ':')
				marknum++;
		}
		for (i = 0; (ch = src[i]) != 0; i++)
		{
			if (ch == ':')
			{
				x = ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8);
				ip[k++] = x;
				if (k == 8)
					return 0;
				x = 0;
				if (i > 0 && src[i - 1] == ':')
					k += 7 - marknum;
			}
			else if (ch >= '0' && ch <= '9')
				x = x * 16 + ch - '0';
			else if (ch >= 'a' && ch <= 'f')
				x = x * 16 + ch - 'a' + 10;
			else if (ch >= 'A' && ch <= 'F')
				x = x * 16 + ch - 'A' + 10;
			else
				return 0;
			if (x > 0xFFFF)
				return 0;
		}
		x = ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8);
		ip[k++] = x;
		if (k != 8)
			return 0;
	}
	return 1;
}

}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// This file is part of Swift2D.                                              //
//                                                                            //
// Copyright: (c) 2011-2014 Simon Schneegans & Felix Lauer                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// includes  -------------------------------------------------------------------
#include <swift2d/network/Network.hpp>

#include <swift2d/network/ReplicationManager.hpp>
#include <swift2d/utils/Logger.hpp>
#include <swift2d/math/operators.hpp>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <raknet/src/MessageIdentifiers.h>
#include <raknet/src/RakNetTypes.h>
#include <raknet/src/RakPeerInterface.h>
#include <raknet/src/BitStream.h>
#include <raknet/src/FullyConnectedMesh2.h>
#include <raknet/src/PacketLogger.h>
#include <raknet/src/NatTypeDetectionClient.h>

#include <sstream>

#define USE_UPNP false

namespace swift {

////////////////////////////////////////////////////////////////////////////////

Network::Network()
  : phase_(SEARCHING_FOR_OTHER_INSTANCES) {

  update_timer_.start();

  Logger::LOG_MESSAGE << "I'm " << get_own_id() << std::endl;
}

////////////////////////////////////////////////////////////////////////////////

void Network::disconnect() {
  if (phase_ == HOSTING_INSTANCE) {
    Logger::LOG_MESSAGE << "Unregistering game." << std::endl;
    unregister_game();
  }
}

////////////////////////////////////////////////////////////////////////////////

uint64_t Network::get_own_id() {
  return peer_.get_guid();
}

////////////////////////////////////////////////////////////////////////////////

void Network::connect(std::string const& game_ID) {
  game_ID_ = game_ID;

  http_.on_response.connect([&](std::string const& response) {
    switch (phase_) {

      // -----------------------------------------------------------------------
      case SEARCHING_FOR_OTHER_INSTANCES: {
        Logger::LOG_MESSAGE << "Got response from master server." << std::endl;

        bool found_other_game(false);

        try {
          boost::property_tree::ptree tree;
          std::istringstream is(response);
          boost::property_tree::read_json(is, tree);

          if (tree.get_child("GET").size() > 0) {
            host_guid_        = tree.get_child("GET").front().second.get<uint64_t>("guid");
            found_other_game  = true;
          }

        } catch(std::runtime_error const& e) {
          Logger::LOG_WARNING << "Failed to parse response: " << e.what() << std::endl;
        }

        if (found_other_game) enter_phase(CONNECTING_TO_HOST);
        else                  enter_phase(STARTING_NEW_INSTANCE);

        } break;

      // -----------------------------------------------------------------------
      case STARTING_NEW_INSTANCE:
        Logger::LOG_MESSAGE << "Successfully registered new instance." << std::endl;
        enter_phase(HOSTING_INSTANCE);
        break;

      // -----------------------------------------------------------------------
      case HOSTING_INSTANCE:
        // ignore reply
        break;

      // -----------------------------------------------------------------------
      default:
        Logger::LOG_WARNING << "Got unexpected HTTP response." << std::endl;
        break;
    }
  });

  upnp_.on_success.connect([&](){
    Logger::LOG_MESSAGE << "Successfully opened UPNP." << std::endl;
    enter_phase(SEARCHING_FOR_OTHER_INSTANCES);
  });

  upnp_.on_fail.connect([&](){
    Logger::LOG_MESSAGE << "Failed to open UPNP. Using NAT punch through." << std::endl;
    enter_phase(OPENING_UPNP);
  });

  enter_phase(HOSTING_INSTANCE);
}

////////////////////////////////////////////////////////////////////////////////

void Network::update() {

  auto register_new_peer = [&](RakNet::RakNetGUID guid){
    RakNet::Connection_RM3 *connection = peer_.replica_->AllocConnection(peer_.peer_->GetSystemAddressFromGuid(guid), guid);
    if (peer_.replica_->PushConnection(connection) == false) {
      peer_.replica_->DeallocConnection(connection);
    }
  };

  http_.update();

  if (phase_ == HOSTING_INSTANCE && update_timer_.get_elapsed() > 10.0) {
    register_game();
    update_timer_.reset();
  }

  for (RakNet::Packet* packet=peer_.peer_->Receive(); packet; peer_.peer_->DeallocatePacket(packet), packet=peer_.peer_->Receive()) {
          Logger::LOG_MESSAGE << RakNet::PacketLogger::BaseIDTOString(packet->data[0]) << std::endl;
    switch (packet->data[0]) {

      // ##################### BASIC PACKETS ###################################
      // -----------------------------------------------------------------------
      case ID_CONNECTION_REQUEST_ACCEPTED:
        if (phase_ == CONNECTING_TO_SERVER) {
          Logger::LOG_MESSAGE << "Connected to NAT server." << std::endl;
          nat_server_address_ = packet->systemAddress.ToString();

          if (USE_UPNP)          enter_phase(OPENING_UPNP);
          else                   enter_phase(SEARCHING_FOR_OTHER_INSTANCES);

        } else if (phase_ == CONNECTING_TO_HOST) {
          Logger::LOG_MESSAGE << "Connected to host " << packet->guid.ToString() << ". Sending join request." << std::endl;
          peer_.request_join(packet->guid.g);

        } else if (phase_ == HOSTING_INSTANCE) {
          Logger::LOG_MESSAGE << "Connected to client " << packet->guid.ToString() << "." << std::endl;
        }
        break;

      // -----------------------------------------------------------------------
      case ID_DISCONNECTION_NOTIFICATION:
        Logger::LOG_MESSAGE << packet->guid.ToString() << " disconnected." << std::endl;
        break;

      // ################ NAT PUNCH THROUGH PACKETS ############################
      // -----------------------------------------------------------------------
      case ID_NAT_PUNCHTHROUGH_SUCCEEDED:
        if (phase_ == CONNECTING_TO_HOST || phase_ == CONNECTING_TO_PEERS) {
          Logger::LOG_MESSAGE << "NAT punch succeeded. Connecting..." << std::endl;
          peer_.connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort());
        }
        break;

      // -----------------------------------------------------------------------
      case ID_NAT_PUNCHTHROUGH_FAILED:
        Logger::LOG_MESSAGE << "NAT punch through failed." << std::endl;
        break;

      // -----------------------------------------------------------------------
      case ID_NAT_TYPE_DETECTION_RESULT: {
        auto type = (RakNet::NATTypeDetectionResult) packet->data[1];
        Logger::LOG_MESSAGE << "NAT Type is " << RakNet::NATTypeDetectionResultToString(type) << " (" << RakNet::NATTypeDetectionResultToStringFriendly(type) << ")" << std::endl;

        if (USE_UPNP) enter_phase(OPENING_UPNP);
        else          enter_phase(SEARCHING_FOR_OTHER_INSTANCES);
        } break;

      // ################## FULLY CONNECTED MESH ###############################
      // -----------------------------------------------------------------------
      case ID_FCM2_NEW_HOST: {
        RakNet::BitStream bs(packet->data, packet->length, false);
        bs.IgnoreBytes(1);
        RakNet::RakNetGUID old_host;
        bs.Read(old_host);

        if (packet->guid.g == peer_.get_guid()) {
          if (phase_ != HOSTING_INSTANCE) {
            enter_phase(HOSTING_INSTANCE);
          }
        } else {
          Logger::LOG_MESSAGE << packet->guid.ToString() << " is host now." << std::endl;

          if (old_host != RakNet::UNASSIGNED_RAKNET_GUID) {
            Logger::LOG_MESSAGE << "Old host was " << old_host.ToString() << std::endl;
          } else {
            Logger::LOG_MESSAGE << "There was no host before." << std::endl;
          }
        }

        if (old_host == RakNet::UNASSIGNED_RAKNET_GUID) {
          DataStructures::List<RakNet::RakNetGUID> peers;
          peer_.mesh_->GetParticipantList(peers);
          for (unsigned int i=0; i < peers.Size(); i++) {
            register_new_peer(peers[i]);
          }
        }

        } break;

      // -----------------------------------------------------------------------
      case (ID_USER_PACKET_ENUM + REQUEST_JOIN):
        Logger::LOG_MESSAGE << "Got join request from " << packet->guid.ToString() << "." << std::endl;
        peer_.start_join(packet->guid.g);
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_CAPABLE:
        peer_.mesh_->RespondOnVerifiedJoinCapable(packet, true, 0);
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_ACCEPTED: {
        DataStructures::List<RakNet::RakNetGUID> peers;
        bool this_was_accepted;
        peer_.mesh_->GetVerifiedJoinAcceptedAdditionalData(packet, &this_was_accepted, peers, 0);
        if (this_was_accepted) {
          Logger::LOG_MESSAGE << "Join accepted." << std::endl;
        } else {
          Logger::LOG_MESSAGE << "Peer " << peers[0].ToString() << " joined the game." << std::endl;
        }

        if (peer_.mesh_->GetConnectedHost() != RakNet::UNASSIGNED_RAKNET_GUID) {
          for (unsigned int i=0; i < peers.Size(); i++) {
            register_new_peer(peers[i]);
          }
        }

        if (this_was_accepted) {
          enter_phase(PARTICIPATING);
        }

      } break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_REJECTED:
        Logger::LOG_MESSAGE << "Join rejected." << std::endl;
        peer_.peer_->CloseConnection(packet->guid, true);
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_FAILED:
        Logger::LOG_MESSAGE << "Join failed." << std::endl;
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_START:
        Logger::LOG_MESSAGE << "Connecting to other peers..." << std::endl;
        enter_phase(CONNECTING_TO_PEERS);
        peer_.join(packet->guid.g, nat_server_address_);
        break;

      // ##################### OTHER PACKETS ###################################
      case ID_ADVERTISE_SYSTEM:
        Logger::LOG_MESSAGE << "Got ID_ADVERTISE_SYSTEM" << std::endl;
        if (packet->guid!=peer_.peer_->GetMyGUID()) {
          peer_.peer_->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0);
        }
        break;

      // -----------------------------------------------------------------------
      default:
        Logger::LOG_TRACE << "Got " << RakNet::PacketLogger::BaseIDTOString(packet->data[0])
                          << " from " << packet->guid.ToString() << std::endl;
        break;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

void Network::distribute_object(NetworkObjectBase* object) {
  peer_.replica_->Reference(object);
}

////////////////////////////////////////////////////////////////////////////////

bool Network::is_host() const {
  return peer_.mesh_->IsConnectedHost();
}

////////////////////////////////////////////////////////////////////////////////

void Network::enter_phase(Phase phase) {
  phase_ = phase;

  switch (phase) {

    // -------------------------------------------------------------------------
    case CONNECTING_TO_SERVER:
      Logger::LOG_MESSAGE << "Connecting to NAT server..." << std::endl;
      peer_.connect("natpunch.jenkinssoftware.com", 61111);
      break;

    // -------------------------------------------------------------------------
    case OPENING_UPNP:
      Logger::LOG_MESSAGE << "Opening UPNP..." << std::endl;
      upnp_.open(peer_);
      break;

    // -------------------------------------------------------------------------
    case SEARCHING_FOR_OTHER_INSTANCES:
      Logger::LOG_MESSAGE << "Downloading running instances from "
                          << "master server..." << std::endl;
      http_.get("masterserver2.raknet.com/testServer?__gameId=" + game_ID_,
                "masterserver2.raknet.com", 80);
      break;

    // -------------------------------------------------------------------------
    case CONNECTING_TO_HOST:
      Logger::LOG_MESSAGE << "Found running instance. Searching route to host "
                          << host_guid_ << "..." << std::endl;
      peer_.open_nat(host_guid_, nat_server_address_);
      break;

    // -------------------------------------------------------------------------
    case STARTING_NEW_INSTANCE:
      Logger::LOG_MESSAGE << "No running instances found. "
                          << "Starting new instance..." << std::endl;
      peer_.mesh_->ResetHostCalculation();
      register_game();
      update_timer_.reset();
      break;

    // -------------------------------------------------------------------------
    case HOSTING_INSTANCE:
      Logger::LOG_MESSAGE << "I'm host now." << std::endl;
      register_game();
      update_timer_.reset();
      break;

    // -------------------------------------------------------------------------
    case PARTICIPATING:
      Logger::LOG_MESSAGE << "Participating game." << std::endl;
      break;
  }
}

////////////////////////////////////////////////////////////////////////////////

void Network::register_game() {
  std::stringstream game_descriptor;
  game_descriptor << "{'__gameId': '" << game_ID_ << "', '__clientReqId': '0', "
                  << "'__rowId': '0', '__timeoutSec': '45', "
                  << "'guid': '" << peer_.peer_->GetMyGUID().ToString() << "' }";

  http_.post("masterserver2.raknet.com/testServer", game_descriptor.str(),
             "masterserver2.raknet.com", 80);
}

////////////////////////////////////////////////////////////////////////////////

void Network::unregister_game() {
  http_.del("masterserver2.raknet.com/testServer?__gameId=" + game_ID_ + "&__rowId=0",
            "masterserver2.raknet.com", 80);
}

////////////////////////////////////////////////////////////////////////////////

}
<commit_msg>worked on network<commit_after>////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// This file is part of Swift2D.                                              //
//                                                                            //
// Copyright: (c) 2011-2014 Simon Schneegans & Felix Lauer                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// includes  -------------------------------------------------------------------
#include <swift2d/network/Network.hpp>

#include <swift2d/network/ReplicationManager.hpp>
#include <swift2d/utils/Logger.hpp>
#include <swift2d/math/operators.hpp>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <raknet/src/MessageIdentifiers.h>
#include <raknet/src/RakNetTypes.h>
#include <raknet/src/RakPeerInterface.h>
#include <raknet/src/BitStream.h>
#include <raknet/src/FullyConnectedMesh2.h>
#include <raknet/src/PacketLogger.h>
#include <raknet/src/NatTypeDetectionClient.h>

#include <sstream>

#define USE_UPNP false

namespace swift {

////////////////////////////////////////////////////////////////////////////////

Network::Network()
  : phase_(CONNECTING_TO_HOST) {

  update_timer_.start();

  Logger::LOG_MESSAGE << "I'm " << get_own_id() << std::endl;
}

////////////////////////////////////////////////////////////////////////////////

void Network::disconnect() {
  if (phase_ == HOSTING_INSTANCE) {
    Logger::LOG_MESSAGE << "Unregistering game." << std::endl;
    unregister_game();
  }
}

////////////////////////////////////////////////////////////////////////////////

uint64_t Network::get_own_id() {
  return peer_.get_guid();
}

////////////////////////////////////////////////////////////////////////////////

void Network::connect(std::string const& game_ID) {
  game_ID_ = game_ID;

  http_.on_response.connect([&](std::string const& response) {
    switch (phase_) {

      // -----------------------------------------------------------------------
      case SEARCHING_FOR_OTHER_INSTANCES: {
        Logger::LOG_MESSAGE << "Got response from master server." << std::endl;

        bool found_other_game(false);

        try {
          boost::property_tree::ptree tree;
          std::istringstream is(response);
          boost::property_tree::read_json(is, tree);

          if (tree.get_child("GET").size() > 0) {
            host_guid_        = tree.get_child("GET").front().second.get<uint64_t>("guid");
            found_other_game  = true;
          }

        } catch(std::runtime_error const& e) {
          Logger::LOG_WARNING << "Failed to parse response: " << e.what() << std::endl;
        }

        if (found_other_game) enter_phase(CONNECTING_TO_HOST);
        else                  enter_phase(STARTING_NEW_INSTANCE);

        } break;

      // -----------------------------------------------------------------------
      case STARTING_NEW_INSTANCE:
        Logger::LOG_MESSAGE << "Successfully registered new instance." << std::endl;
        enter_phase(HOSTING_INSTANCE);
        break;

      // -----------------------------------------------------------------------
      case HOSTING_INSTANCE:
        // ignore reply
        break;

      // -----------------------------------------------------------------------
      default:
        Logger::LOG_WARNING << "Got unexpected HTTP response." << std::endl;
        break;
    }
  });

  upnp_.on_success.connect([&](){
    Logger::LOG_MESSAGE << "Successfully opened UPNP." << std::endl;
    enter_phase(SEARCHING_FOR_OTHER_INSTANCES);
  });

  upnp_.on_fail.connect([&](){
    Logger::LOG_MESSAGE << "Failed to open UPNP. Using NAT punch through." << std::endl;
    enter_phase(OPENING_UPNP);
  });

  enter_phase(HOSTING_INSTANCE);
}

////////////////////////////////////////////////////////////////////////////////

void Network::update() {

  auto register_new_peer = [&](RakNet::RakNetGUID guid){
    RakNet::Connection_RM3 *connection = peer_.replica_->AllocConnection(peer_.peer_->GetSystemAddressFromGuid(guid), guid);
    if (peer_.replica_->PushConnection(connection) == false) {
      peer_.replica_->DeallocConnection(connection);
    }
  };

  http_.update();

  if (phase_ == HOSTING_INSTANCE && update_timer_.get_elapsed() > 10.0) {
    register_game();
    update_timer_.reset();
  }

  for (RakNet::Packet* packet=peer_.peer_->Receive(); packet; peer_.peer_->DeallocatePacket(packet), packet=peer_.peer_->Receive()) {
          Logger::LOG_MESSAGE << RakNet::PacketLogger::BaseIDTOString(packet->data[0]) << std::endl;
    switch (packet->data[0]) {

      // ##################### BASIC PACKETS ###################################
      // -----------------------------------------------------------------------
      case ID_CONNECTION_REQUEST_ACCEPTED:
        if (phase_ == CONNECTING_TO_SERVER) {
          Logger::LOG_MESSAGE << "Connected to NAT server." << std::endl;
          nat_server_address_ = packet->systemAddress.ToString();

          if (USE_UPNP)          enter_phase(OPENING_UPNP);
          else                   enter_phase(SEARCHING_FOR_OTHER_INSTANCES);

        } else if (phase_ == CONNECTING_TO_HOST) {
          Logger::LOG_MESSAGE << "Connected to host " << packet->guid.ToString() << ". Sending join request." << std::endl;
          peer_.request_join(packet->guid.g);

        } else if (phase_ == HOSTING_INSTANCE) {
          Logger::LOG_MESSAGE << "Connected to client " << packet->guid.ToString() << "." << std::endl;
        }
        break;

      // -----------------------------------------------------------------------
      case ID_DISCONNECTION_NOTIFICATION:
        Logger::LOG_MESSAGE << packet->guid.ToString() << " disconnected." << std::endl;
        break;

      // ################ NAT PUNCH THROUGH PACKETS ############################
      // -----------------------------------------------------------------------
      case ID_NAT_PUNCHTHROUGH_SUCCEEDED:
        if (phase_ == CONNECTING_TO_HOST || phase_ == CONNECTING_TO_PEERS) {
          Logger::LOG_MESSAGE << "NAT punch succeeded. Connecting..." << std::endl;
          peer_.connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort());
        }
        break;

      // -----------------------------------------------------------------------
      case ID_NAT_PUNCHTHROUGH_FAILED:
        Logger::LOG_MESSAGE << "NAT punch through failed." << std::endl;
        break;

      // -----------------------------------------------------------------------
      case ID_NAT_TYPE_DETECTION_RESULT: {
        auto type = (RakNet::NATTypeDetectionResult) packet->data[1];
        Logger::LOG_MESSAGE << "NAT Type is " << RakNet::NATTypeDetectionResultToString(type) << " (" << RakNet::NATTypeDetectionResultToStringFriendly(type) << ")" << std::endl;

        if (USE_UPNP) enter_phase(OPENING_UPNP);
        else          enter_phase(SEARCHING_FOR_OTHER_INSTANCES);
        } break;

      // ################## FULLY CONNECTED MESH ###############################
      // -----------------------------------------------------------------------
      case ID_FCM2_NEW_HOST: {
        RakNet::BitStream bs(packet->data, packet->length, false);
        bs.IgnoreBytes(1);
        RakNet::RakNetGUID old_host;
        bs.Read(old_host);

        if (packet->guid.g == peer_.get_guid()) {
          if (phase_ != HOSTING_INSTANCE) {
            enter_phase(HOSTING_INSTANCE);
          }
        } else {
          Logger::LOG_MESSAGE << packet->guid.ToString() << " is host now." << std::endl;

          if (old_host != RakNet::UNASSIGNED_RAKNET_GUID) {
            Logger::LOG_MESSAGE << "Old host was " << old_host.ToString() << std::endl;
          } else {
            Logger::LOG_MESSAGE << "There was no host before." << std::endl;
          }
        }

        if (old_host == RakNet::UNASSIGNED_RAKNET_GUID) {
          DataStructures::List<RakNet::RakNetGUID> peers;
          peer_.mesh_->GetParticipantList(peers);
          for (unsigned int i=0; i < peers.Size(); i++) {
            register_new_peer(peers[i]);
          }
        }

        } break;

      // -----------------------------------------------------------------------
      case (ID_USER_PACKET_ENUM + REQUEST_JOIN):
        Logger::LOG_MESSAGE << "Got join request from " << packet->guid.ToString() << "." << std::endl;
        peer_.start_join(packet->guid.g);
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_CAPABLE:
        peer_.mesh_->RespondOnVerifiedJoinCapable(packet, true, 0);
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_ACCEPTED: {
        DataStructures::List<RakNet::RakNetGUID> peers;
        bool this_was_accepted;
        peer_.mesh_->GetVerifiedJoinAcceptedAdditionalData(packet, &this_was_accepted, peers, 0);
        if (this_was_accepted) {
          Logger::LOG_MESSAGE << "Join accepted." << std::endl;
        } else {
          Logger::LOG_MESSAGE << "Peer " << peers[0].ToString() << " joined the game." << std::endl;
        }

        if (peer_.mesh_->GetConnectedHost() != RakNet::UNASSIGNED_RAKNET_GUID) {
          for (unsigned int i=0; i < peers.Size(); i++) {
            register_new_peer(peers[i]);
          }
        }

        if (this_was_accepted) {
          enter_phase(PARTICIPATING);
        }

      } break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_REJECTED:
        Logger::LOG_MESSAGE << "Join rejected." << std::endl;
        peer_.peer_->CloseConnection(packet->guid, true);
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_FAILED:
        Logger::LOG_MESSAGE << "Join failed." << std::endl;
        break;

      // -----------------------------------------------------------------------
      case ID_FCM2_VERIFIED_JOIN_START:
        Logger::LOG_MESSAGE << "Connecting to other peers..." << std::endl;
        enter_phase(CONNECTING_TO_PEERS);
        peer_.join(packet->guid.g, nat_server_address_);
        break;

      // ##################### OTHER PACKETS ###################################
      case ID_ADVERTISE_SYSTEM:
        Logger::LOG_MESSAGE << "Got ID_ADVERTISE_SYSTEM" << std::endl;
        if (packet->guid!=peer_.peer_->GetMyGUID()) {
          peer_.peer_->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0);
        }
        break;

      // -----------------------------------------------------------------------
      default:
        Logger::LOG_TRACE << "Got " << RakNet::PacketLogger::BaseIDTOString(packet->data[0])
                          << " from " << packet->guid.ToString() << std::endl;
        break;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

void Network::distribute_object(NetworkObjectBase* object) {
  peer_.replica_->Reference(object);
}

////////////////////////////////////////////////////////////////////////////////

bool Network::is_host() const {
  return peer_.mesh_->IsConnectedHost();
}

////////////////////////////////////////////////////////////////////////////////

void Network::enter_phase(Phase phase) {
  phase_ = phase;

  switch (phase) {

    // -------------------------------------------------------------------------
    case CONNECTING_TO_SERVER:
      Logger::LOG_MESSAGE << "Connecting to NAT server..." << std::endl;
      peer_.connect("natpunch.jenkinssoftware.com", 61111);
      break;

    // -------------------------------------------------------------------------
    case OPENING_UPNP:
      Logger::LOG_MESSAGE << "Opening UPNP..." << std::endl;
      upnp_.open(peer_);
      break;

    // -------------------------------------------------------------------------
    case SEARCHING_FOR_OTHER_INSTANCES:
      Logger::LOG_MESSAGE << "Downloading running instances from "
                          << "master server..." << std::endl;
      http_.get("masterserver2.raknet.com/testServer?__gameId=" + game_ID_,
                "masterserver2.raknet.com", 80);
      break;

    // -------------------------------------------------------------------------
    case CONNECTING_TO_HOST:
      Logger::LOG_MESSAGE << "Found running instance. Searching route to host "
                          << host_guid_ << "..." << std::endl;
      peer_.open_nat(host_guid_, nat_server_address_);
      break;

    // -------------------------------------------------------------------------
    case STARTING_NEW_INSTANCE:
      Logger::LOG_MESSAGE << "No running instances found. "
                          << "Starting new instance..." << std::endl;
      peer_.mesh_->ResetHostCalculation();
      register_game();
      update_timer_.reset();
      break;

    // -------------------------------------------------------------------------
    case HOSTING_INSTANCE:
      Logger::LOG_MESSAGE << "I'm host now." << std::endl;
      register_game();
      update_timer_.reset();
      break;

    // -------------------------------------------------------------------------
    case PARTICIPATING:
      Logger::LOG_MESSAGE << "Participating game." << std::endl;
      break;
  }
}

////////////////////////////////////////////////////////////////////////////////

void Network::register_game() {
  std::stringstream game_descriptor;
  game_descriptor << "{'__gameId': '" << game_ID_ << "', '__clientReqId': '0', "
                  << "'__rowId': '0', '__timeoutSec': '45', "
                  << "'guid': '" << peer_.peer_->GetMyGUID().ToString() << "' }";

  http_.post("masterserver2.raknet.com/testServer", game_descriptor.str(),
             "masterserver2.raknet.com", 80);
}

////////////////////////////////////////////////////////////////////////////////

void Network::unregister_game() {
  http_.del("masterserver2.raknet.com/testServer?__gameId=" + game_ID_ + "&__rowId=0",
            "masterserver2.raknet.com", 80);
}

////////////////////////////////////////////////////////////////////////////////

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 */

#include "QXmppArchiveIq.h"
#include "QXmppArchiveManager.h"
#include "QXmppStream.h"

#include <QDebug>

QXmppArchiveManager::QXmppArchiveManager(QXmppStream *stream, QObject *parent)
    : QObject(parent),
    m_stream(stream)
{
    bool check = QObject::connect(m_stream, SIGNAL(archiveChatIqReceived(const QXmppArchiveChatIq&)),
        this, SLOT(archiveChatIqReceived(const QXmppArchiveChatIq&)));
    Q_ASSERT(check);

    check = QObject::connect(m_stream, SIGNAL(archiveListIqReceived(const QXmppArchiveListIq&)),
        this, SLOT(archiveListIqReceived(const QXmppArchiveListIq&)));
    Q_ASSERT(check);

    check = QObject::connect(m_stream, SIGNAL(archivePrefIqReceived(const QXmppArchivePrefIq&)),
        this, SLOT(archivePrefIqReceived(const QXmppArchivePrefIq&)));
    Q_ASSERT(check);
}

void QXmppArchiveManager::archiveChatIqReceived(const QXmppArchiveChatIq &chatIq)
{
    emit archiveChatReceived(chatIq.chat());
}

void QXmppArchiveManager::archiveListIqReceived(const QXmppArchiveListIq &listIq)
{
    emit archiveListReceived(listIq.chats());
}

void QXmppArchiveManager::archivePrefIqReceived(const QXmppArchivePrefIq &prefIq)
{
    Q_UNUSED(prefIq);
}

/// Retrieves the list of available collections. Once the results are
/// received, the archiveChatReceived() signal will be emitted.
///
/// \param jid Optional JID if you only want conversations with a specific JID.
/// \param start Optional start time.
/// \param end Optional end time.
/// \param max Optional maximum.
///
void QXmppArchiveManager::listCollections(const QString &jid, const QDateTime &start, const QDateTime &end, int max)
{
    QXmppArchiveListIq packet;
    packet.setMax(max);
    packet.setWith(jid);
    packet.setStart(start);
    packet.setEnd(end);
    m_stream->sendPacket(packet);
}

/// Retrieves the specified collection. Once the results are received,
/// the archiveChatReceived() will be emitted.
///
/// \param jid The JID of the collection
/// \param start The start time of the collection.
/// \param max Optional maximum number of messages to retrieve.
///
void QXmppArchiveManager::retrieveCollection(const QString &jid, const QDateTime &start, int max)
{
    QXmppArchiveRetrieveIq packet;
    packet.setMax(max);
    packet.setStart(start);
    packet.setWith(jid);
    m_stream->sendPacket(packet);
}

#if 0
void QXmppArchiveManager::getPreferences()
{
    QXmppArchivePrefIq packet;
    m_stream->sendPacket(packet);
}
#endif
<commit_msg>typo fix<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 */

#include "QXmppArchiveIq.h"
#include "QXmppArchiveManager.h"
#include "QXmppStream.h"

#include <QDebug>

QXmppArchiveManager::QXmppArchiveManager(QXmppStream *stream, QObject *parent)
    : QObject(parent),
    m_stream(stream)
{
    bool check = QObject::connect(m_stream, SIGNAL(archiveChatIqReceived(const QXmppArchiveChatIq&)),
        this, SLOT(archiveChatIqReceived(const QXmppArchiveChatIq&)));
    Q_ASSERT(check);

    check = QObject::connect(m_stream, SIGNAL(archiveListIqReceived(const QXmppArchiveListIq&)),
        this, SLOT(archiveListIqReceived(const QXmppArchiveListIq&)));
    Q_ASSERT(check);

    check = QObject::connect(m_stream, SIGNAL(archivePrefIqReceived(const QXmppArchivePrefIq&)),
        this, SLOT(archivePrefIqReceived(const QXmppArchivePrefIq&)));
    Q_ASSERT(check);
}

void QXmppArchiveManager::archiveChatIqReceived(const QXmppArchiveChatIq &chatIq)
{
    emit archiveChatReceived(chatIq.chat());
}

void QXmppArchiveManager::archiveListIqReceived(const QXmppArchiveListIq &listIq)
{
    emit archiveListReceived(listIq.chats());
}

void QXmppArchiveManager::archivePrefIqReceived(const QXmppArchivePrefIq &prefIq)
{
    Q_UNUSED(prefIq);
}

/// Retrieves the list of available collections. Once the results are
/// received, the archiveListReceived() signal will be emitted.
///
/// \param jid Optional JID if you only want conversations with a specific JID.
/// \param start Optional start time.
/// \param end Optional end time.
/// \param max Optional maximum.
///
void QXmppArchiveManager::listCollections(const QString &jid, const QDateTime &start, const QDateTime &end, int max)
{
    QXmppArchiveListIq packet;
    packet.setMax(max);
    packet.setWith(jid);
    packet.setStart(start);
    packet.setEnd(end);
    m_stream->sendPacket(packet);
}

/// Retrieves the specified collection. Once the results are received,
/// the archiveChatReceived() will be emitted.
///
/// \param jid The JID of the collection
/// \param start The start time of the collection.
/// \param max Optional maximum number of messages to retrieve.
///
void QXmppArchiveManager::retrieveCollection(const QString &jid, const QDateTime &start, int max)
{
    QXmppArchiveRetrieveIq packet;
    packet.setMax(max);
    packet.setStart(start);
    packet.setWith(jid);
    m_stream->sendPacket(packet);
}

#if 0
void QXmppArchiveManager::getPreferences()
{
    QXmppArchivePrefIq packet;
    m_stream->sendPacket(packet);
}
#endif
<|endoftext|>


<commit_before>// Apache Thrift Frame Layer Network Transport Server in C++

#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <string>
#include <iostream>
#include <memory>

using namespace apache::thrift::transport;
using boost::shared_ptr;
using boost::make_shared;

int main()
{
    const std::string msg("Hello Thrift!\n");
    const std::string stop_cmd("STOP");
    const int buf_size = 1024*8;
    char buf[buf_size] = "";
    auto port = 9090;

    auto acceptor = std::make_shared<TServerSocket>(port);
    acceptor->listen();
    std::cout << "[Server] listening on port " << port << std::endl;

    do {
        auto trans_ep = acceptor->accept();
        auto trans = make_shared<TFramedTransport>(trans_ep);
        auto len = trans->read(reinterpret_cast<uint8_t *>(buf), buf_size);
        buf[(0 < len && len < buf_size) ? len : 0] = '\0';
        std::cout << "[Server] handling request: " << buf << std::endl;
        trans->write(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.length());
        trans->flush();
        trans->close();
    } while (0 == stop_cmd.compare(0, std::string::npos, buf, 4));

    std::cout << "[Server] exiting" << std::endl;
    acceptor->close();
}

<commit_msg>fixed bool logic<commit_after>// Apache Thrift Frame Layer Network Transport Server in C++

#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <string>
#include <iostream>
#include <memory>

using namespace apache::thrift::transport;
using boost::shared_ptr;
using boost::make_shared;

int main()
{
    const std::string msg("Hello Thrift!\n");
    const std::string stop_cmd("STOP");
    const int buf_size = 1024*8;
    char buf[buf_size] = "";
    auto port = 9090;

    auto acceptor = std::make_shared<TServerSocket>(port);
    acceptor->listen();
    std::cout << "[Server] listening on port " << port << std::endl;

    do {
        auto trans_ep = acceptor->accept();
        auto trans = make_shared<TFramedTransport>(trans_ep);
        auto len = trans->read(reinterpret_cast<uint8_t *>(buf), buf_size);
        buf[(0 < len && len < buf_size) ? len : 0] = '\0';
        std::cout << "[Server] handling request: " << buf << std::endl;
        trans->write(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.length());
        trans->flush();
        trans->close();
    } while (0 != stop_cmd.compare(0, std::string::npos, buf, 4));

    std::cout << "[Server] exiting" << std::endl;
    acceptor->close();
}

<|endoftext|>


<commit_before>/*
 *
 * Copyright 2017 Asylo authors
 *
 * 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.
 *
 */

#include <unistd.h>

#include <sys/stat.h>
#include <cstdlib>
#include <cstring>

#include "asylo/platform/arch/include/trusted/fork.h"
#include "asylo/platform/arch/include/trusted/host_calls.h"
#include "asylo/platform/core/trusted_global_state.h"
#include "asylo/platform/posix/io/io_manager.h"
#include "asylo/util/statusor.h"

using asylo::io::IOManager;

// Simulated page size, used by the POSIX wrappers.
constexpr size_t kPageSize = 4096;

extern "C" {

int access(const char *path_name, int mode) {
  return IOManager::GetInstance().Access(path_name, mode);
}

int chown(const char *path, uid_t owner, gid_t group) {
  return IOManager::GetInstance().Chown(path, owner, group);
}

int fchown(int fd, uid_t owner, gid_t group) {
  return IOManager::GetInstance().FChOwn(fd, owner, group);
}

ssize_t readlink(const char *path_name, char *buf, size_t bufsize) {
  return IOManager::GetInstance().ReadLink(path_name, buf, bufsize);
}

int symlink(const char *path1, const char *path2) {
  return IOManager::GetInstance().SymLink(path1, path2);
}

int pipe(int pipefd[2]) { return IOManager::GetInstance().Pipe(pipefd, 0); }

int pipe2(int pipefd[2], int flags) {
  return IOManager::GetInstance().Pipe(pipefd, flags);
}

int gethostname(char *name, size_t len) {
  asylo::StatusOr<const asylo::EnclaveConfig *> config_result =
      asylo::GetEnclaveConfig();

  if (!config_result.ok()) {
    errno = EFAULT;
    return -1;
  }

  const asylo::EnclaveConfig *config = config_result.ValueOrDie();
  if (!config->has_host_name()) {
    errno = EFAULT;
    return -1;
  }
  std::string host_name = config->host_name();
  int size = host_name.size();
  // Truncate |host_name| if longer than size of the buffer.
  if (size >= len) {
    size = len - 1;
  }
  memcpy(name, host_name.c_str(), size);
  name[size] = '\0';
  return 0;
}

// Only _SC_NPROCESSORS_ONLN, _SC_NPROCESSORS_CONF, and _SC_PAGESIZE are
// supported for now. _SC_NPROCESSORS_CONF and _SC_NOPROCESSORS_ONLN retrieve
// the return value from the host because processor resources are under control
// of the host. _SC_PAGESIZE is hard-coded because a malicious value returned by
// a host could result in undesired behavior. For any other arguments, -1 is
// returned.
long sysconf(int name) {
  switch (name) {
    case _SC_NPROCESSORS_CONF:
    case _SC_NPROCESSORS_ONLN:
      return enc_untrusted_sysconf(name);
    case _SC_PAGESIZE:
      // Hard-code a reasonable guess for the page size, without having to
      // make an untrusted call.
      return kPageSize;
    default:
      errno = ENOSYS;
      return -1;
  }
}

int getpagesize() { return kPageSize; }

uint32_t sleep(uint32_t seconds) { return enc_untrusted_sleep(seconds); }

int usleep(useconds_t usec) { return enc_untrusted_usleep(usec); }

// For dup() and dup2() we do not exit enclave to call dup() or dup() on host.
// Instead, we create a new reference to the same host file descriptor in
// IOManager. Therefore the FD_CLOEXEC flag of the new file descriptor will be
// the same as the old one, as opposed to what dup() and dup2() behaves normally
// (FD_CLOEXEC may be different).
int dup(int oldfd) { return IOManager::GetInstance().Dup(oldfd); }

// See the comment for dup().
int dup2(int oldfd, int newfd) {
  return IOManager::GetInstance().Dup2(oldfd, newfd);
}

int fsync(int fd) { return IOManager::GetInstance().FSync(fd); }

int fdatasync(int fd) { return IOManager::GetInstance().FDataSync(fd); }

char *getcwd(char *buf, size_t bufsize) {
  asylo::StatusOr<const asylo::EnclaveConfig *> config_result =
      asylo::GetEnclaveConfig();

  // It is possible for global constructors to call getcwd prior to us
  // initializing the enclave.  In this case, return a dummy value.
  if (!config_result.ok()) {
    const char *dir = "./";
    memcpy(buf, dir, 3);
    return buf;
  }

  std::string current_working_directory =
      IOManager::GetInstance().GetCurrentWorkingDirectory();
  int size = current_working_directory.size();

  if (current_working_directory.empty()) {
    errno = ENOENT;
    return nullptr;
  }

  // Verify the buffer size.
  if (!buf && !bufsize) bufsize = size + 1;
  if (bufsize <= size) {
    errno = ERANGE;
    return nullptr;
  }

  // If |buf| is null, allocate one.
  if (!buf) {
    buf = reinterpret_cast<char *>(malloc(bufsize));
    if (!buf) {
      errno = ENOMEM;
      return nullptr;
    }
  }

  // Copy into provided buffer.
  current_working_directory.copy(buf, size);
  buf[size] = '\0';

  return buf;
}

int chdir(const char *path) {
  asylo::Status status =
      IOManager::GetInstance().SetCurrentWorkingDirectory(path);
  if (!status.ok()) {
    errno = status.error_code();
    return -1;
  }

  return 0;
}

int rmdir(const char *pathname) {
  return IOManager::GetInstance().RmDir(pathname);
}

uid_t getuid() { return enc_untrusted_getuid(); }

uid_t geteuid() { return enc_untrusted_geteuid(); }

gid_t getgid() { return enc_untrusted_getgid(); }

gid_t getegid() { return enc_untrusted_getegid(); }

pid_t getppid() { return enc_untrusted_getppid(); }

pid_t setsid() { return enc_untrusted_setsid(); }

// The functions below are prefixed with |enclave_|, as they are plumbed in from
// newlib.
int enclave_getpid() {
  int pid = enc_untrusted_getpid();
  if (pid == 0) {
    enc_untrusted_puts("FATAL ERROR: Host returned 0 from getpid()");
    abort();
  }
  return pid;
}

int enclave_fstat(int fd, struct stat *st) {
  return IOManager::GetInstance().FStat(fd, st);
}

int enclave_isatty(int fd) { return IOManager::GetInstance().Isatty(fd); }

int enclave_unlink(const char *pathname) {
  return IOManager::GetInstance().Unlink(pathname);
}

int truncate(const char *path, off_t length) {
  return IOManager::GetInstance().Truncate(path, length);
}

int ftruncate(int fd, off_t length) {
  return IOManager::GetInstance().FTruncate(fd, length);
}

void enclave_exit(int rc) {
  enc_untrusted__exit(rc);
}

pid_t enclave_fork() {
  asylo::StatusOr<const asylo::EnclaveConfig *> config_result =
      asylo::GetEnclaveConfig();

  if (!config_result.ok()) {
    errno = EFAULT;
    return -1;
  }

  const asylo::EnclaveConfig *config = config_result.ValueOrDie();
  if (!config->has_enable_fork()) {
    errno = EFAULT;
    return -1;
  }
  if (!config->enable_fork()) {
    errno = ENOSYS;
    return -1;
  }

  return asylo::enc_fork(asylo::GetEnclaveName().c_str(), *config);
}

}  // extern "C"
<commit_msg>Implement vfork(2)<commit_after>/*
 *
 * Copyright 2017 Asylo authors
 *
 * 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.
 *
 */

#include <unistd.h>

#include <sys/stat.h>
#include <sys/wait.h>
#include <cstdlib>
#include <cstring>

#include "asylo/platform/arch/include/trusted/fork.h"
#include "asylo/platform/arch/include/trusted/host_calls.h"
#include "asylo/platform/core/trusted_global_state.h"
#include "asylo/platform/posix/io/io_manager.h"
#include "asylo/util/statusor.h"

using asylo::io::IOManager;

// Simulated page size, used by the POSIX wrappers.
constexpr size_t kPageSize = 4096;

namespace {

pid_t ForkEnclave() {
  asylo::StatusOr<const asylo::EnclaveConfig *> config_result =
      asylo::GetEnclaveConfig();

  if (!config_result.ok()) {
    errno = EFAULT;
    return -1;
  }

  const asylo::EnclaveConfig *config = config_result.ValueOrDie();
  if (!config->has_enable_fork()) {
    errno = EFAULT;
    return -1;
  }
  if (!config->enable_fork()) {
    errno = ENOSYS;
    return -1;
  }

  return asylo::enc_fork(asylo::GetEnclaveName().c_str(), *config);
}

}  // namespace

extern "C" {

int access(const char *path_name, int mode) {
  return IOManager::GetInstance().Access(path_name, mode);
}

int chown(const char *path, uid_t owner, gid_t group) {
  return IOManager::GetInstance().Chown(path, owner, group);
}

int fchown(int fd, uid_t owner, gid_t group) {
  return IOManager::GetInstance().FChOwn(fd, owner, group);
}

ssize_t readlink(const char *path_name, char *buf, size_t bufsize) {
  return IOManager::GetInstance().ReadLink(path_name, buf, bufsize);
}

int symlink(const char *path1, const char *path2) {
  return IOManager::GetInstance().SymLink(path1, path2);
}

int pipe(int pipefd[2]) { return IOManager::GetInstance().Pipe(pipefd, 0); }

int pipe2(int pipefd[2], int flags) {
  return IOManager::GetInstance().Pipe(pipefd, flags);
}

int gethostname(char *name, size_t len) {
  asylo::StatusOr<const asylo::EnclaveConfig *> config_result =
      asylo::GetEnclaveConfig();

  if (!config_result.ok()) {
    errno = EFAULT;
    return -1;
  }

  const asylo::EnclaveConfig *config = config_result.ValueOrDie();
  if (!config->has_host_name()) {
    errno = EFAULT;
    return -1;
  }
  std::string host_name = config->host_name();
  int size = host_name.size();
  // Truncate |host_name| if longer than size of the buffer.
  if (size >= len) {
    size = len - 1;
  }
  memcpy(name, host_name.c_str(), size);
  name[size] = '\0';
  return 0;
}

// Only _SC_NPROCESSORS_ONLN, _SC_NPROCESSORS_CONF, and _SC_PAGESIZE are
// supported for now. _SC_NPROCESSORS_CONF and _SC_NOPROCESSORS_ONLN retrieve
// the return value from the host because processor resources are under control
// of the host. _SC_PAGESIZE is hard-coded because a malicious value returned by
// a host could result in undesired behavior. For any other arguments, -1 is
// returned.
long sysconf(int name) {
  switch (name) {
    case _SC_NPROCESSORS_CONF:
    case _SC_NPROCESSORS_ONLN:
      return enc_untrusted_sysconf(name);
    case _SC_PAGESIZE:
      // Hard-code a reasonable guess for the page size, without having to
      // make an untrusted call.
      return kPageSize;
    default:
      errno = ENOSYS;
      return -1;
  }
}

int getpagesize() { return kPageSize; }

uint32_t sleep(uint32_t seconds) { return enc_untrusted_sleep(seconds); }

int usleep(useconds_t usec) { return enc_untrusted_usleep(usec); }

// For dup() and dup2() we do not exit enclave to call dup() or dup() on host.
// Instead, we create a new reference to the same host file descriptor in
// IOManager. Therefore the FD_CLOEXEC flag of the new file descriptor will be
// the same as the old one, as opposed to what dup() and dup2() behaves normally
// (FD_CLOEXEC may be different).
int dup(int oldfd) { return IOManager::GetInstance().Dup(oldfd); }

// See the comment for dup().
int dup2(int oldfd, int newfd) {
  return IOManager::GetInstance().Dup2(oldfd, newfd);
}

int fsync(int fd) { return IOManager::GetInstance().FSync(fd); }

int fdatasync(int fd) { return IOManager::GetInstance().FDataSync(fd); }

char *getcwd(char *buf, size_t bufsize) {
  asylo::StatusOr<const asylo::EnclaveConfig *> config_result =
      asylo::GetEnclaveConfig();

  // It is possible for global constructors to call getcwd prior to us
  // initializing the enclave.  In this case, return a dummy value.
  if (!config_result.ok()) {
    const char *dir = "./";
    memcpy(buf, dir, 3);
    return buf;
  }

  std::string current_working_directory =
      IOManager::GetInstance().GetCurrentWorkingDirectory();
  int size = current_working_directory.size();

  if (current_working_directory.empty()) {
    errno = ENOENT;
    return nullptr;
  }

  // Verify the buffer size.
  if (!buf && !bufsize) bufsize = size + 1;
  if (bufsize <= size) {
    errno = ERANGE;
    return nullptr;
  }

  // If |buf| is null, allocate one.
  if (!buf) {
    buf = reinterpret_cast<char *>(malloc(bufsize));
    if (!buf) {
      errno = ENOMEM;
      return nullptr;
    }
  }

  // Copy into provided buffer.
  current_working_directory.copy(buf, size);
  buf[size] = '\0';

  return buf;
}

int chdir(const char *path) {
  asylo::Status status =
      IOManager::GetInstance().SetCurrentWorkingDirectory(path);
  if (!status.ok()) {
    errno = status.error_code();
    return -1;
  }

  return 0;
}

int rmdir(const char *pathname) {
  return IOManager::GetInstance().RmDir(pathname);
}

uid_t getuid() { return enc_untrusted_getuid(); }

uid_t geteuid() { return enc_untrusted_geteuid(); }

gid_t getgid() { return enc_untrusted_getgid(); }

gid_t getegid() { return enc_untrusted_getegid(); }

pid_t getppid() { return enc_untrusted_getppid(); }

pid_t setsid() { return enc_untrusted_setsid(); }

int truncate(const char *path, off_t length) {
  return IOManager::GetInstance().Truncate(path, length);
}

int ftruncate(int fd, off_t length) {
  return IOManager::GetInstance().FTruncate(fd, length);
}

pid_t vfork() {
  pid_t ret = ForkEnclave();
  if (ret < 0) {
    return ret;
  }
  // Suspend the parent and waits till the child finishes.
  if (ret != 0) {
    int status;
    if (wait(&status) == -1) {
      // Errno is set by wait() call.
      return -1;
    }
  }
  return ret;
}

// The functions below are prefixed with |enclave_|, as they are plumbed in from
// newlib.
int enclave_getpid() {
  int pid = enc_untrusted_getpid();
  if (pid == 0) {
    enc_untrusted_puts("FATAL ERROR: Host returned 0 from getpid()");
    abort();
  }
  return pid;
}

int enclave_fstat(int fd, struct stat *st) {
  return IOManager::GetInstance().FStat(fd, st);
}

int enclave_isatty(int fd) { return IOManager::GetInstance().Isatty(fd); }

int enclave_unlink(const char *pathname) {
  return IOManager::GetInstance().Unlink(pathname);
}

void enclave_exit(int rc) {
  enc_untrusted__exit(rc);
}

pid_t enclave_fork() { return ForkEnclave(); }

}  // extern "C"
<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/atom_main_delegate.h"

#include <iostream>
#include <string>

#include "atom/app/atom_content_client.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/relauncher.h"
#include "atom/common/google_api_key.h"
#include "atom/common/options_switches.h"
#include "atom/renderer/atom_renderer_client.h"
#include "atom/renderer/atom_sandboxed_renderer_client.h"
#include "atom/utility/atom_content_utility_client.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
#include "base/environment.h"
#include "base/logging.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/common/content_switches.h"
#include "ipc/ipc_features.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"

#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
#define IPC_MESSAGE_MACROS_LOG_ENABLED
#include "content/public/common/content_ipc_logging.h"
#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
  content::RegisterIPCLogger(msg_id, logger)
#include "atom/common/common_message_generator.h"
#endif

namespace atom {

namespace {

const char* kRelauncherProcess = "relauncher";

bool IsBrowserProcess(base::CommandLine* cmd) {
  std::string process_type = cmd->GetSwitchValueASCII(::switches::kProcessType);
  return process_type.empty();
}

#if defined(OS_WIN)
void InvalidParameterHandler(const wchar_t*,
                             const wchar_t*,
                             const wchar_t*,
                             unsigned int,
                             uintptr_t) {
  // noop.
}
#endif

}  // namespace

AtomMainDelegate::AtomMainDelegate() {}

AtomMainDelegate::~AtomMainDelegate() {}

bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
  auto* command_line = base::CommandLine::ForCurrentProcess();

  logging::LoggingSettings settings;
#if defined(OS_WIN)
  // On Windows the terminal returns immediately, so we add a new line to
  // prevent output in the same line as the prompt.
  if (IsBrowserProcess(command_line))
    std::wcout << std::endl;
#if defined(DEBUG)
  // Print logging to debug.log on Windows
  settings.logging_dest = logging::LOG_TO_ALL;
  settings.log_file = L"debug.log";
  settings.lock_log = logging::LOCK_LOG_FILE;
  settings.delete_old = logging::DELETE_OLD_LOG_FILE;
#else
  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif  // defined(DEBUG)
#else   // defined(OS_WIN)
  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif  // !defined(OS_WIN)

  // Only enable logging when --enable-logging is specified.
  auto env = base::Environment::Create();
  if (!command_line->HasSwitch(::switches::kEnableLogging) &&
      !env->HasVar("ELECTRON_ENABLE_LOGGING")) {
    settings.logging_dest = logging::LOG_NONE;
    logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
  }

  logging::InitLogging(settings);

  // Logging with pid and timestamp.
  logging::SetLogItems(true, false, true, false);

  // Enable convient stack printing.
#if defined(DEBUG) && defined(OS_LINUX)
  bool enable_stack_dumping = true;
#else
  bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING");
#endif
#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
  // For 32bit ARM enabling stack printing would end up crashing.
  // https://github.com/electron/electron/pull/11230#issuecomment-363232482
  enable_stack_dumping = false;
#endif
  if (enable_stack_dumping)
    base::debug::EnableInProcessStackDumping();

  chrome::RegisterPathProvider();

#if defined(OS_MACOSX)
  SetUpBundleOverrides();
#endif

#if defined(OS_WIN)
  // Ignore invalid parameter errors.
  _set_invalid_parameter_handler(InvalidParameterHandler);
  // Disable the ActiveVerifier, which is used by Chrome to track possible
  // bugs, but no use in Electron.
  base::win::DisableHandleVerifier();
#endif

  return brightray::MainDelegate::BasicStartupComplete(exit_code);
}

void AtomMainDelegate::PreSandboxStartup() {
  brightray::MainDelegate::PreSandboxStartup();

  auto* command_line = base::CommandLine::ForCurrentProcess();
  std::string process_type =
      command_line->GetSwitchValueASCII(::switches::kProcessType);

  // Only append arguments for browser process.
  if (!IsBrowserProcess(command_line))
    return;

  if (!command_line->HasSwitch(switches::kEnableMixedSandbox)) {
    if (command_line->HasSwitch(switches::kEnableSandbox)) {
      // Disable setuid sandbox since it is not longer required on
      // linux(namespace sandbox is available on most distros).
      command_line->AppendSwitch(::switches::kDisableSetuidSandbox);
    } else {
      // Disable renderer sandbox for most of node's functions.
      command_line->AppendSwitch(::switches::kNoSandbox);
    }
  }

  // Allow file:// URIs to read other file:// URIs by default.
  command_line->AppendSwitch(::switches::kAllowFileAccessFromFiles);

#if defined(OS_MACOSX)
  // Enable AVFoundation.
  command_line->AppendSwitch("enable-avfoundation");
#endif
}

content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
  browser_client_.reset(new AtomBrowserClient);
  return browser_client_.get();
}

content::ContentRendererClient*
AtomMainDelegate::CreateContentRendererClient() {
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableSandbox) ||
      !base::CommandLine::ForCurrentProcess()->HasSwitch(
          ::switches::kNoSandbox)) {
    renderer_client_.reset(new AtomSandboxedRendererClient);
  } else {
    renderer_client_.reset(new AtomRendererClient);
  }

  return renderer_client_.get();
}

content::ContentUtilityClient* AtomMainDelegate::CreateContentUtilityClient() {
  utility_client_.reset(new AtomContentUtilityClient);
  return utility_client_.get();
}

int AtomMainDelegate::RunProcess(
    const std::string& process_type,
    const content::MainFunctionParams& main_function_params) {
  if (process_type == kRelauncherProcess)
    return relauncher::RelauncherMain(main_function_params);
  else
    return -1;
}

#if defined(OS_MACOSX)
bool AtomMainDelegate::ShouldSendMachPort(const std::string& process_type) {
  return process_type != kRelauncherProcess;
}

bool AtomMainDelegate::DelaySandboxInitialization(
    const std::string& process_type) {
  return process_type == kRelauncherProcess;
}
#endif

std::unique_ptr<brightray::ContentClient>
AtomMainDelegate::CreateContentClient() {
  return std::make_unique<AtomContentClient>();
}

}  // namespace atom
<commit_msg>Remove content/linux_sandbox dependence on content_switches.h<commit_after>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/atom_main_delegate.h"

#include <iostream>
#include <string>

#include "atom/app/atom_content_client.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/relauncher.h"
#include "atom/common/google_api_key.h"
#include "atom/common/options_switches.h"
#include "atom/renderer/atom_renderer_client.h"
#include "atom/renderer/atom_sandboxed_renderer_client.h"
#include "atom/utility/atom_content_utility_client.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
#include "base/environment.h"
#include "base/logging.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/common/content_switches.h"
#include "ipc/ipc_features.h"
#include "services/service_manager/sandbox/switches.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"

#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
#define IPC_MESSAGE_MACROS_LOG_ENABLED
#include "content/public/common/content_ipc_logging.h"
#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
  content::RegisterIPCLogger(msg_id, logger)
#include "atom/common/common_message_generator.h"
#endif

namespace atom {

namespace {

const char* kRelauncherProcess = "relauncher";

bool IsBrowserProcess(base::CommandLine* cmd) {
  std::string process_type = cmd->GetSwitchValueASCII(::switches::kProcessType);
  return process_type.empty();
}

#if defined(OS_WIN)
void InvalidParameterHandler(const wchar_t*,
                             const wchar_t*,
                             const wchar_t*,
                             unsigned int,
                             uintptr_t) {
  // noop.
}
#endif

}  // namespace

AtomMainDelegate::AtomMainDelegate() {}

AtomMainDelegate::~AtomMainDelegate() {}

bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
  auto* command_line = base::CommandLine::ForCurrentProcess();

  logging::LoggingSettings settings;
#if defined(OS_WIN)
  // On Windows the terminal returns immediately, so we add a new line to
  // prevent output in the same line as the prompt.
  if (IsBrowserProcess(command_line))
    std::wcout << std::endl;
#if defined(DEBUG)
  // Print logging to debug.log on Windows
  settings.logging_dest = logging::LOG_TO_ALL;
  settings.log_file = L"debug.log";
  settings.lock_log = logging::LOCK_LOG_FILE;
  settings.delete_old = logging::DELETE_OLD_LOG_FILE;
#else
  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif  // defined(DEBUG)
#else   // defined(OS_WIN)
  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif  // !defined(OS_WIN)

  // Only enable logging when --enable-logging is specified.
  auto env = base::Environment::Create();
  if (!command_line->HasSwitch(::switches::kEnableLogging) &&
      !env->HasVar("ELECTRON_ENABLE_LOGGING")) {
    settings.logging_dest = logging::LOG_NONE;
    logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
  }

  logging::InitLogging(settings);

  // Logging with pid and timestamp.
  logging::SetLogItems(true, false, true, false);

  // Enable convient stack printing.
#if defined(DEBUG) && defined(OS_LINUX)
  bool enable_stack_dumping = true;
#else
  bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING");
#endif
#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
  // For 32bit ARM enabling stack printing would end up crashing.
  // https://github.com/electron/electron/pull/11230#issuecomment-363232482
  enable_stack_dumping = false;
#endif
  if (enable_stack_dumping)
    base::debug::EnableInProcessStackDumping();

  chrome::RegisterPathProvider();

#if defined(OS_MACOSX)
  SetUpBundleOverrides();
#endif

#if defined(OS_WIN)
  // Ignore invalid parameter errors.
  _set_invalid_parameter_handler(InvalidParameterHandler);
  // Disable the ActiveVerifier, which is used by Chrome to track possible
  // bugs, but no use in Electron.
  base::win::DisableHandleVerifier();
#endif

  return brightray::MainDelegate::BasicStartupComplete(exit_code);
}

void AtomMainDelegate::PreSandboxStartup() {
  brightray::MainDelegate::PreSandboxStartup();

  auto* command_line = base::CommandLine::ForCurrentProcess();
  std::string process_type =
      command_line->GetSwitchValueASCII(::switches::kProcessType);

  // Only append arguments for browser process.
  if (!IsBrowserProcess(command_line))
    return;

  if (!command_line->HasSwitch(switches::kEnableMixedSandbox)) {
    if (command_line->HasSwitch(switches::kEnableSandbox)) {
      // Disable setuid sandbox since it is not longer required on
      // linux(namespace sandbox is available on most distros).
      command_line->AppendSwitch(
          service_manager::switches::kDisableSetuidSandbox);
    } else {
      // Disable renderer sandbox for most of node's functions.
      command_line->AppendSwitch(::switches::kNoSandbox);
    }
  }

  // Allow file:// URIs to read other file:// URIs by default.
  command_line->AppendSwitch(::switches::kAllowFileAccessFromFiles);

#if defined(OS_MACOSX)
  // Enable AVFoundation.
  command_line->AppendSwitch("enable-avfoundation");
#endif
}

content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
  browser_client_.reset(new AtomBrowserClient);
  return browser_client_.get();
}

content::ContentRendererClient*
AtomMainDelegate::CreateContentRendererClient() {
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableSandbox) ||
      !base::CommandLine::ForCurrentProcess()->HasSwitch(
          ::switches::kNoSandbox)) {
    renderer_client_.reset(new AtomSandboxedRendererClient);
  } else {
    renderer_client_.reset(new AtomRendererClient);
  }

  return renderer_client_.get();
}

content::ContentUtilityClient* AtomMainDelegate::CreateContentUtilityClient() {
  utility_client_.reset(new AtomContentUtilityClient);
  return utility_client_.get();
}

int AtomMainDelegate::RunProcess(
    const std::string& process_type,
    const content::MainFunctionParams& main_function_params) {
  if (process_type == kRelauncherProcess)
    return relauncher::RelauncherMain(main_function_params);
  else
    return -1;
}

#if defined(OS_MACOSX)
bool AtomMainDelegate::ShouldSendMachPort(const std::string& process_type) {
  return process_type != kRelauncherProcess;
}

bool AtomMainDelegate::DelaySandboxInitialization(
    const std::string& process_type) {
  return process_type == kRelauncherProcess;
}
#endif

std::unique_ptr<brightray::ContentClient>
AtomMainDelegate::CreateContentClient() {
  return std::make_unique<AtomContentClient>();
}

}  // namespace atom
<|endoftext|>


<commit_before>/*
 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <vector>

#include "webrtc/base/sslstreamadapterhelper.h"

#include "webrtc/base/common.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/stream.h"

namespace rtc {

SSLStreamAdapterHelper::SSLStreamAdapterHelper(StreamInterface* stream)
    : SSLStreamAdapter(stream),
      state_(SSL_NONE),
      role_(SSL_CLIENT),
      ssl_error_code_(0),  // Not meaningful yet
      ssl_mode_(SSL_MODE_TLS),
      ssl_max_version_(SSL_PROTOCOL_TLS_12) {}

SSLStreamAdapterHelper::~SSLStreamAdapterHelper() = default;

void SSLStreamAdapterHelper::SetIdentity(SSLIdentity* identity) {
  ASSERT(identity_.get() == NULL);
  identity_.reset(identity);
}

void SSLStreamAdapterHelper::SetServerRole(SSLRole role) {
  role_ = role;
}

int SSLStreamAdapterHelper::StartSSLWithServer(const char* server_name) {
  ASSERT(server_name != NULL && server_name[0] != '\0');
  ssl_server_name_ = server_name;
  return StartSSL();
}

int SSLStreamAdapterHelper::StartSSLWithPeer() {
  ASSERT(ssl_server_name_.empty());
  // It is permitted to specify peer_certificate_ only later.
  return StartSSL();
}

void SSLStreamAdapterHelper::SetMode(SSLMode mode) {
  ASSERT(state_ == SSL_NONE);
  ssl_mode_ = mode;
}

void SSLStreamAdapterHelper::SetMaxProtocolVersion(SSLProtocolVersion version) {
  ssl_max_version_ = version;
}

StreamState SSLStreamAdapterHelper::GetState() const {
  switch (state_) {
    case SSL_WAIT:
    case SSL_CONNECTING:
      return SS_OPENING;
    case SSL_CONNECTED:
      return SS_OPEN;
    default:
      return SS_CLOSED;
  };
  // not reached
}

bool SSLStreamAdapterHelper::GetPeerCertificate(SSLCertificate** cert) const {
  if (!peer_certificate_)
    return false;

  *cert = peer_certificate_->GetReference();
  return true;
}

bool SSLStreamAdapterHelper::SetPeerCertificateDigest(
    const std::string &digest_alg,
    const unsigned char* digest_val,
    size_t digest_len) {
  ASSERT(peer_certificate_.get() == NULL);
  ASSERT(peer_certificate_digest_algorithm_.empty());
  ASSERT(ssl_server_name_.empty());
  size_t expected_len;

  if (!GetDigestLength(digest_alg, &expected_len)) {
    LOG(LS_WARNING) << "Unknown digest algorithm: " << digest_alg;
    return false;
  }
  if (expected_len != digest_len)
    return false;

  peer_certificate_digest_value_.SetData(digest_val, digest_len);
  peer_certificate_digest_algorithm_ = digest_alg;

  return true;
}

void SSLStreamAdapterHelper::Error(const char* context, int err, bool signal) {
  LOG(LS_WARNING) << "SSLStreamAdapterHelper::Error("
                  << context << ", " << err << "," << signal << ")";
  state_ = SSL_ERROR;
  ssl_error_code_ = err;
  Cleanup();
  if (signal)
    StreamAdapterInterface::OnEvent(stream(), SE_CLOSE, err);
}

void SSLStreamAdapterHelper::Close() {
  Cleanup();
  ASSERT(state_ == SSL_CLOSED || state_ == SSL_ERROR);
  StreamAdapterInterface::Close();
}

int SSLStreamAdapterHelper::StartSSL() {
  ASSERT(state_ == SSL_NONE);

  if (StreamAdapterInterface::GetState() != SS_OPEN) {
    state_ = SSL_WAIT;
    return 0;
  }

  state_ = SSL_CONNECTING;
  int err = BeginSSL();
  if (err) {
    Error("BeginSSL", err, false);
    return err;
  }

  return 0;
}

}  // namespace rtc

<commit_msg>Remove accidentally readded webrtc/base/sslstreamadapterhelper.cc<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * 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.
 */

#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <time.h>

#define SIMPLE_AWAY_DEFAULT_REASON "Auto away at %s"
#define SIMPLE_AWAY_DEFAULT_TIME   60

class CSimpleAway;

class CSimpleAwayJob : public CTimer {
public:
	CSimpleAwayJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription)
		: CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {}

	virtual ~CSimpleAwayJob() {}

protected:
	void RunJob() override;
};

class CSimpleAway : public CModule {
private:
	CString      m_sReason;
	unsigned int m_iAwayWait;
	unsigned int m_iMinClients;
	bool         m_bClientSetAway;
	bool         m_bWeSetAway;

public:
	MODCONSTRUCTOR(CSimpleAway) {
		m_sReason        = SIMPLE_AWAY_DEFAULT_REASON;
		m_iAwayWait      = SIMPLE_AWAY_DEFAULT_TIME;
		m_iMinClients    = 1;
		m_bClientSetAway = false;
		m_bWeSetAway     = false;

		AddHelpCommand();
		AddCommand("Reason", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnReasonCommand), "[<text>]", "Prints or sets the away reason (%s is replaced with the time you were set away)");
		AddCommand("Timer", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnTimerCommand), "", "Prints the current time to wait before setting you away");
		AddCommand("SetTimer", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnSetTimerCommand), "<seconds>", "Sets the time to wait before setting you away");
		AddCommand("DisableTimer", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnDisableTimerCommand), "", "Disables the wait time before setting you away");
		AddCommand("MinClients", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnMinClientsCommand), "", "Get or set the minimum number of clients before going away");
	}

	virtual ~CSimpleAway() {}

	bool OnLoad(const CString& sArgs, CString& sMessage) override {
		CString sReasonArg;

		// Load AwayWait
		CString sFirstArg = sArgs.Token(0);
		if (sFirstArg.Equals("-notimer")) {
			SetAwayWait(0);
			sReasonArg = sArgs.Token(1, true);
		} else if (sFirstArg.Equals("-timer")) {
			SetAwayWait(sArgs.Token(1).ToUInt());
			sReasonArg = sArgs.Token(2, true);
		} else {
			CString sAwayWait = GetNV("awaywait");
			if (!sAwayWait.empty())
				SetAwayWait(sAwayWait.ToUInt(), false);
			sReasonArg = sArgs;
		}

		// Load Reason
		if (!sReasonArg.empty()) {
			SetReason(sReasonArg);
		} else {
			CString sSavedReason = GetNV("reason");
			if (!sSavedReason.empty())
				SetReason(sSavedReason, false);
		}

		// MinClients
		CString sMinClients = GetNV("minclients");
		if (!sMinClients.empty())
			SetMinClients(sMinClients.ToUInt(), false);

		// Set away on load, required if loaded via webadmin
		if (GetNetwork()->IsIRCConnected() && MinClientsConnected())
			SetAway(false);

		return true;
	}

	void OnIRCConnected() override {
		if (MinClientsConnected())
			SetBack();
		else
			SetAway(false);
	}

	void OnClientLogin() override {
		if (MinClientsConnected())
			SetBack();
	}

	void OnClientDisconnect() override {
		/* There might still be other clients */
		if (!MinClientsConnected())
			SetAway();
	}

	void OnReasonCommand(const CString& sLine) {
		CString sReason = sLine.Token(1, true);

		if (!sReason.empty()) {
			SetReason(sReason);
			PutModule("Away reason set");
		} else {
			PutModule("Away reason: " + m_sReason);
			PutModule("Current away reason would be: " + ExpandReason());
		}
	}

	void OnTimerCommand(const CString& sLine) {
		PutModule("Current timer setting: "
				+ CString(m_iAwayWait) + " seconds");
	}

	void OnSetTimerCommand(const CString& sLine) {
		SetAwayWait(sLine.Token(1).ToUInt());

		if (m_iAwayWait == 0)
			PutModule("Timer disabled");
		else
			PutModule("Timer set to "
					+ CString(m_iAwayWait) + " seconds");
	}

	void OnDisableTimerCommand(const CString& sLine) {
		SetAwayWait(0);
		PutModule("Timer disabled");
	}

	void OnMinClientsCommand(const CString& sLine) {
		if (sLine.Token(1).empty()) {
			PutModule(CString(m_iMinClients));
		} else {
			SetMinClients(sLine.Token(1).ToUInt());
			PutModule("MinClients set");
		}
	}

	EModRet OnUserRaw(CString &sLine) override {
		if (!sLine.Token(0).Equals("AWAY"))
			return CONTINUE;

		// If a client set us away, we don't touch that away message
		const CString sArg = sLine.Token(1, true).Trim_n(" ");
		if (sArg.empty() || sArg == ":")
			m_bClientSetAway = false;
		else
			m_bClientSetAway = true;

		m_bWeSetAway = false;

		return CONTINUE;
	}

	void SetAway(bool bTimer = true) {
		if (bTimer) {
			RemTimer("simple_away");
			AddTimer(new CSimpleAwayJob(this, m_iAwayWait, 1,
				"simple_away", "Sets you away after detach"));
		} else {
			if (!m_bClientSetAway) {
				PutIRC("AWAY :" + ExpandReason());
				m_bWeSetAway = true;
			}
		}
	}

	void SetBack() {
		RemTimer("simple_away");
		if (m_bWeSetAway) {
			PutIRC("AWAY");
			m_bWeSetAway = false;
		}
	}

private:
	bool MinClientsConnected()
	{
		return GetNetwork()->GetClients().size() >= m_iMinClients;
	}

	CString ExpandReason() {
		CString sReason = m_sReason;
		if (sReason.empty())
			sReason = SIMPLE_AWAY_DEFAULT_REASON;

		time_t iTime = time(nullptr);
		CString sTime = CUtils::CTime(iTime, GetUser()->GetTimezone());
		sReason.Replace("%s", sTime);

		return sReason;
	}

/* Settings */
	void SetReason(CString& sReason, bool bSave = true) {
		if (bSave)
			SetNV("reason", sReason);
		m_sReason = sReason;
	}

	void SetAwayWait(unsigned int iAwayWait, bool bSave = true) {
		if (bSave)
			SetNV("awaywait", CString(iAwayWait));
		m_iAwayWait = iAwayWait;
	}

	void SetMinClients(unsigned int iMinClients, bool bSave = true) {
		if (bSave)
			SetNV("minclients", CString(iMinClients));
		m_iMinClients = iMinClients;
	}
};

void CSimpleAwayJob::RunJob() {
	((CSimpleAway*)GetModule())->SetAway(false);
}

template<> void TModInfo<CSimpleAway>(CModInfo& Info) {
	Info.SetWikiPage("simple_away");
	Info.SetHasArgs(true);
	Info.SetArgsHelpText("You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 awaymessage.");
}

NETWORKMODULEDEFS(CSimpleAway, "This module will automatically set you away on IRC while you are disconnected from the bouncer.")
<commit_msg>Add more verbose output when setting/getting MinClients<commit_after>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * 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.
 */

#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <time.h>

#define SIMPLE_AWAY_DEFAULT_REASON "Auto away at %s"
#define SIMPLE_AWAY_DEFAULT_TIME   60

class CSimpleAway;

class CSimpleAwayJob : public CTimer {
public:
	CSimpleAwayJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription)
		: CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {}

	virtual ~CSimpleAwayJob() {}

protected:
	void RunJob() override;
};

class CSimpleAway : public CModule {
private:
	CString      m_sReason;
	unsigned int m_iAwayWait;
	unsigned int m_iMinClients;
	bool         m_bClientSetAway;
	bool         m_bWeSetAway;

public:
	MODCONSTRUCTOR(CSimpleAway) {
		m_sReason        = SIMPLE_AWAY_DEFAULT_REASON;
		m_iAwayWait      = SIMPLE_AWAY_DEFAULT_TIME;
		m_iMinClients    = 1;
		m_bClientSetAway = false;
		m_bWeSetAway     = false;

		AddHelpCommand();
		AddCommand("Reason", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnReasonCommand), "[<text>]", "Prints or sets the away reason (%s is replaced with the time you were set away)");
		AddCommand("Timer", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnTimerCommand), "", "Prints the current time to wait before setting you away");
		AddCommand("SetTimer", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnSetTimerCommand), "<seconds>", "Sets the time to wait before setting you away");
		AddCommand("DisableTimer", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnDisableTimerCommand), "", "Disables the wait time before setting you away");
		AddCommand("MinClients", static_cast<CModCommand::ModCmdFunc>(&CSimpleAway::OnMinClientsCommand), "", "Get or set the minimum number of clients before going away");
	}

	virtual ~CSimpleAway() {}

	bool OnLoad(const CString& sArgs, CString& sMessage) override {
		CString sReasonArg;

		// Load AwayWait
		CString sFirstArg = sArgs.Token(0);
		if (sFirstArg.Equals("-notimer")) {
			SetAwayWait(0);
			sReasonArg = sArgs.Token(1, true);
		} else if (sFirstArg.Equals("-timer")) {
			SetAwayWait(sArgs.Token(1).ToUInt());
			sReasonArg = sArgs.Token(2, true);
		} else {
			CString sAwayWait = GetNV("awaywait");
			if (!sAwayWait.empty())
				SetAwayWait(sAwayWait.ToUInt(), false);
			sReasonArg = sArgs;
		}

		// Load Reason
		if (!sReasonArg.empty()) {
			SetReason(sReasonArg);
		} else {
			CString sSavedReason = GetNV("reason");
			if (!sSavedReason.empty())
				SetReason(sSavedReason, false);
		}

		// MinClients
		CString sMinClients = GetNV("minclients");
		if (!sMinClients.empty())
			SetMinClients(sMinClients.ToUInt(), false);

		// Set away on load, required if loaded via webadmin
		if (GetNetwork()->IsIRCConnected() && MinClientsConnected())
			SetAway(false);

		return true;
	}

	void OnIRCConnected() override {
		if (MinClientsConnected())
			SetBack();
		else
			SetAway(false);
	}

	void OnClientLogin() override {
		if (MinClientsConnected())
			SetBack();
	}

	void OnClientDisconnect() override {
		/* There might still be other clients */
		if (!MinClientsConnected())
			SetAway();
	}

	void OnReasonCommand(const CString& sLine) {
		CString sReason = sLine.Token(1, true);

		if (!sReason.empty()) {
			SetReason(sReason);
			PutModule("Away reason set");
		} else {
			PutModule("Away reason: " + m_sReason);
			PutModule("Current away reason would be: " + ExpandReason());
		}
	}

	void OnTimerCommand(const CString& sLine) {
		PutModule("Current timer setting: "
				+ CString(m_iAwayWait) + " seconds");
	}

	void OnSetTimerCommand(const CString& sLine) {
		SetAwayWait(sLine.Token(1).ToUInt());

		if (m_iAwayWait == 0)
			PutModule("Timer disabled");
		else
			PutModule("Timer set to "
					+ CString(m_iAwayWait) + " seconds");
	}

	void OnDisableTimerCommand(const CString& sLine) {
		SetAwayWait(0);
		PutModule("Timer disabled");
	}

	void OnMinClientsCommand(const CString& sLine) {
		if (sLine.Token(1).empty()) {
			PutModule("Current MinClients setting: " + CString(m_iMinClients));
		} else {
			SetMinClients(sLine.Token(1).ToUInt());
			PutModule("MinClients set to " + CString(m_iMinClients));
		}
	}

	EModRet OnUserRaw(CString &sLine) override {
		if (!sLine.Token(0).Equals("AWAY"))
			return CONTINUE;

		// If a client set us away, we don't touch that away message
		const CString sArg = sLine.Token(1, true).Trim_n(" ");
		if (sArg.empty() || sArg == ":")
			m_bClientSetAway = false;
		else
			m_bClientSetAway = true;

		m_bWeSetAway = false;

		return CONTINUE;
	}

	void SetAway(bool bTimer = true) {
		if (bTimer) {
			RemTimer("simple_away");
			AddTimer(new CSimpleAwayJob(this, m_iAwayWait, 1,
				"simple_away", "Sets you away after detach"));
		} else {
			if (!m_bClientSetAway) {
				PutIRC("AWAY :" + ExpandReason());
				m_bWeSetAway = true;
			}
		}
	}

	void SetBack() {
		RemTimer("simple_away");
		if (m_bWeSetAway) {
			PutIRC("AWAY");
			m_bWeSetAway = false;
		}
	}

private:
	bool MinClientsConnected()
	{
		return GetNetwork()->GetClients().size() >= m_iMinClients;
	}

	CString ExpandReason() {
		CString sReason = m_sReason;
		if (sReason.empty())
			sReason = SIMPLE_AWAY_DEFAULT_REASON;

		time_t iTime = time(nullptr);
		CString sTime = CUtils::CTime(iTime, GetUser()->GetTimezone());
		sReason.Replace("%s", sTime);

		return sReason;
	}

/* Settings */
	void SetReason(CString& sReason, bool bSave = true) {
		if (bSave)
			SetNV("reason", sReason);
		m_sReason = sReason;
	}

	void SetAwayWait(unsigned int iAwayWait, bool bSave = true) {
		if (bSave)
			SetNV("awaywait", CString(iAwayWait));
		m_iAwayWait = iAwayWait;
	}

	void SetMinClients(unsigned int iMinClients, bool bSave = true) {
		if (bSave)
			SetNV("minclients", CString(iMinClients));
		m_iMinClients = iMinClients;
	}
};

void CSimpleAwayJob::RunJob() {
	((CSimpleAway*)GetModule())->SetAway(false);
}

template<> void TModInfo<CSimpleAway>(CModInfo& Info) {
	Info.SetWikiPage("simple_away");
	Info.SetHasArgs(true);
	Info.SetArgsHelpText("You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 awaymessage.");
}

NETWORKMODULEDEFS(CSimpleAway, "This module will automatically set you away on IRC while you are disconnected from the bouncer.")
<|endoftext|>


<commit_before>/** \brief Utility for finding potentially doubly-mapped PPN's.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2019 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include "FileUtil.h"
#include "MapUtil.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

namespace {

void ProcessRecords(MARC::Reader * const marc_reader, std::unordered_map<std::string, std::string> * const old_bsz_to_new_k10plus_ppns_map,
                    std::unordered_set<std::string> * const new_k10plus_ppns)
{
    unsigned identity_count(0), old_to_new_count(0);
    while (const MARC::Record record = marc_reader->read()) {
        for (const auto &field : record.getTagRange("035")) {
            new_k10plus_ppns->emplace(record.getControlNumber());
            const auto subfield_a(field.getFirstSubfieldWithCode('a'));
            if (StringUtil::StartsWith(subfield_a, "(DE-576)")) {
                const std::string old_bsz_ppn(subfield_a.substr(__builtin_strlen( "(DE-576)")));
                if (unlikely(old_bsz_ppn == record.getControlNumber()))
                    ++identity_count;
                else {
                    (*old_bsz_to_new_k10plus_ppns_map)[old_bsz_ppn] = record.getControlNumber();
                    ++old_to_new_count;
                }
                continue;
            }
        }
    }

    LOG_INFO("Found " + std::to_string(identity_count) + " identity mappings.");
    LOG_INFO("Found " + std::to_string(old_to_new_count) + " mappings of old BSZ PPN's to new K10+ PPN's.");
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc != 4)
        ::Usage("title_records authority_records found_candidates_map");

    std::unordered_map<std::string, std::string> old_bsz_to_new_k10plus_ppns_map;
    std::unordered_set<std::string> new_k10plus_ppns;

    auto marc_reader(MARC::Reader::Factory(argv[1]));
    ProcessRecords(marc_reader.get(), &old_bsz_to_new_k10plus_ppns_map, &new_k10plus_ppns);

    auto marc_reader2(MARC::Reader::Factory(argv[2]));
    ProcessRecords(marc_reader2.get(), &old_bsz_to_new_k10plus_ppns_map, &new_k10plus_ppns);

    std::unordered_map<std::string, std::string> k10plus_to_k10plus_map;
    for (const auto &bsz_and_k10plus_ppns : old_bsz_to_new_k10plus_ppns_map) {
        // Is the replaced PPN an old BSZ PPN?
        if (old_bsz_to_new_k10plus_ppns_map.find(bsz_and_k10plus_ppns.second) != old_bsz_to_new_k10plus_ppns_map.cend()) {
            unsigned replacement_count(1);
            std::string final_k10plus_ppn(bsz_and_k10plus_ppns.second);
            for (;;) {
                auto bsz_and_k10plus_ppn2(old_bsz_to_new_k10plus_ppns_map.find(final_k10plus_ppn));
                if (bsz_and_k10plus_ppn2 == old_bsz_to_new_k10plus_ppns_map.cend())
                    break;
                final_k10plus_ppn = bsz_and_k10plus_ppn2->second;
                ++replacement_count;
            }
            if (replacement_count > 1)
                k10plus_to_k10plus_map[final_k10plus_ppn] = bsz_and_k10plus_ppns.second;
        }
    }
    LOG_INFO("Found " + std::to_string(k10plus_to_k10plus_map.size()) + " doubly mapped candidates.");

    MapUtil::SerialiseMap(argv[3], k10plus_to_k10plus_map);

    return EXIT_SUCCESS;
}
<commit_msg>Another attempt at global truth.<commit_after>/** \brief Utility for finding potentially doubly-mapped PPN's.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2019 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include "FileUtil.h"
#include "MapUtil.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

namespace {

void ProcessRecords(MARC::Reader * const marc_reader, std::unordered_map<std::string, std::string> * const old_bsz_to_new_k10plus_ppns_map,
                    std::unordered_set<std::string> * const new_k10plus_ppns)
{
    unsigned identity_count(0), old_to_new_count(0);
    while (const MARC::Record record = marc_reader->read()) {
        for (const auto &field : record.getTagRange("035")) {
            new_k10plus_ppns->emplace(record.getControlNumber());
            const auto subfield_a(field.getFirstSubfieldWithCode('a'));
            if (StringUtil::StartsWith(subfield_a, "(DE-576)")) {
                const std::string old_bsz_ppn(subfield_a.substr(__builtin_strlen( "(DE-576)")));
                if (unlikely(old_bsz_ppn == record.getControlNumber()))
                    ++identity_count;
                else {
                    (*old_bsz_to_new_k10plus_ppns_map)[old_bsz_ppn] = record.getControlNumber();
                    ++old_to_new_count;
                }
                continue;
            }
        }
    }

    LOG_INFO("Found " + std::to_string(identity_count) + " identity mappings.");
    LOG_INFO("Found " + std::to_string(old_to_new_count) + " mappings of old BSZ PPN's to new K10+ PPN's.");
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc != 4)
        ::Usage("title_records authority_records\nGenerates two output files: title_backpatch.map and authority_backpatch.map");

    std::unordered_map<std::string, std::string> old_bsz_to_new_k10plus_ppns_map;
    std::unordered_set<std::string> new_k10plus_ppns;

    auto marc_reader(MARC::Reader::Factory(argv[1]));
    ProcessRecords(marc_reader.get(), &old_bsz_to_new_k10plus_ppns_map, &new_k10plus_ppns);

    auto marc_reader2(MARC::Reader::Factory(argv[2]));
    ProcessRecords(marc_reader2.get(), &old_bsz_to_new_k10plus_ppns_map, &new_k10plus_ppns);

    std::unordered_map<std::string, std::string> k10plus_to_k10plus_map;
    for (const auto &bsz_and_k10plus_ppns : old_bsz_to_new_k10plus_ppns_map) {
        // Is the replaced PPN an old BSZ PPN?
        unsigned replacement_count(0);
        std::string final_k10plus_ppn;
        for (;;) {
            auto bsz_and_k10plus_ppn2(old_bsz_to_new_k10plus_ppns_map.find(final_k10plus_ppn));
            if (bsz_and_k10plus_ppn2 == old_bsz_to_new_k10plus_ppns_map.cend())
                break;
            final_k10plus_ppn = bsz_and_k10plus_ppn2->second;
            ++replacement_count;
        }
        if (replacement_count > 1)
            k10plus_to_k10plus_map[final_k10plus_ppn] = bsz_and_k10plus_ppns.second;
    }
    LOG_INFO("Found " + std::to_string(k10plus_to_k10plus_map.size()) + " doubly mapped candidates.");

    MapUtil::SerialiseMap(argv[3], k10plus_to_k10plus_map);

    return EXIT_SUCCESS;
}
<|endoftext|>