proxygen
SocketFileDescriptorMap.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #if _WIN32
20 
21 #include <shared_mutex>
22 #include <unordered_map>
23 
24 #include <fcntl.h>
25 
26 // Including ntdef.h requires building as a driver, but all we want
27 // is a status code, but we need NTSTATUS defined for that. Luckily
28 // bcrypt.h also defines NTSTATUS, so we'll use that one instead.
29 #include <bcrypt.h> // @manual
30 #include <ntstatus.h> // @manual
31 
32 namespace folly {
33 namespace netops {
34 namespace detail {
35 
36 static std::unordered_map<SOCKET, int> socketMap;
37 static std::shared_mutex socketMapMutex;
38 
39 static int closeOnlyFileDescriptor(int fd) {
40  HANDLE h = (HANDLE)_get_osfhandle(fd);
41 
42  // If we were to just call _close on the descriptor, it would
43  // close the HANDLE, but it wouldn't free any of the resources
44  // associated to the SOCKET, and we can't call _close after
45  // calling closesocket, because closesocket has already closed
46  // the HANDLE, and _close would attempt to close the HANDLE
47  // again, resulting in a double free.
48  // We can however protect the HANDLE from actually being closed
49  // long enough to close the file descriptor, then close the
50  // socket itself.
51  constexpr DWORD protectFlag = HANDLE_FLAG_PROTECT_FROM_CLOSE;
52  DWORD handleFlags = 0;
53  if (!GetHandleInformation(h, &handleFlags)) {
54  return -1;
55  }
56  if (!SetHandleInformation(h, protectFlag, protectFlag)) {
57  return -1;
58  }
59  int c = 0;
60  __try {
61  // We expect this to fail. It still closes the file descriptor though.
62  c = ::_close(fd);
63  // We just have to catch the SEH exception that gets thrown when we do
64  // this with a debugger attached -_-....
65  } __except (
66  GetExceptionCode() == STATUS_HANDLE_NOT_CLOSABLE
67  ? EXCEPTION_CONTINUE_EXECUTION
68  : EXCEPTION_CONTINUE_SEARCH) {
69  // We told it to continue execution, so nothing here would
70  // be run anyways.
71  }
72  // We're at the core, we don't get the luxery of SCOPE_EXIT because
73  // of circular dependencies.
74  if (!SetHandleInformation(h, protectFlag, handleFlags)) {
75  return -1;
76  }
77  if (c != -1) {
78  return -1;
79  }
80  return 0;
81 }
82 
85  {
86  std::unique_lock<std::shared_mutex> lock{socketMapMutex};
87  if (socketMap.find(hand) != socketMap.end()) {
88  socketMap.erase(hand);
89  }
90  }
91  auto r = closeOnlyFileDescriptor(fd);
92  if (r != 0) {
93  return r;
94  }
95  return closesocket((SOCKET)hand);
96 }
97 
99  bool found = false;
100  int fd = 0;
101  {
102  std::unique_lock<std::shared_mutex> lock{socketMapMutex};
103  auto lookup = socketMap.find(sock);
104  found = lookup != socketMap.end();
105  if (found) {
106  fd = lookup->second;
107  }
108  }
109 
110  if (found) {
112  }
113 
114  return closesocket(sock);
115 }
116 
118  if (fd == -1) {
119  return INVALID_SOCKET;
120  }
121 
122  return (SOCKET)_get_osfhandle(fd);
123 }
124 
126  if (sock == INVALID_SOCKET) {
127  return -1;
128  }
129 
130  {
131  std::shared_lock<std::shared_mutex> lock{socketMapMutex};
132  auto const found = socketMap.find(sock);
133  if (found != socketMap.end()) {
134  return found->second;
135  }
136  }
137 
138  std::unique_lock<std::shared_mutex> lock{socketMapMutex};
139  auto const found = socketMap.find(sock);
140  if (found != socketMap.end()) {
141  return found->second;
142  }
143 
144  int fd = _open_osfhandle((intptr_t)sock, O_RDWR | O_BINARY);
145  socketMap.emplace(sock, fd);
146  return fd;
147 }
148 } // namespace detail
149 } // namespace netops
150 } // namespace folly
151 #endif
*than *hazptr_holder h
Definition: Hazptr.h:116
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
static const std::string lookup
char c