1/********************************************************************
2 * Copyright (c) 2013 - 2014, Pivotal Inc.
3 * All rights reserved.
4 *
5 * Author: Zhanwei Wang
6 ********************************************************************/
7/********************************************************************
8 * 2014 -
9 * open source under Apache License Version 2.0
10 ********************************************************************/
11/**
12 * Licensed to the Apache Software Foundation (ASF) under one
13 * or more contributor license agreements. See the NOTICE file
14 * distributed with this work for additional information
15 * regarding copyright ownership. The ASF licenses this file
16 * to you under the Apache License, Version 2.0 (the
17 * "License"); you may not use this file except in compliance
18 * with the License. You may obtain a copy of the License at
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28#include "platform.h"
29
30#include "Exception.h"
31#include "ExceptionInternal.h"
32#include "Thread.h"
33
34#include <cstring>
35#include <cassert>
36#include <sstream>
37
38namespace Hdfs {
39
40function<bool(void)> ChecnOperationCanceledCallback;
41
42namespace Internal {
43
44bool CheckOperationCanceled() {
45 if (ChecnOperationCanceledCallback && ChecnOperationCanceledCallback()) {
46 THROW(HdfsCanceled, "Operation has been canceled by the user.");
47 }
48
49 return false;
50}
51
52const char * GetSystemErrorInfo(int eno) {
53 static THREAD_LOCAL char message[64];
54 char buffer[64], *pbuffer;
55 pbuffer = buffer;
56#ifdef STRERROR_R_RETURN_INT
57 strerror_r(eno, buffer, sizeof(buffer));
58#else
59 pbuffer = strerror_r(eno, buffer, sizeof(buffer));
60#endif
61 snprintf(message, sizeof(message), "(errno: %d) %s", eno, pbuffer);
62 return message;
63}
64
65static void GetExceptionDetailInternal(const Hdfs::HdfsException & e,
66 std::stringstream & ss, bool topLevel);
67
68static void GetExceptionDetailInternal(const std::exception & e,
69 std::stringstream & ss, bool topLevel) {
70 try {
71 if (!topLevel) {
72 ss << "Caused by\n";
73 }
74
75 ss << e.what();
76 } catch (const std::bad_alloc & e) {
77 return;
78 }
79
80 try {
81 Hdfs::rethrow_if_nested(e);
82 } catch (const Hdfs::HdfsException & nested) {
83 GetExceptionDetailInternal(nested, ss, false);
84 } catch (const std::exception & nested) {
85 GetExceptionDetailInternal(nested, ss, false);
86 }
87}
88
89static void GetExceptionDetailInternal(const Hdfs::HdfsException & e,
90 std::stringstream & ss, bool topLevel) {
91 try {
92 if (!topLevel) {
93 ss << "Caused by\n";
94 }
95
96 ss << e.msg();
97 } catch (const std::bad_alloc & e) {
98 return;
99 }
100
101 try {
102 Hdfs::rethrow_if_nested(e);
103 } catch (const Hdfs::HdfsException & nested) {
104 GetExceptionDetailInternal(nested, ss, false);
105 } catch (const std::exception & nested) {
106 GetExceptionDetailInternal(nested, ss, false);
107 }
108}
109
110const char* GetExceptionDetail(const Hdfs::HdfsException& e,
111 std::string& buffer) {
112 try {
113 std::stringstream ss;
114 ss.imbue(std::locale::classic());
115 GetExceptionDetailInternal(e, ss, true);
116 buffer = ss.str();
117 } catch (const std::bad_alloc& e) {
118 return "Out of memory";
119 }
120
121 return buffer.c_str();
122}
123
124const char* GetExceptionDetail(const exception_ptr e, std::string& buffer) {
125 std::stringstream ss;
126 ss.imbue(std::locale::classic());
127
128 try {
129 Hdfs::rethrow_exception(e);
130 } catch (const Hdfs::HdfsException& nested) {
131 GetExceptionDetailInternal(nested, ss, true);
132 } catch (const std::exception& nested) {
133 GetExceptionDetailInternal(nested, ss, true);
134 }
135
136 try {
137 buffer = ss.str();
138 } catch (const std::bad_alloc& e) {
139 return "Out of memory";
140 }
141
142 return buffer.c_str();
143}
144
145static void GetExceptionMessage(const std::exception & e,
146 std::stringstream & ss, int recursive) {
147 try {
148 for (int i = 0; i < recursive; ++i) {
149 ss << '\t';
150 }
151
152 if (recursive > 0) {
153 ss << "Caused by: ";
154 }
155
156 ss << e.what();
157 } catch (const std::bad_alloc & e) {
158 return;
159 }
160
161 try {
162 Hdfs::rethrow_if_nested(e);
163 } catch (const std::exception & nested) {
164 GetExceptionMessage(nested, ss, recursive + 1);
165 }
166}
167
168const char * GetExceptionMessage(const exception_ptr e, std::string & buffer) {
169 std::stringstream ss;
170 ss.imbue(std::locale::classic());
171
172 try {
173 Hdfs::rethrow_exception(e);
174 } catch (const std::bad_alloc & e) {
175 return "Out of memory";
176 } catch (const std::exception & e) {
177 GetExceptionMessage(e, ss, 0);
178 }
179
180 try {
181 buffer = ss.str();
182 } catch (const std::bad_alloc & e) {
183 return "Out of memory";
184 }
185
186 return buffer.c_str();
187}
188
189}
190}
191
192