1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * This module provides a portable way of using operating system error codes. 7 * 8 * Copyright: Eugene Wissner 2017-2020. 9 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, 10 * Mozilla Public License, v. 2.0). 11 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) 12 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/os/tanya/os/error.d, 13 * tanya/os/error.d) 14 */ 15 module tanya.os.error; 16 17 import tanya.meta.trait; 18 19 // Socket API error. 20 private template SAError(int posix, int wsa = posix) 21 { 22 version (Windows) 23 { 24 enum SAError = 10000 + wsa; 25 } 26 else 27 { 28 alias SAError = posix; 29 } 30 } 31 32 // Error for Windows and Posix separately. 33 private template NativeError(int posix, int win) 34 { 35 version (Windows) 36 { 37 alias NativeError = win; 38 } 39 else 40 { 41 alias NativeError = posix; 42 } 43 } 44 45 version (Windows) 46 { 47 private enum eProtocolError = -71; 48 } 49 else version (OpenBSD) 50 { 51 private enum eProtocolError = -71; 52 } 53 else 54 { 55 private enum eProtocolError = 71; 56 } 57 58 /** 59 * System error code. 60 */ 61 struct ErrorCode 62 { 63 /** 64 * Error code numbers. 65 */ 66 enum ErrorNo : int 67 { 68 /// The operation completed successfully. 69 success = 0, 70 71 /// Operation not permitted. 72 noPermission = NativeError!(1, 5), 73 74 /// Interrupted system call. 75 interrupted = SAError!4, 76 77 /// Bad file descriptor. 78 badDescriptor = SAError!9, 79 80 /// An operation on a non-blocking socket would block. 81 wouldBlock = SAError!(11, 35), 82 83 /// Out of memory. 84 noMemory = NativeError!(12, 14), 85 86 /// Access denied. 87 accessDenied = SAError!13, 88 89 /// An invalid pointer address detected. 90 fault = SAError!14, 91 92 /// No such device. 93 noSuchDevice = NativeError!(19, 20), 94 95 /// An invalid argument was supplied. 96 invalidArgument = SAError!22, 97 98 /// The limit on the number of open file descriptors. 99 tooManyDescriptors = NativeError!(23, 331), 100 101 /// The limit on the number of open file descriptors. 102 noDescriptors = SAError!24, 103 104 /// Broken pipe. 105 brokenPipe = NativeError!(32, 109), 106 107 /// The name was too long. 108 nameTooLong = SAError!(36, 63), 109 110 /// A socket operation was attempted on a non-socket. 111 notSocket = SAError!(88, 38), 112 113 /// Protocol error. 114 protocolError = eProtocolError, 115 116 /// Message too long. 117 messageTooLong = SAError!(90, 40), 118 119 /// Wrong protocol type for socket. 120 wrongProtocolType = SAError!(91, 41), 121 122 /// Protocol not available. 123 noProtocolOption = SAError!(92, 42), 124 125 /// The protocol is not implemented or has not been configured. 126 protocolNotSupported = SAError!(93, 43), 127 128 /// The support for the specified socket type does not exist in this 129 /// address family. 130 socketNotSupported = SAError!(94, 44), 131 132 /// The address family is no supported by the protocol family. 133 operationNotSupported = SAError!(95, 45), 134 135 /// Address family specified is not supported. 136 addressFamilyNotSupported = SAError!(97, 47), 137 138 /// Address already in use. 139 addressInUse = SAError!(98, 48), 140 141 /// The network is not available. 142 networkDown = SAError!(100, 50), 143 144 /// No route to host. 145 networkUnreachable = SAError!(101, 51), 146 147 /// Network dropped connection because of reset. 148 networkReset = SAError!(102, 52), 149 150 /// The connection has been aborted. 151 connectionAborted = SAError!(103, 53), 152 153 /// Connection reset by peer. 154 connectionReset = SAError!(104, 54), 155 156 /// No free buffer space is available for a socket operation. 157 noBufferSpace = SAError!(105, 55), 158 159 /// Transport endpoint is already connected. 160 alreadyConnected = SAError!(106, 56), 161 162 /// Transport endpoint is not connected. 163 notConnected = SAError!(107, 57), 164 165 /// Cannot send after transport endpoint shutdown. 166 shutdown = SAError!(108, 58), 167 168 /// The connection attempt timed out, or the connected host has failed 169 /// to respond. 170 timedOut = SAError!(110, 60), 171 172 /// Connection refused. 173 connectionRefused = SAError!(111, 61), 174 175 /// Host is down. 176 hostDown = SAError!(112, 64), 177 178 /// No route to host. 179 hostUnreachable = SAError!(113, 65), 180 181 /// Operation already in progress. 182 alreadyStarted = SAError!(114, 37), 183 184 /// Operation now in progress. 185 inProgress = SAError!(115, 36), 186 187 /// Operation cancelled. 188 cancelled = SAError!(125, 103), 189 } 190 191 /** 192 * Error descriptions. 193 */ 194 private enum ErrorStr : string 195 { 196 success = "The operation completed successfully", 197 noPermission = "Operation not permitted", 198 interrupted = "Interrupted system call", 199 badDescriptor = "Bad file descriptor", 200 wouldBlock = "An operation on a non-blocking socket would block", 201 noMemory = "Out of memory", 202 accessDenied = "Access denied", 203 fault = "An invalid pointer address detected", 204 noSuchDevice = "No such device", 205 invalidArgument = "An invalid argument was supplied", 206 tooManyDescriptors = "The limit on the number of open file descriptors", 207 noDescriptors = "The limit on the number of open file descriptors", 208 brokenPipe = "Broken pipe", 209 nameTooLong = "The name was too long", 210 notSocket = "A socket operation was attempted on a non-socket", 211 protocolError = "Protocol error", 212 messageTooLong = "Message too long", 213 wrongProtocolType = "Wrong protocol type for socket", 214 noProtocolOption = "Protocol not available", 215 protocolNotSupported = "The protocol is not implemented or has not been configured", 216 socketNotSupported = "Socket type not supported", 217 operationNotSupported = "The address family is no supported by the protocol family", 218 addressFamilyNotSupported = "Address family specified is not supported", 219 addressInUse = "Address already in use", 220 networkDown = "The network is not available", 221 networkUnreachable = "No route to host", 222 networkReset = "Network dropped connection because of reset", 223 connectionAborted = "The connection has been aborted", 224 connectionReset = "Connection reset by peer", 225 noBufferSpace = "No free buffer space is available for a socket operation", 226 alreadyConnected = "Transport endpoint is already connected", 227 notConnected = "Transport endpoint is not connected", 228 shutdown = "Cannot send after transport endpoint shutdown", 229 timedOut = "Operation timed out", 230 connectionRefused = "Connection refused", 231 hostDown = "Host is down", 232 hostUnreachable = "No route to host", 233 alreadyStarted = "Operation already in progress", 234 inProgress = "Operation now in progress", 235 cancelled = "Operation cancelled", 236 } 237 238 /** 239 * Constructor. 240 * 241 * Params: 242 * value = Numeric error code. 243 */ 244 this(const ErrorNo value) @nogc nothrow pure @safe 245 { 246 this.value_ = value; 247 } 248 249 /// 250 @nogc nothrow pure @safe unittest 251 { 252 ErrorCode ec; 253 assert(ec == ErrorCode.success); 254 255 ec = ErrorCode.fault; 256 assert(ec == ErrorCode.fault); 257 } 258 259 /** 260 * Resets this $(D_PSYMBOL ErrorCode) to default 261 * ($(D_PSYMBOL ErrorCode.success)). 262 */ 263 void reset() @nogc nothrow pure @safe 264 { 265 this.value_ = ErrorNo.success; 266 } 267 268 /// 269 @nogc nothrow pure @safe unittest 270 { 271 auto ec = ErrorCode(ErrorCode.fault); 272 assert(ec == ErrorCode.fault); 273 274 ec.reset(); 275 assert(ec == ErrorCode.success); 276 } 277 278 /** 279 * Returns: Numeric error code. 280 */ 281 ErrorNo opCast(T : ErrorNo)() const 282 { 283 return this.value_; 284 } 285 286 /// ditto 287 ErrorNo opCast(T : int)() const 288 { 289 return this.value_; 290 } 291 292 /// 293 @nogc nothrow pure @safe unittest 294 { 295 ErrorCode ec = ErrorCode.fault; 296 auto errorNo = cast(ErrorCode.ErrorNo) ec; 297 298 assert(errorNo == ErrorCode.fault); 299 static assert(is(typeof(cast(int) ec))); 300 } 301 302 /** 303 * Assigns another error code or error code number. 304 * 305 * Params: 306 * that = Numeric error code. 307 * 308 * Returns: $(D_KEYWORD this). 309 */ 310 ref ErrorCode opAssign(const ErrorNo that) return @nogc nothrow pure @safe 311 { 312 this.value_ = that; 313 return this; 314 } 315 316 /// ditto 317 ref ErrorCode opAssign(const ErrorCode that) return @nogc nothrow pure @safe 318 { 319 this.value_ = that.value_; 320 return this; 321 } 322 323 /// 324 @nogc nothrow pure @safe unittest 325 { 326 ErrorCode ec; 327 assert(ec == ErrorCode.success); 328 329 ec = ErrorCode.fault; 330 assert(ec == ErrorCode.fault); 331 } 332 333 /// 334 @nogc nothrow pure @safe unittest 335 { 336 auto ec1 = ErrorCode(ErrorCode.fault); 337 ErrorCode ec2; 338 assert(ec2 == ErrorCode.success); 339 340 ec2 = ec1; 341 assert(ec1 == ec2); 342 } 343 344 /** 345 * Equality with another error code or error code number. 346 * 347 * Params: 348 * that = Numeric error code. 349 * 350 * Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal. 351 */ 352 bool opEquals(const ErrorNo that) const @nogc nothrow pure @safe 353 { 354 return this.value_ == that; 355 } 356 357 /// ditto 358 bool opEquals(const ErrorCode that) const @nogc nothrow pure @safe 359 { 360 return this.value_ == that.value_; 361 } 362 363 /// 364 @nogc nothrow pure @safe unittest 365 { 366 ErrorCode ec1 = ErrorCode.fault; 367 ErrorCode ec2 = ErrorCode.accessDenied; 368 369 assert(ec1 != ec2); 370 assert(ec1 != ErrorCode.accessDenied); 371 assert(ErrorCode.fault != ec2); 372 } 373 374 /// 375 @nogc nothrow pure @safe unittest 376 { 377 ErrorCode ec1 = ErrorCode.fault; 378 ErrorCode ec2 = ErrorCode.fault; 379 380 assert(ec1 == ec2); 381 assert(ec1 == ErrorCode.fault); 382 assert(ErrorCode.fault == ec2); 383 } 384 385 /** 386 * Returns string describing the error number. If a description for a 387 * specific error number is not available, returns $(D_KEYWORD null). 388 * 389 * Returns: String describing the error number. 390 */ 391 string toString() const @nogc nothrow pure @safe 392 { 393 foreach (e; __traits(allMembers, ErrorNo)) 394 { 395 if (__traits(getMember, ErrorNo, e) == this.value_) 396 { 397 return __traits(getMember, ErrorStr, e); 398 } 399 } 400 return null; 401 } 402 403 /// 404 @nogc nothrow pure @safe unittest 405 { 406 ErrorCode ec = ErrorCode.fault; 407 assert(ec.toString() == "An invalid pointer address detected"); 408 } 409 410 private ErrorNo value_ = ErrorNo.success; 411 412 alias ErrorNo this; 413 }