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 "src/core/lib/iomgr/error.h"
19
20 #include <grpc/status.h>
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/port_platform.h>
23 #include <grpc/support/string_util.h>
24 #include <inttypes.h>
25 #include <string.h>
26
27 #include "absl/log/check.h"
28 #include "absl/log/log.h"
29 #include "absl/strings/str_cat.h"
30 #include "absl/strings/str_format.h"
31 #include "src/core/util/crash.h"
32
33 #ifdef GPR_WINDOWS
34 #include <grpc/support/log_windows.h>
35 #endif
36
37 #include "src/core/lib/debug/trace.h"
38 #include "src/core/lib/slice/slice_internal.h"
39 #include "src/core/util/strerror.h"
40 #include "src/core/util/useful.h"
41
grpc_status_create(absl::StatusCode code,absl::string_view msg,const grpc_core::DebugLocation & location,size_t children_count,absl::Status * children)42 absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
43 const grpc_core::DebugLocation& location,
44 size_t children_count, absl::Status* children) {
45 absl::Status s = StatusCreate(code, msg, location, {});
46 for (size_t i = 0; i < children_count; ++i) {
47 if (!children[i].ok()) {
48 grpc_core::StatusAddChild(&s, children[i]);
49 }
50 }
51 return s;
52 }
53
grpc_os_error(const grpc_core::DebugLocation & location,int err,const char * call_name)54 absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
55 const char* call_name) {
56 return StatusCreate(
57 absl::StatusCode::kUnknown,
58 absl::StrCat(call_name, ": ", grpc_core::StrError(err), " (", err, ")"),
59 location, {});
60 }
61
62 #ifdef GPR_WINDOWS
WSAErrorToShortDescription(int err)63 std::string WSAErrorToShortDescription(int err) {
64 switch (err) {
65 case WSAEACCES:
66 return "Permission denied";
67 case WSAEFAULT:
68 return "Bad address";
69 case WSAEMFILE:
70 return "Too many open files";
71 case WSAEMSGSIZE:
72 return "Message too long";
73 case WSAENETDOWN:
74 return "Network is down";
75 case WSAENETUNREACH:
76 return "Network is unreachable";
77 case WSAENETRESET:
78 return "Network dropped connection on reset";
79 case WSAECONNABORTED:
80 return "Connection aborted";
81 case WSAECONNRESET:
82 return "Connection reset";
83 case WSAETIMEDOUT:
84 return "Connection timed out";
85 case WSAECONNREFUSED:
86 return "Connection refused";
87 case WSAEHOSTUNREACH:
88 return "No route to host";
89 default:
90 return "WSA Error";
91 };
92 }
93 // 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)94 absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
95 absl::string_view call_name) {
96 char* utf8_message = gpr_format_message(err);
97 absl::Status status = StatusCreate(
98 absl::StatusCode::kUnavailable,
99 absl::StrCat(call_name, ": ", WSAErrorToShortDescription(err), " (",
100 utf8_message, " -- ", err, ")"),
101 location, {});
102 StatusSetInt(&status, grpc_core::StatusIntProperty::kRpcStatus,
103 GRPC_STATUS_UNAVAILABLE);
104 gpr_free(utf8_message);
105 return status;
106 }
107 #endif
108
grpc_error_set_int(grpc_error_handle src,grpc_core::StatusIntProperty which,intptr_t value)109 grpc_error_handle grpc_error_set_int(grpc_error_handle src,
110 grpc_core::StatusIntProperty which,
111 intptr_t value) {
112 if (src.ok()) {
113 src = absl::UnknownError("");
114 StatusSetInt(&src, grpc_core::StatusIntProperty::kRpcStatus,
115 GRPC_STATUS_OK);
116 }
117 grpc_core::StatusSetInt(&src, which, value);
118 return src;
119 }
120
grpc_error_get_int(grpc_error_handle error,grpc_core::StatusIntProperty which,intptr_t * p)121 bool grpc_error_get_int(grpc_error_handle error,
122 grpc_core::StatusIntProperty which, intptr_t* p) {
123 absl::optional<intptr_t> value = grpc_core::StatusGetInt(error, which);
124 if (value.has_value()) {
125 *p = *value;
126 return true;
127 } else {
128 // TODO(veblush): Remove this once absl::Status migration is done
129 if (which == grpc_core::StatusIntProperty::kRpcStatus) {
130 switch (error.code()) {
131 case absl::StatusCode::kOk:
132 *p = GRPC_STATUS_OK;
133 return true;
134 case absl::StatusCode::kResourceExhausted:
135 *p = GRPC_STATUS_RESOURCE_EXHAUSTED;
136 return true;
137 case absl::StatusCode::kCancelled:
138 *p = GRPC_STATUS_CANCELLED;
139 return true;
140 default:
141 break;
142 }
143 }
144 return false;
145 }
146 }
147
grpc_error_set_str(grpc_error_handle src,grpc_core::StatusStrProperty which,absl::string_view str)148 grpc_error_handle grpc_error_set_str(grpc_error_handle src,
149 grpc_core::StatusStrProperty which,
150 absl::string_view str) {
151 if (src.ok()) {
152 src = absl::UnknownError("");
153 StatusSetInt(&src, grpc_core::StatusIntProperty::kRpcStatus,
154 GRPC_STATUS_OK);
155 }
156 if (which == grpc_core::StatusStrProperty::kDescription) {
157 // To change the message of absl::Status, a new instance should be created
158 // with a code and payload because it doesn't have a setter for it.
159 absl::Status s = absl::Status(src.code(), str);
160 src.ForEachPayload(
161 [&](absl::string_view type_url, const absl::Cord& payload) {
162 s.SetPayload(type_url, payload);
163 });
164 return s;
165 } else {
166 grpc_core::StatusSetStr(&src, which, str);
167 }
168 return src;
169 }
170
grpc_error_get_str(grpc_error_handle error,grpc_core::StatusStrProperty which,std::string * s)171 bool grpc_error_get_str(grpc_error_handle error,
172 grpc_core::StatusStrProperty which, std::string* s) {
173 if (which == grpc_core::StatusStrProperty::kDescription) {
174 // absl::Status uses the message field for
175 // grpc_core::StatusStrProperty::kDescription instead of using payload.
176 absl::string_view msg = error.message();
177 if (msg.empty()) {
178 return false;
179 } else {
180 *s = std::string(msg);
181 return true;
182 }
183 } else {
184 absl::optional<std::string> value = grpc_core::StatusGetStr(error, which);
185 if (value.has_value()) {
186 *s = std::move(*value);
187 return true;
188 } else {
189 // TODO(veblush): Remove this once absl::Status migration is done
190 if (which == grpc_core::StatusStrProperty::kGrpcMessage) {
191 switch (error.code()) {
192 case absl::StatusCode::kOk:
193 *s = "";
194 return true;
195 case absl::StatusCode::kCancelled:
196 *s = "CANCELLED";
197 return true;
198 default:
199 break;
200 }
201 }
202 return false;
203 }
204 }
205 }
206
grpc_error_add_child(grpc_error_handle src,grpc_error_handle child)207 grpc_error_handle grpc_error_add_child(grpc_error_handle src,
208 grpc_error_handle child) {
209 if (src.ok()) {
210 return child;
211 } else {
212 if (!child.ok()) {
213 grpc_core::StatusAddChild(&src, child);
214 }
215 return src;
216 }
217 }
218
grpc_log_error(const char * what,grpc_error_handle error,const char * file,int line)219 bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
220 int line) {
221 DCHECK(!error.ok());
222 LOG(ERROR).AtLocation(file, line)
223 << what << ": " << grpc_core::StatusToString(error);
224 return false;
225 }
226