1 //
2 // detail/winsock_init.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP
12 #define BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 
20 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
21 
22 #include <boost/asio/detail/push_options.hpp>
23 
24 namespace boost {
25 namespace asio {
26 namespace detail {
27 
28 class winsock_init_base
29 {
30 protected:
31   // Structure to track result of initialisation and number of uses. POD is used
32   // to ensure that the values are zero-initialised prior to any code being run.
33   struct data
34   {
35     long init_count_;
36     long result_;
37   };
38 
39   BOOST_ASIO_DECL static void startup(data& d,
40       unsigned char major, unsigned char minor);
41 
42   BOOST_ASIO_DECL static void manual_startup(data& d);
43 
44   BOOST_ASIO_DECL static void cleanup(data& d);
45 
46   BOOST_ASIO_DECL static void manual_cleanup(data& d);
47 
48   BOOST_ASIO_DECL static void throw_on_error(data& d);
49 };
50 
51 template <int Major = 2, int Minor = 0>
52 class winsock_init : private winsock_init_base
53 {
54 public:
winsock_init(bool allow_throw=true)55   winsock_init(bool allow_throw = true)
56   {
57     startup(data_, Major, Minor);
58     if (allow_throw)
59       throw_on_error(data_);
60   }
61 
winsock_init(const winsock_init &)62   winsock_init(const winsock_init&)
63   {
64     startup(data_, Major, Minor);
65     throw_on_error(data_);
66   }
67 
~winsock_init()68   ~winsock_init()
69   {
70     cleanup(data_);
71   }
72 
73   // This class may be used to indicate that user code will manage Winsock
74   // initialisation and cleanup. This may be required in the case of a DLL, for
75   // example, where it is not safe to initialise Winsock from global object
76   // constructors.
77   //
78   // To prevent asio from initialising Winsock, the object must be constructed
79   // before any Asio's own global objects. With MSVC, this may be accomplished
80   // by adding the following code to the DLL:
81   //
82   //   #pragma warning(push)
83   //   #pragma warning(disable:4073)
84   //   #pragma init_seg(lib)
85   //   boost::asio::detail::winsock_init<>::manual manual_winsock_init;
86   //   #pragma warning(pop)
87   class manual
88   {
89   public:
manual()90     manual()
91     {
92       manual_startup(data_);
93     }
94 
manual(const manual &)95     manual(const manual&)
96     {
97       manual_startup(data_);
98     }
99 
~manual()100     ~manual()
101     {
102       manual_cleanup(data_);
103     }
104   };
105 
106 private:
107   friend class manual;
108   static data data_;
109 };
110 
111 template <int Major, int Minor>
112 winsock_init_base::data winsock_init<Major, Minor>::data_;
113 
114 // Static variable to ensure that winsock is initialised before main, and
115 // therefore before any other threads can get started.
116 static const winsock_init<>& winsock_init_instance = winsock_init<>(false);
117 
118 } // namespace detail
119 } // namespace asio
120 } // namespace boost
121 
122 #include <boost/asio/detail/pop_options.hpp>
123 
124 #if defined(BOOST_ASIO_HEADER_ONLY)
125 # include <boost/asio/detail/impl/winsock_init.ipp>
126 #endif // defined(BOOST_ASIO_HEADER_ONLY)
127 
128 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
129 
130 #endif // BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP
131