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