libexplain  1.4.D001
libexplain/buffer/errno/listen.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2010, 2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 3 of the License, or (at
00008  * your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/errno.h>
00020 #include <libexplain/ac/string.h>
00021 #include <libexplain/ac/sys/socket.h>
00022 #include <libexplain/ac/unistd.h>
00023 
00024 #include <libexplain/buffer/ebadf.h>
00025 #include <libexplain/buffer/enotsock.h>
00026 #include <libexplain/buffer/errno/generic.h>
00027 #include <libexplain/buffer/errno/listen.h>
00028 #include <libexplain/buffer/gettext.h>
00029 #include <libexplain/buffer/sockaddr.h>
00030 #include <libexplain/buffer/socket_type.h>
00031 #include <libexplain/explanation.h>
00032 #include <libexplain/option.h>
00033 #include <libexplain/sizeof.h>
00034 
00035 
00036 static void
00037 explain_buffer_errno_listen_system_call(explain_string_buffer_t *sb,
00038     int errnum, int fildes, int backlog)
00039 {
00040     (void)errnum;
00041     explain_string_buffer_puts(sb, "listen(");
00042     explain_string_buffer_printf(sb, "fildes = %d", fildes);
00043     explain_string_buffer_puts(sb, ", ");
00044     explain_string_buffer_printf(sb, "backlog = %d", backlog);
00045     explain_string_buffer_putc(sb, ')');
00046 }
00047 
00048 
00049 static void
00050 append_getsockname(explain_string_buffer_t *sb, int fildes)
00051 {
00052     struct sockaddr_storage sas;
00053     struct sockaddr *sa;
00054     socklen_t sa_len;
00055 
00056     sa = (struct sockaddr *)&sas;
00057     sa_len = sizeof(sas);
00058     if (getsockname(fildes, sa, &sa_len) >= 0)
00059     {
00060         explain_string_buffer_putc(sb, ' ');
00061         explain_buffer_sockaddr(sb, sa, sa_len);
00062     }
00063 }
00064 
00065 
00066 #ifdef __linux__
00067 #include <sys/syscall.h>
00068 #include <linux/sysctl.h>
00069 #endif
00070 
00071 
00072 static int
00073 get_somaxconn(void)
00074 {
00075 #ifdef __linux__
00076     struct __sysctl_args args;
00077     long somaxconn;
00078     size_t somaxconn_size = sizeof(somaxconn);
00079     int name[] = { CTL_NET, NET_CORE_SOMAXCONN };
00080 
00081     memset(&args, 0, sizeof(struct __sysctl_args));
00082     args.name = name;
00083     args.nlen = SIZEOF(name);
00084     args.oldval = &somaxconn;
00085     args.oldlenp = &somaxconn_size;
00086 
00087     if (syscall(SYS__sysctl, &args) >= 0)
00088         return somaxconn;
00089 #endif
00090 #ifdef SOMAXCONN
00091     return SOMAXCONN;
00092 #else
00093     return -1;
00094 #endif
00095 }
00096 
00097 
00098 static void
00099 explain_buffer_errno_listen_explanation(explain_string_buffer_t *sb,
00100     int errnum, int fildes, int backlog)
00101 {
00102     /*
00103      * http://www.opengroup.org/onlinepubs/009695399/functions/listen.html
00104      */
00105     switch (errnum)
00106     {
00107     case EADDRINUSE:
00108         explain_buffer_gettext
00109         (
00110             sb,
00111             /*
00112              * xgettext: This message is used to explain an EADDRINUSE error.
00113              */
00114             i18n("another socket is already listening on the same port")
00115         );
00116         append_getsockname(sb, fildes);
00117         break;
00118 
00119     case EBADF:
00120         explain_buffer_ebadf(sb, fildes, "fildes");
00121         break;
00122 
00123     case ENOTSOCK:
00124         explain_buffer_enotsock(sb, fildes, "fildes");
00125         break;
00126 
00127     case EOPNOTSUPP:
00128         explain_buffer_gettext
00129         (
00130             sb,
00131             /*
00132              * xgettext: This message is used to explain an EOPNOTSUPP
00133              * error returned by a listen(2) system call.
00134              */
00135             i18n("the socket is not of a type that supports the "
00136             "listen(2) system call")
00137         );
00138         explain_buffer_socket_type_from_fildes(sb, fildes);
00139         break;
00140 
00141     case EDESTADDRREQ:
00142         explain_buffer_gettext
00143         (
00144             sb,
00145             /*
00146              * xgettext: This message is used to explain an EDESTADDRREQ
00147              * error returned by a listen(2) system call.
00148              */
00149             i18n("the socket is not bound to a local address, and the "
00150             "protocol does not support listening on an unbound socket")
00151         );
00152         append_getsockname(sb, fildes);
00153         explain_buffer_socket_type_from_fildes(sb, fildes);
00154         break;
00155 
00156     case EINVAL:
00157         /* FIXME: which is it? */
00158         explain_buffer_gettext
00159         (
00160             sb,
00161             /*
00162              * xgettext: This message is used to explain an EINVAL
00163              * error returned by a listen(2) system call.
00164              */
00165             i18n("the socket is already connected, or the socket has "
00166             "been shut down")
00167         );
00168         append_getsockname(sb, fildes);
00169         break;
00170 
00171     default:
00172         explain_buffer_errno_generic(sb, errnum, "listen");
00173         break;
00174     }
00175     if (explain_option_dialect_specific())
00176     {
00177         int             somaxconn;
00178 
00179         somaxconn = get_somaxconn();
00180         if (somaxconn > 0 && backlog > somaxconn)
00181         {
00182             explain_string_buffer_puts(sb->footnotes, "; ");
00183             explain_string_buffer_printf_gettext
00184             (
00185                 sb->footnotes,
00186                 /*
00187                  * xgettext: This message is used to inform users of the
00188                  * listen(2) system call when they specify a backlog
00189                  * valie in excess of SOMAXCONN.
00190                  *
00191                  * %1$d => The maximum queue length for completely
00192                  *         established sockets waiting to be accepted.
00193                  */
00194                 i18n("large backlog values are silently truncated to the "
00195                     "system maximum (SOMAXCONN, %d)"),
00196                 somaxconn
00197             );
00198         }
00199     }
00200 }
00201 
00202 
00203 void
00204 explain_buffer_errno_listen(explain_string_buffer_t *sb, int errnum,
00205     int fildes, int backlog)
00206 {
00207     explain_explanation_t exp;
00208 
00209     explain_explanation_init(&exp, errnum);
00210     explain_buffer_errno_listen_system_call
00211     (
00212         &exp.system_call_sb,
00213         errnum,
00214         fildes,
00215         backlog
00216     );
00217     explain_buffer_errno_listen_explanation
00218     (
00219         &exp.explanation_sb,
00220         errnum,
00221         fildes,
00222         backlog
00223     );
00224     explain_explanation_assemble(&exp, sb);
00225 }
00226 
00227 
00228 /* vim: set ts=8 sw=4 et : */