• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #ifndef GRPC_SRC_CORE_LIB_EVENT_ENGINE_WINDOWS_WIN_SOCKET_H
15 #define GRPC_SRC_CORE_LIB_EVENT_ENGINE_WINDOWS_WIN_SOCKET_H
16 
17 #include <grpc/support/port_platform.h>
18 
19 #ifdef GPR_WINDOWS
20 
21 #include <grpc/event_engine/event_engine.h>
22 
23 #include "absl/base/thread_annotations.h"
24 #include "absl/functional/any_invocable.h"
25 #include "src/core/lib/event_engine/thread_pool/thread_pool.h"
26 #include "src/core/util/debug_location.h"
27 #include "src/core/util/sync.h"
28 
29 namespace grpc_event_engine {
30 namespace experimental {
31 
32 class WinSocket {
33  public:
34   struct OverlappedResult {
35     int wsa_error;
36     DWORD bytes_transferred;
37     absl::Status error_status;
38   };
39 
40   // State related to a Read or Write socket operation
41   class OpState {
42    public:
43     explicit OpState(WinSocket* win_socket) noexcept;
44     // Signal a result has returned
45     // If a callback is already primed for notification, it will be executed via
46     // the WinSocket's ThreadPool. Otherwise, a "pending iocp" flag will
47     // be set.
48     void SetReady();
49     // Set WSA result for a completed op.
50     // If the error is non-zero, bytes will be overridden to 0.
51     void SetResult(int wsa_error, DWORD bytes, absl::string_view context);
52     // Set error results for a completed op.
53     // This is a manual override, meant to ignore any WSA status code.
54     void SetErrorStatus(absl::Status error_status);
55     // Retrieve the results of an overlapped operation (via Winsock API) and
56     // store them locally.
57     void GetOverlappedResult();
58     // Retrieve the results of an overlapped operation (via Winsock API) and
59     // store them locally. This overload allows acceptance of connections on new
60     // sockets.
61     void GetOverlappedResult(SOCKET sock);
62     // Retrieve the cached result from GetOverlappedResult
result()63     const OverlappedResult& result() const { return result_; }
64     // OVERLAPPED, needed for Winsock API calls
overlapped()65     LPOVERLAPPED overlapped() { return &overlapped_; }
66 
67    private:
68     friend class WinSocket;
69 
70     OVERLAPPED overlapped_;
71     WinSocket* win_socket_ = nullptr;
72     EventEngine::Closure* closure_ = nullptr;
73     OverlappedResult result_;
74   };
75 
76   WinSocket(SOCKET socket, ThreadPool* thread_pool) noexcept;
77   ~WinSocket();
78   // Provide a closure that will be called when an IOCP completion has occurred.
79   //
80   // Notification callbacks *must be registered* before any WSASend or WSARecv
81   // operations are started. Only one closure can be registered at a time for
82   // each read or send operation.
83   void NotifyOnRead(EventEngine::Closure* on_read);
84   void NotifyOnWrite(EventEngine::Closure* on_write);
85   // Remove the notification callback for read/write events.
86   //
87   // This method should only be called if no IOCP event is pending for the
88   // socket. It is UB if an IOCP event comes through and a notification is not
89   // registered.
90   void UnregisterReadCallback();
91   void UnregisterWriteCallback();
92 
93   bool IsShutdown();
94   // Shutdown socket operations, but do not delete the WinSocket.
95   // Connections will be disconnected, and the socket will be closed.
96   // If the socket is managed by a shared_ptr (most should be), then the
97   // WinSocket will be deleted when the last outstanding overlapped event comes
98   // back.
99   void Shutdown();
100   void Shutdown(const grpc_core::DebugLocation& location,
101                 absl::string_view reason);
102 
103   // Return the appropriate OpState for a given OVERLAPPED
104   // Returns nullptr if the overlapped does not match either read or write ops.
105   OpState* GetOpInfoForOverlapped(OVERLAPPED* overlapped);
106   // Getters for the operation state data.
read_info()107   OpState* read_info() { return &read_info_; }
write_info()108   OpState* write_info() { return &write_info_; }
109   // Accessor method for underlying socket
110   SOCKET raw_socket();
111 
112  private:
113   void NotifyOnReady(OpState& info, EventEngine::Closure* closure);
114 
115   SOCKET socket_;
116   std::atomic<bool> is_shutdown_{false};
117   ThreadPool* thread_pool_;
118   // These OpStates are effectively synchronized using their respective
119   // OVERLAPPED structures and the Overlapped I/O APIs. For example, OpState
120   // users should not attempt to read their bytes_transeferred until
121   // GetOverlappedResult has returned, to ensure there are no two threads
122   // reading and writing the same values concurrently.
123   //
124   // Callers must also ensure that at most one read and write operation are
125   // occurring at a time. Attempting to do multiple concurrent reads/writes will
126   // have undefined behavior.
127   OpState read_info_;
128   OpState write_info_;
129 };
130 
131 // Attempt to configure default socket settings
132 absl::Status PrepareSocket(SOCKET sock);
133 
134 // Set non block option for socket.
135 absl::Status SetSocketNonBlock(SOCKET sock);
136 
137 }  // namespace experimental
138 }  // namespace grpc_event_engine
139 
140 #endif
141 
142 #endif  // GRPC_SRC_CORE_LIB_EVENT_ENGINE_WINDOWS_WIN_SOCKET_H
143