//

// winsock_init.hpp

// ~~~~~~~~~~~~~~~~

//

// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)

//

// Distributed under the Boost Software License, Version 1.0. (See accompanying

// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//



#ifndef BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP

#define BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP



#if defined(_MSC_VER) && (_MSC_VER >= 1200)

# pragma once

#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)



#include <boost/asio/detail/push_options.hpp>



#include <boost/asio/detail/push_options.hpp>

#include <boost/config.hpp>

#include <boost/system/system_error.hpp>

#include <boost/asio/detail/pop_options.hpp>



#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)



#include <boost/asio/detail/push_options.hpp>

#include <boost/shared_ptr.hpp>

#include <boost/throw_exception.hpp>

#include <boost/asio/detail/pop_options.hpp>



#include <boost/asio/error.hpp>

#include <boost/asio/detail/noncopyable.hpp>

#include <boost/asio/detail/socket_types.hpp>



namespace boost {

namespace asio {

namespace detail {



template <int Major = 2, int Minor = 0>

class winsock_init

  : private noncopyable

{

private:

  // Structure to perform the actual initialisation.

  struct do_init

  {

    do_init()

    {

      WSADATA wsa_data;

      result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data);

    }



    ~do_init()

    {

      ::WSACleanup();

    }



    int result() const

    {

      return result_;

    }



    // Helper function to manage a do_init singleton. The static instance of the

    // winsock_init object ensures that this function is always called before

    // main, and therefore before any other threads can get started. The do_init

    // instance must be static in this function to ensure that it gets

    // initialised before any other global objects try to use it.

    static boost::shared_ptr<do_init> instance()

    {

      static boost::shared_ptr<do_init> init(new do_init);

      return init;

    }



  private:

    int result_;

  };



public:

  // Constructor.

  winsock_init()

    : ref_(do_init::instance())

  {

    // Check whether winsock was successfully initialised. This check is not

    // performed for the global instance since there will be nobody around to

    // catch the exception.

    if (this != &instance_ && ref_->result() != 0)

    {

      boost::system::system_error e(

          boost::system::error_code(ref_->result(),

            boost::asio::error::get_system_category()),

          "winsock");

      boost::throw_exception(e);

    }

  }



  // Destructor.

  ~winsock_init()

  {

  }



private:

  // Instance to force initialisation of winsock at global scope.

  static winsock_init instance_;



  // Reference to singleton do_init object to ensure that winsock does not get

  // cleaned up until the last user has finished with it.

  boost::shared_ptr<do_init> ref_;

};



template <int Major, int Minor>

winsock_init<Major, Minor> winsock_init<Major, Minor>::instance_;



} // namespace detail

} // namespace asio

} // namespace boost



#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)



#include <boost/asio/detail/pop_options.hpp>



#endif // BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP

