1 //
2 //
3 // Copyright 2016 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 #include <grpc/support/port_platform.h>
19
20 #include "src/core/lib/iomgr/error.h"
21
22 #include <inttypes.h>
23 #include <string.h>
24
25 #include "absl/strings/str_format.h"
26
27 #include <grpc/status.h>
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
30 #include <grpc/support/string_util.h>
31
32 #include "src/core/lib/gprpp/crash.h"
33
34 #ifdef GPR_WINDOWS
35 #include <grpc/support/log_windows.h>
36 #endif
37
38 #include "src/core/lib/debug/trace.h"
39 #include "src/core/lib/gpr/useful.h"
40 #include "src/core/lib/gprpp/strerror.h"
41 #include "src/core/lib/slice/slice_internal.h"
42
43 grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount(false,
44 "error_refcount");
45 grpc_core::DebugOnlyTraceFlag grpc_trace_closure(false, "closure");
46
grpc_status_create(absl::StatusCode code,absl::string_view msg,const grpc_core::DebugLocation & location,size_t children_count,absl::Status * children)47 absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
48 const grpc_core::DebugLocation& location,
49 size_t children_count, absl::Status* children) {
50 absl::Status s = StatusCreate(code, msg, location, {});
51 for (size_t i = 0; i < children_count; ++i) {
52 if (!children[i].ok()) {
53 grpc_core::StatusAddChild(&s, children[i]);
54 }
55 }
56 return s;
57 }
58
grpc_os_error(const grpc_core::DebugLocation & location,int err,const char * call_name)59 absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
60 const char* call_name) {
61 auto err_string = grpc_core::StrError(err);
62 absl::Status s =
63 StatusCreate(absl::StatusCode::kUnknown, err_string, location, {});
64 grpc_core::StatusSetInt(&s, grpc_core::StatusIntProperty::kErrorNo, err);
65 grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::kOsError,
66 err_string);
67 grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::kSyscall,
68 call_name);
69 return s;
70 }
71
72 #ifdef GPR_WINDOWS
WSAErrorToShortDescription(int err)73 std::string WSAErrorToShortDescription(int err) {
74 switch (err) {
75 case WSAEACCES:
76 return "Permission denied";
77 case WSAEFAULT:
78 return "Bad address";
79 case WSAEMFILE:
80 return "Too many open files";
81 case WSAEMSGSIZE:
82 return "Message too long";
83 case WSAENETDOWN:
84 return "Network is down";
85 case WSAENETUNREACH:
86 return "Network is unreachable";
87 case WSAENETRESET:
88 return "Network dropped connection on reset";
89 case WSAECONNABORTED:
90 return "Connection aborted";
91 case WSAECONNRESET:
92 return "Connection reset";
93 case WSAETIMEDOUT:
94 return "Connection timed out";
95 case WSAECONNREFUSED:
96 return "Connection refused";
97 case WSAEHOSTUNREACH:
98 return "No route to host";
99 default:
100 return "WSA Error";
101 };
102 }
103 // TODO(veblush): lift out of iomgr for use in the WindowsEventEngine
grpc_wsa_error(const grpc_core::DebugLocation & location,int err,absl::string_view call_name)104 absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
105 absl::string_view call_name) {
106 char* utf8_message = gpr_format_message(err);
107 absl::Status s = StatusCreate(absl::StatusCode::kUnavailable,
108 WSAErrorToShortDescription(err), location, {});
109 StatusSetInt(&s, grpc_core::StatusIntProperty::kWsaError, err);
110 StatusSetInt(&s, grpc_core::StatusIntProperty::kRpcStatus,
111 GRPC_STATUS_UNAVAILABLE);
112 StatusSetStr(&s, grpc_core::StatusStrProperty::kOsError, utf8_message);
113 StatusSetStr(&s, grpc_core::StatusStrProperty::kSyscall, call_name);
114 gpr_free(utf8_message);
115 return s;
116 }
117 #endif
118
grpc_error_set_int(grpc_error_handle src,grpc_core::StatusIntProperty which,intptr_t value)119 grpc_error_handle grpc_error_set_int(grpc_error_handle src,
120 grpc_core::StatusIntProperty which,
121 intptr_t value) {
122 if (src.ok()) {
123 src = absl::UnknownError("");
124 StatusSetInt(&src, grpc_core::StatusIntProperty::kRpcStatus,
125 GRPC_STATUS_OK);
126 }
127 grpc_core::StatusSetInt(&src, which, value);
128 return src;
129 }
130
grpc_error_get_int(grpc_error_handle error,grpc_core::StatusIntProperty which,intptr_t * p)131 bool grpc_error_get_int(grpc_error_handle error,
132 grpc_core::StatusIntProperty which, intptr_t* p) {
133 absl::optional<intptr_t> value = grpc_core::StatusGetInt(error, which);
134 if (value.has_value()) {
135 *p = *value;
136 return true;
137 } else {
138 // TODO(veblush): Remove this once absl::Status migration is done
139 if (which == grpc_core::StatusIntProperty::kRpcStatus) {
140 switch (error.code()) {
141 case absl::StatusCode::kOk:
142 *p = GRPC_STATUS_OK;
143 return true;
144 case absl::StatusCode::kResourceExhausted:
145 *p = GRPC_STATUS_RESOURCE_EXHAUSTED;
146 return true;
147 case absl::StatusCode::kCancelled:
148 *p = GRPC_STATUS_CANCELLED;
149 return true;
150 default:
151 break;
152 }
153 }
154 return false;
155 }
156 }
157
grpc_error_set_str(grpc_error_handle src,grpc_core::StatusStrProperty which,absl::string_view str)158 grpc_error_handle grpc_error_set_str(grpc_error_handle src,
159 grpc_core::StatusStrProperty which,
160 absl::string_view str) {
161 if (src.ok()) {
162 src = absl::UnknownError("");
163 StatusSetInt(&src, grpc_core::StatusIntProperty::kRpcStatus,
164 GRPC_STATUS_OK);
165 }
166 if (which == grpc_core::StatusStrProperty::kDescription) {
167 // To change the message of absl::Status, a new instance should be created
168 // with a code and payload because it doesn't have a setter for it.
169 absl::Status s = absl::Status(src.code(), str);
170 src.ForEachPayload(
171 [&](absl::string_view type_url, const absl::Cord& payload) {
172 s.SetPayload(type_url, payload);
173 });
174 return s;
175 } else {
176 grpc_core::StatusSetStr(&src, which, str);
177 }
178 return src;
179 }
180
grpc_error_get_str(grpc_error_handle error,grpc_core::StatusStrProperty which,std::string * s)181 bool grpc_error_get_str(grpc_error_handle error,
182 grpc_core::StatusStrProperty which, std::string* s) {
183 if (which == grpc_core::StatusStrProperty::kDescription) {
184 // absl::Status uses the message field for
185 // grpc_core::StatusStrProperty::kDescription instead of using payload.
186 absl::string_view msg = error.message();
187 if (msg.empty()) {
188 return false;
189 } else {
190 *s = std::string(msg);
191 return true;
192 }
193 } else {
194 absl::optional<std::string> value = grpc_core::StatusGetStr(error, which);
195 if (value.has_value()) {
196 *s = std::move(*value);
197 return true;
198 } else {
199 // TODO(veblush): Remove this once absl::Status migration is done
200 if (which == grpc_core::StatusStrProperty::kGrpcMessage) {
201 switch (error.code()) {
202 case absl::StatusCode::kOk:
203 *s = "";
204 return true;
205 case absl::StatusCode::kCancelled:
206 *s = "CANCELLED";
207 return true;
208 default:
209 break;
210 }
211 }
212 return false;
213 }
214 }
215 }
216
grpc_error_add_child(grpc_error_handle src,grpc_error_handle child)217 grpc_error_handle grpc_error_add_child(grpc_error_handle src,
218 grpc_error_handle child) {
219 if (src.ok()) {
220 return child;
221 } else {
222 if (!child.ok()) {
223 grpc_core::StatusAddChild(&src, child);
224 }
225 return src;
226 }
227 }
228
grpc_log_error(const char * what,grpc_error_handle error,const char * file,int line)229 bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
230 int line) {
231 GPR_DEBUG_ASSERT(!error.ok());
232 gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what,
233 grpc_core::StatusToString(error).c_str());
234 return false;
235 }
236