diff options
-rw-r--r-- | APRDesign | 144 | ||||
-rw-r--r-- | include/apr_errno.h | 269 | ||||
-rw-r--r-- | include/arch/unix/misc.h | 1 | ||||
-rw-r--r-- | include/arch/unix/networkio.h | 3 | ||||
-rw-r--r-- | include/arch/win32/misc.h | 1 | ||||
-rw-r--r-- | misc/unix/Makefile.in | 2 | ||||
-rw-r--r-- | misc/unix/misc.h | 1 | ||||
-rw-r--r-- | network_io/unix/networkio.h | 3 | ||||
-rw-r--r-- | network_io/unix/sockets.c | 2 | ||||
-rw-r--r-- | network_io/unix/sockopt.c | 29 |
10 files changed, 182 insertions, 273 deletions
@@ -179,3 +179,147 @@ The format for the comment block is: */ For an actual example, look at any function in the fileio/unix directory. + +APR Error reporting + +Most APR functions should return an ap_status_t type. The only time an +APR function does not return an ap_status_t is if it absolutly CAN NOT +fail. Examples of this would be filling out an array when you know you are +not beyond the array's range. If it cannot fail on your platform, but it +could conceivably fail on another platform, it should return an ap_status_t. +Unless you are sure, return an ap_status_t. :-) + +All platform return errno values unchanged. Each platform can also have +one system error type, which can be returned after an offset is added. +There are five types of error values in APR, each with it's own offset. + + Name Purpose +0) This is 0 for all platforms and isn't really defined + anywhere, but it is the offset for errno values. + (This has no name because it isn't actually defined, + but completeness we are discussing it here). +1) APR_OS_START_ERROR This is platform dependant, and is the offset at which + APR errors start to be defined. (Canonical error + values are also defined in this section. [Canonical + error values are discussed later]). +2) APR_OS_START_STATUS This is platform dependant, and is the offset at which + APR status values start. +4) APR_OS_START_USEERR This is platform dependant, and is the offset at which + APR apps can begin to add their own error codes. +3) APR_OS_START_SYSERR This is platform dependant, and is the offset at which + system error values begin. + +All of these definitions can be found in apr_errno.h for all platforms. When +an error occurs in an APR function, the function must return an error code. +If the error occurred in a system call and that system call uses errno to +report an error, then the code is returned unchanged. For example: + + if (open(fname, oflags, 0777) < 0) + return errno; + + +The next place an error can occur is a system call that uses some error value +other than the primary error value on a platform. This can also be handled +by APR applications. For example: + + if (CreateFile(fname, oflags, sharemod, NULL, + createflags, attributes,0) == INVALID_HANDLE_VALUE + return (GetLAstError() + APR_OS_START_SYSERR); + +These two examples implement the same function for two different platforms. +Obviously even if the underlying problem is the same on both platforms, this +will result in two different error codes being returned. This is OKAY, and +is correct for APR. APR relies on the fact that most of the time an error +occurs, the program logs the error and continues, it does not try to +programatically solve the problem. This does not mean we have not provided +support for programmatically solving the problem, it just isn't the default +case. We'll get to how this problem is solved in a little while. + +If the error occurs in an APR function but it is not due to a system call, +but it is actually an APR error or just a status code from APR, then the +appropriate code should be returned. These codes are defined in apr_errno.h +and are self explanatory. + +No APR code should ever return a code between APR_OS_START_USEERR and +APR_OS_START_SYSERR, those codes are reserved for APR applications. + +To programmatically correct an error in a running application, the error codes +need to be consistent across platforms. This should make sense. To get +consistent error codes, APR provides a function ap_canonicalize_error(). +This function will take as input any ap_status_t value, and return a small +subset of canonical APR error codes. These codes will be equivalent to +Unix errno's. Why is it a small subset? Because we don't want to try to +convert everything in the first pass. As more programs require that more +error codes are converted, they will be added to this function. + +Why did APR take this approach? There are two ways to deal with error +codes portably. + +1) return the same error code across all platforms. 2) return platform +specific error codes and convert them when necessary. + +The problem with option number one is that it takes time to convert error +codes to a common code, and most of the time programs want to just output +an error string. If we convert all errors to a common subset, we have four +steps to output an error string: + + make syscall that fails + convert to common error code step 1 + return common error code + check for success + call error output function step 2 + convert back to system error step 3 + output error string step 4 + +By keeping the errors platform specific, we can output error strings in two +steps. + + make syscall that fails + return error code + check for success + call error output function step 1 + output error string step 2 + +Less often, programs change their execution based on what error was returned. +This is no more expensive using option 2 and it is using option 1, but we +put the onus of converting the error code on the programmer themselves. +For example, using option 1: + + make syscall that fails + convert to common error code + return common error code + decide execution basd on common error code + +Using option 2: + + make syscall that fails + return error code + convert to common error code (using ap_canonicalize_error) + decide execution based on common error code + +Finally, there is one more operation on error codes. You can get a string +that explains in human readable form what has happened. To do this using +APR, call ap_strerror(). + +On all platforms ap_strerror takes the form: + +char *ap_strerror(ap_status_t err) +{ + if (err < APR_OS_START_ERRNO2) + return (platform dependant error string generator) + if (err < APR_OS_START_ERROR) + return (platform dependant error string generator for + supplemental error values) + if (err < APR_OS_SYSERR) + return (APR generated error or status string) + if (err == 0) + return "No error was found" + else + return "APR doesn't understand this error value" +} + +Notice, this does not handle canonicalized error values well. Those will +return "APR doesn't understand this error value" on some platforms and +an actual error string on others. To deal with this, just get the +string before canonicalizing your error code. + diff --git a/include/apr_errno.h b/include/apr_errno.h index 8d0ece02d..9d7d20fef 100644 --- a/include/apr_errno.h +++ b/include/apr_errno.h @@ -62,29 +62,24 @@ extern "C" { #endif /* __cplusplus */ -/* Define four layers of status code offsets so that we don't interfere - * with the predefined errno codes on the operating system. Codes beyond +/* APR_OS_START_ERROR is where the APR specific error values should start. + * APR_OS_START_STATUS is where the APR specific status codes should start. * APR_OS_START_USEERR are reserved for applications that use APR that - * layer their own error codes along with APR's. + * layer their own error codes along with APR's. + * APR_OS_START_SYSERR should be used for system error values on + * each platform. */ -#ifndef APR_OS_START_ERROR -#define APR_OS_START_ERROR 4000 -#endif -#ifndef APR_OS_START_STATUS -#define APR_OS_START_STATUS (APR_OS_START_ERROR + 500) -#endif -#ifndef APR_OS_START_SYSERR -#define APR_OS_START_SYSERR (APR_OS_START_STATUS + 500) -#endif -#ifndef APR_OS_START_USEERR -#define APR_OS_START_USEERR (APR_OS_START_SYSERR + 500) -#endif +#define APR_OS_START_ERROR 1000 +#define APR_OS_START_STATUS (APR_OS_START_ERROR + 500) +#define APR_OS_START_USEERR (APR_OS_START_STATUS + 500) +#define APR_OS_START_CANONERR (APR_OS_START_USEERR + 500) +#define APR_OS_START_SYSERR (APR_OS_START_CANONERR + 500) -/* If this definition of APRStatus changes, then we can remove this, but right - * now, the decision was to use an errno-like implementation. - */ typedef int ap_status_t; +int ap_canonical_error(ap_status_t err); +const char *ap_strerror(ap_status_t err); + #define APR_SUCCESS 0 /* APR ERROR VALUES */ @@ -144,310 +139,106 @@ typedef int ap_status_t; */ #define APR_EMISMATCH (APR_OS_START_STATUS + 18) -/* - * APR equivalents to what should be standard errno codes. - */ #ifdef EACCES #define APR_EACCES EACCES #else -#define APR_EACCES (APR_OS_START_SYSERR + 0) +#define APR_EACCES (APR_OS_START_CANONERR + 1) #endif #ifdef EEXIST #define APR_EEXIST EEXIST #else -#define APR_EEXIST (APR_OS_START_SYSERR + 1) -#endif - -#ifdef EISDIR -#define APR_EISDIR EISDIR -#else -#define APR_EISDIR (APR_OS_START_SYSERR + 2) +#define APR_EEXIST (APR_OS_START_CANONERR + 12) #endif #ifdef ENAMETOOLONG #define APR_ENAMETOOLONG ENAMETOOLONG #else -#define APR_ENAMETOOLONG (APR_OS_START_SYSERR + 3) +#define APR_ENAMETOOLONG (APR_OS_START_CANONERR + 13) #endif #ifdef ENOENT #define APR_ENOENT ENOENT #else -#define APR_ENOENT (APR_OS_START_SYSERR + 4) +#define APR_ENOENT (APR_OS_START_CANONERR + 14) #endif #ifdef ENOTDIR #define APR_ENOTDIR ENOTDIR #else -#define APR_ENOTDIR (APR_OS_START_SYSERR + 5) -#endif - -#ifdef ENXIO -#define APR_ENXIO ENXIO -#else -#define APR_ENXIO (APR_OS_START_SYSERR + 6) -#endif - -#ifdef ENODEV -#define APR_ENODEV ENODEV -#else -#define APR_ENODEV (APR_OS_START_SYSERR + 7) -#endif - -#ifdef EROFS -#define APR_EROFS EROFS -#else -#define APR_EROFS (APR_OS_START_SYSERR + 8) -#endif - -#ifdef ETXTBSY -#define APR_ETXTBSY ETXTBSY -#else -#define APR_ETXTBSY (APR_OS_START_SYSERR + 9) -#endif - -#ifdef EFAULT -#define APR_EFAULT EFAULT -#else -#define APR_EFAULT (APR_OS_START_SYSERR + 10) -#endif - -#ifdef ELOOP -#define APR_ELOOP ELOOP -#else -#define APR_ELOOP (APR_OS_START_SYSERR + 11) +#define APR_ENOTDIR (APR_OS_START_CANONERR + 15) #endif #ifdef ENOSPC #define APR_ENOSPC ENOSPC #else -#define APR_ENOSPC (APR_OS_START_SYSERR + 12) +#define APR_ENOSPC (APR_OS_START_CANONERR + 16) #endif #ifdef ENONOMEM #define APR_ENOMEM ENOMEM #else -#define APR_ENOMEM (APR_OS_START_SYSERR + 13) +#define APR_ENOMEM (APR_OS_START_CANONERR + 17) #endif #ifdef EMFILE #define APR_EMFILE EMFILE #else -#define APR_EMFILE (APR_OS_START_SYSERR + 14) +#define APR_EMFILE (APR_OS_START_CANONERR + 18) #endif #ifdef ENFILE #define APR_ENFILE ENFILE #else -#define APR_ENFILE (APR_OS_START_SYSERR + 15) +#define APR_ENFILE (APR_OS_START_CANONERR + 19) #endif #ifdef EBADF #define APR_EBADF EBADF #else -#define APR_EBADF (APR_OS_START_SYSERR + 16) -#endif - -#ifdef EPERM -#define APR_EPERM EPERM -#else -#define APR_EPERM (APR_OS_START_SYSERR + 17) -#endif - -#ifdef EIO -#define APR_EIO EIO -#else -#define APR_EIO (APR_OS_START_SYSERR + 18) +#define APR_EBADF (APR_OS_START_CANONERR + 110) #endif #ifdef EINVAL #define APR_EINVAL EINVAL #else -#define APR_EINVAL (APR_OS_START_SYSERR + 19) -#endif - -#ifdef ENOEMPTY -#define APR_ENOEMPTY ENOEMPTY -#else -#define APR_ENOEMPTY (APR_OS_START_SYSERR + 20) -#endif - -#ifdef EBUSY -#define APR_EBUSY EBUSY -#else -#define APR_EBUSY (APR_OS_START_SYSERR + 21) +#define APR_EINVAL (APR_OS_START_CANONERR + 111) #endif #ifdef ESPIPE #define APR_ESPIPE ESPIPE #else -#define APR_ESPIPE (APR_OS_START_SYSERR + 22) -#endif - -#ifdef EIDRM -#define APR_EIDRM EIDRM -#else -#define APR_EIDRM (APR_OS_START_SYSERR + 23) -#endif - -#ifdef ERANGE -#define APR_ERANGE ERANGE -#else -#define APR_ERANGE (APR_OS_START_SYSERR + 24) -#endif - -#ifdef E2BIG -#define APR_E2BIG E2BIG -#else -#define APR_E2BIG (APR_OS_START_SYSERR + 25) +#define APR_ESPIPE (APR_OS_START_CANONERR + 112) #endif #ifdef EAGAIN #define APR_EAGAIN EAGAIN #else -#define APR_EAGAIN (APR_OS_START_SYSERR + 26) -#endif - -#ifdef EFBIG -#define APR_EFBIG EFBIG -#else -#define APR_EFBIG (APR_OS_START_SYSERR + 27) +#define APR_EAGAIN (APR_OS_START_CANONERR + 13) #endif #ifdef EINTR #define APR_EINTR EINTR #else -#define APR_EINTR (APR_OS_START_SYSERR + 28) -#endif - -#ifdef EDEADLK -#define APR_EDEADLK EDEADLK -#else -#define APR_EDEADLK (APR_OS_START_SYSERR + 29) -#endif - -#ifdef ENOLCK -#define APR_ENOLCK ENOLCK -#else -#define APR_ENOLCK (APR_OS_START_SYSERR + 30) -#endif - -#ifdef EWOULDBLOCK -#define APR_EWOULDBLOCK EWOULDBLOCK -#else -#define APR_EWOULDBLOCK (APR_OS_START_SYSERR + 31) -#endif - -#ifdef EPROTONOSUPPORT -#define APR_EPROTONOSUPPORT EPROTONOSUPPORT -#else -#define APR_EPROTONOSUPPORT (APR_OS_START_SYSERR + 32) +#define APR_EINTR (APR_OS_START_CANONERR + 14) #endif #ifdef ENOTSOCK #define APR_ENOTSOCK ENOTSOCK #else -#define APR_ENOTSOCK (APR_OS_START_SYSERR + 33) -#endif - -#ifdef ENOTCONN -#define APR_ENOTCONN ENOTCONN -#else -#define APR_ENOTCONN (APR_OS_START_SYSERR + 34) -#endif - -#ifdef EOPNOTSUPP -#define APR_EOPNOTSUPP EOPNOTSUPP -#else -#define APR_EOPNOTSUPP (APR_OS_START_SYSERR + 35) -#endif - -/* never use h_errno values as-is because doing so makes them - * indistinguishable from errno values - * APR_EHOSTNOTFOUND corresponds to HOST_NOT_FOUND - * APR_ENODATA corresponds to NO_DATA - * APR_ENOADDRESS corresponds to NO_ADDRESS - * APR_ENORECOVERY corresponds to NO_RECOVERY - */ -#define APR_EHOSTNOTFOUND (APR_OS_START_SYSERR + 36) - -#define APR_ENODATA (APR_OS_START_SYSERR + 37) - -#define APR_ENOADDRESS (APR_OS_START_SYSERR + 38) - -#define APR_ENORECOVERY (APR_OS_START_SYSERR + 39) - -#ifdef EISCONN -#define APR_EISCONN EISCONN -#else -#define APR_EISCONN (APR_OS_START_SYSERR + 40) -#endif - -#ifdef ETIMEDOUT -#define APR_ETIMEDOUT ETIMEDOUT -#else -#define APR_ETIMEDOUT (APR_OS_START_SYSERR + 41) +#define APR_ENOTSOCK (APR_OS_START_CANONERR + 15) #endif #ifdef ECONNREFUSED #define APR_ECONNREFUSED ECONNREFUSED #else -#define APR_ECONNREFUSED (APR_OS_START_SYSERR + 42) -#endif - -#ifdef ENETUNREACH -#define APR_ENETUNREACH ENETUNREACH -#else -#define APR_ENETUNREACH (APR_OS_START_SYSERR + 43) -#endif - -#ifdef EADDRINUSE -#define APR_EADDRINUSE EADDRINUSE -#else -#define APR_EADDRINUSE (APR_OS_START_SYSERR + 44) +#define APR_ECONNREFUSED (APR_OS_START_CANONERR + 16) #endif #ifdef EINPROGRESS #define APR_EINPROGRESS EINPROGRESS #else -#define APR_EINPROGRESS (APR_OS_START_SYSERR + 45) -#endif - -#ifdef EALREADY -#define APR_EALREADY EALREADY -#else -#define APR_EALREADY (APR_OS_START_SYSERR + 46) -#endif - -#ifdef EAFNOSUPPORT -#define APR_EAFNOSUPPORT EAFNOSUPPORT -#else -#define APR_EAFNOSUPPORT (APR_OS_START_SYSERR + 47) -#endif - -#ifdef ENOPROTOOPT -#define APR_ENOPROTOOPT ENOPROTOOPT -#else -#define APR_ENOPROTOOPT (APR_OS_START_SYSERR + 48) -#endif - -#ifdef ENOCHILD -#define APR_ENOCHILD ENOCHILD -#else -#define APR_ENOCHILD (APR_OS_START_SYSERR + 49) -#endif - -#ifdef ESRCH -#define APR_ESRCH ESRCH -#else -#define APR_ESRCH (APR_OS_START_SYSERR + 50) -#endif - -#ifdef ENOTSUP -#define APR_ENOTSUP ENOTSUP -#else -#define APR_ENOTSUP (APR_OS_START_SYSERR + 51) +#define APR_EINPROGRESS (APR_OS_START_CANONERR + 17) #endif #ifdef __cplusplus diff --git a/include/arch/unix/misc.h b/include/arch/unix/misc.h index dfa7ae62f..dfe0413a9 100644 --- a/include/arch/unix/misc.h +++ b/include/arch/unix/misc.h @@ -61,6 +61,7 @@ #include "apr_pools.h" #include "apr_getopt.h" #include "apr_thread_proc.h" +#include "apr_errno.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif diff --git a/include/arch/unix/networkio.h b/include/arch/unix/networkio.h index 98fbda7e9..6ebb096e6 100644 --- a/include/arch/unix/networkio.h +++ b/include/arch/unix/networkio.h @@ -57,6 +57,7 @@ #include "apr_config.h" #include "apr_network_io.h" +#include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" @@ -136,7 +137,5 @@ struct ap_pollfd_t { ap_int16_t get_event(ap_int16_t); ap_int16_t get_revent(ap_int16_t); -ap_status_t status_from_res_error(int); - #endif /* ! NETWORK_IO_H */ diff --git a/include/arch/win32/misc.h b/include/arch/win32/misc.h index dfa7ae62f..dfe0413a9 100644 --- a/include/arch/win32/misc.h +++ b/include/arch/win32/misc.h @@ -61,6 +61,7 @@ #include "apr_pools.h" #include "apr_getopt.h" #include "apr_thread_proc.h" +#include "apr_errno.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif diff --git a/misc/unix/Makefile.in b/misc/unix/Makefile.in index 105f10e48..90308359c 100644 --- a/misc/unix/Makefile.in +++ b/misc/unix/Makefile.in @@ -15,7 +15,7 @@ INCLUDES=-I$(INCDIR1) -I$(INCDIR2) -I. #LIB=libmisc.a -OBJS=start.o getopt.o otherchild.o +OBJS=start.o getopt.o otherchild.o error.o .c.o: $(CC) $(CFLAGS) -c $(INCLUDES) $< diff --git a/misc/unix/misc.h b/misc/unix/misc.h index dfa7ae62f..dfe0413a9 100644 --- a/misc/unix/misc.h +++ b/misc/unix/misc.h @@ -61,6 +61,7 @@ #include "apr_pools.h" #include "apr_getopt.h" #include "apr_thread_proc.h" +#include "apr_errno.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif diff --git a/network_io/unix/networkio.h b/network_io/unix/networkio.h index 98fbda7e9..6ebb096e6 100644 --- a/network_io/unix/networkio.h +++ b/network_io/unix/networkio.h @@ -57,6 +57,7 @@ #include "apr_config.h" #include "apr_network_io.h" +#include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" @@ -136,7 +137,5 @@ struct ap_pollfd_t { ap_int16_t get_event(ap_int16_t); ap_int16_t get_revent(ap_int16_t); -ap_status_t status_from_res_error(int); - #endif /* ! NETWORK_IO_H */ diff --git a/network_io/unix/sockets.c b/network_io/unix/sockets.c index 8761e9047..51c59e446 100644 --- a/network_io/unix/sockets.c +++ b/network_io/unix/sockets.c @@ -232,7 +232,7 @@ ap_status_t ap_connect(ap_socket_t *sock, char *hostname) return APR_ENOTSOCK; } if (!hp) { - return status_from_res_error(h_errno); + return (h_errno + APR_OS_START_SYSERR); } memcpy((char *)&sock->remote_addr->sin_addr, hp->h_addr_list[0], hp->h_length); diff --git a/network_io/unix/sockopt.c b/network_io/unix/sockopt.c index 0306772f1..ff73b5539 100644 --- a/network_io/unix/sockopt.c +++ b/network_io/unix/sockopt.c @@ -208,33 +208,6 @@ ap_status_t ap_get_remote_hostname(char **name, ap_socket_t *sock) } /* XXX - Is referencing h_errno threadsafe? */ - return status_from_res_error(h_errno); -} - -ap_status_t status_from_res_error(int herr) -{ - ap_status_t status; - switch(herr) { - case HOST_NOT_FOUND: - status = APR_EHOSTNOTFOUND; - break; - case TRY_AGAIN: - status = APR_EAGAIN; - break; - case NO_RECOVERY: - status = APR_ENORECOVERY; - break; - case NO_ADDRESS: - status = APR_ENOADDRESS; - break; -#if defined(NO_DATA) && (NO_ADDRESS != NO_DATA) - case NO_DATA: -#endif - status = APR_ENODATA; - break; - default: - status = APR_ENORECOVERY; - } - return status; + return (h_errno + APR_OS_START_SYSERR); } |