libexplain  1.4.D001
libexplain/buffer/errno/connect.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 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/sys/socket.h>
00021 #include <libexplain/ac/sys/stat.h>
00022 #include <libexplain/ac/sys/un.h>
00023 
00024 #include <libexplain/buffer/address_family.h>
00025 #include <libexplain/buffer/eacces.h>
00026 #include <libexplain/buffer/eaddrinuse.h>
00027 #include <libexplain/buffer/eafnosupport.h>
00028 #include <libexplain/buffer/ebadf.h>
00029 #include <libexplain/buffer/efault.h>
00030 #include <libexplain/buffer/eintr.h>
00031 #include <libexplain/buffer/enotsock.h>
00032 #include <libexplain/buffer/errno/connect.h>
00033 #include <libexplain/buffer/errno/generic.h>
00034 #include <libexplain/buffer/errno/path_resolution.h>
00035 #include <libexplain/buffer/fildes_to_pathname.h>
00036 #include <libexplain/buffer/file_type.h>
00037 #include <libexplain/buffer/gettext.h>
00038 #include <libexplain/buffer/pointer.h>
00039 #include <libexplain/buffer/software_error.h>
00040 #include <libexplain/buffer/sockaddr.h>
00041 #include <libexplain/explanation.h>
00042 #include <libexplain/option.h>
00043 
00044 
00045 static void
00046 explain_buffer_errno_connect_system_call(explain_string_buffer_t *sb,
00047     int errnum, int fildes, const struct sockaddr *serv_addr,
00048     int serv_addr_size)
00049 {
00050     (void)errnum;
00051     explain_string_buffer_printf(sb, "connect(fildes = %d", fildes);
00052     explain_buffer_fildes_to_pathname(sb, fildes);
00053     explain_string_buffer_puts(sb, ", serv_addr = ");
00054     explain_buffer_sockaddr(sb, serv_addr, serv_addr_size);
00055     explain_string_buffer_printf
00056     (
00057         sb,
00058         ", serv_addr_size = %d)",
00059         serv_addr_size
00060     );
00061 }
00062 
00063 
00064 static void
00065 explain_buffer_errno_connect_explanation(explain_string_buffer_t *sb,
00066     int errnum, int fildes, const struct sockaddr *serv_addr,
00067     int serv_addr_size)
00068 {
00069     /*
00070      * http://www.opengroup.org/onlinepubs/009695399/functions/connect.html
00071      */
00072     (void)serv_addr_size;
00073     switch (errnum)
00074     {
00075     case EACCES:
00076         if (serv_addr->sa_family == AF_UNIX)
00077         {
00078             const struct sockaddr_un *saddr;
00079             explain_final_t final_component;
00080 
00081             saddr = (const struct sockaddr_un *)serv_addr;
00082             explain_final_init(&final_component);
00083             final_component.want_to_write = 1;
00084             final_component.must_be_a_st_mode = 1;
00085             final_component.st_mode = S_IFSOCK;
00086             final_component.path_max = sizeof(saddr->sun_path) - 1;
00087             explain_buffer_eacces
00088             (
00089                 sb,
00090                 saddr->sun_path,
00091                 "sock_addr",
00092                 &final_component
00093             );
00094             break;
00095         }
00096         /* fall through... */
00097 
00098     case EPERM:
00099         explain_buffer_gettext
00100         (
00101             sb,
00102             /*
00103              * xgettext: This message is used to explain an EPERM error
00104              * reported by the connect(2) system call, in the case where
00105              * the process tried to connect to a broadcast address
00106              * without having the socket broadcast flag enabled; or, the
00107              * connection request failed because of a local firewall
00108              * rule
00109              */
00110             i18n("the process tried to connect to a broadcast address "
00111             "without having the socket broadcast flag enabled; or, the "
00112             "connection request failed because of a local firewall "
00113             "rule")
00114         );
00115         break;
00116 
00117     case EADDRINUSE:
00118         explain_buffer_eaddrinuse(sb, fildes);
00119         break;
00120 
00121     case EAFNOSUPPORT:
00122         explain_buffer_eafnosupport
00123         (
00124             sb,
00125             fildes,
00126             "fildes",
00127             serv_addr,
00128             "serv_addr"
00129         );
00130         break;
00131 
00132     case EAGAIN:
00133         explain_buffer_gettext
00134         (
00135             sb,
00136             /*
00137              * xgettext: This message is used to explain an EAGAIN error
00138              * reported by the connect(2) system call, in the case where
00139              * no more free local ports or insufficient entries in the
00140              * routing cache.
00141              */
00142             i18n("no more free local ports or insufficient entries in the "
00143             "routing cache")
00144         );
00145 #ifdef __linux__
00146         if
00147         (
00148             serv_addr->sa_family == PF_INET
00149         &&
00150             explain_option_dialect_specific()
00151         )
00152         {
00153             explain_string_buffer_puts(sb->footnotes, "; ");
00154             explain_buffer_gettext
00155             (
00156                 sb->footnotes,
00157                 /*
00158                  * xgettext: This message is used to supplement an
00159                  * EAGAIN explanation for the connect(2) system call, on
00160                  * Linux the number of local ports can be increased.
00161                  */
00162                 i18n("see the net.ipv4.ip_local_port_range sysctl in ip(7) "
00163                 "for how to increase the number of local ports")
00164             );
00165         }
00166 #endif
00167         break;
00168 
00169     case EALREADY:
00170         explain_buffer_gettext
00171         (
00172             sb,
00173             /*
00174              * xgettext: This message is used to explain an EALREADY
00175              * error reported by the connect(2) system call, in the
00176              * case where the socket is non-blocking and a previous
00177              * connection attempt has not yet been completed.
00178              */
00179             i18n("the socket is non-blocking and a previous connection "
00180             "attempt has not yet been completed")
00181         );
00182         explain_buffer_software_error(sb);
00183         break;
00184 
00185     case EBADF:
00186         explain_buffer_ebadf(sb, fildes, "fildes");
00187         break;
00188 
00189     case ECONNREFUSED:
00190         explain_buffer_gettext
00191         (
00192             sb,
00193             /*
00194              * xgettext: This message is used to explain an ECONNREFUSED
00195              * error reported by the connect(2) system call, in the
00196              * case where the remote server is accessible but is not
00197              * listening for connections to the given port; or, an
00198              * intervening firewall refused the connection.
00199              */
00200             i18n("the remote server is accessible but is not listening for "
00201             "connections to the given port; or, an intervening firewall "
00202             "refused the connection")
00203         );
00204         break;
00205 
00206     case EFAULT:
00207         explain_buffer_efault(sb, "sock_addr");
00208         break;
00209 
00210     case EINPROGRESS:
00211         explain_buffer_gettext
00212         (
00213             sb,
00214             /*
00215              * xgettext: This message is used to explain an EINPROGRESS
00216              * error reported by the connect(2) system call, in the
00217              * case where the socket is non-blocking and the connection
00218              * cannot be completed immediately.
00219              */
00220             i18n("the socket is non-blocking and the connection cannot "
00221             "be completed immediately")
00222         );
00223         explain_buffer_software_error(sb);
00224         break;
00225 
00226     case EINTR:
00227         explain_buffer_eintr(sb, "connect");
00228         break;
00229 
00230     case EISCONN:
00231         {
00232             struct sockaddr_storage sas;
00233             struct sockaddr *sa;
00234             socklen_t       siz;
00235 
00236             sa = (struct sockaddr *)&sas;
00237             siz = sizeof(sas);
00238             if (getsockname(fildes, sa, &siz) >= 0)
00239             {
00240                 char            addr[500];
00241                 explain_string_buffer_t addr_sb;
00242 
00243                 explain_string_buffer_init(&addr_sb, addr, sizeof(addr));
00244                 explain_buffer_sockaddr(&addr_sb, sa, siz);
00245                 explain_string_buffer_printf_gettext
00246                 (
00247                     sb,
00248                     /*
00249                      * xgettext: This message is used to explain an EISCONN
00250                      * error reported by the connect(2) system call, in the case
00251                      * where the socket is already connected.
00252                      *
00253                      * %1$s => The network address to which it is connected
00254                      */
00255                     i18n("the socket is already connected to %s"),
00256                     addr
00257                 );
00258             }
00259             else
00260             {
00261                 explain_buffer_gettext
00262                 (
00263                     sb,
00264                     /*
00265                      * xgettext: This message is used to explain an EISCONN
00266                      * error reported by the connect(2) system call, in the case
00267                      * where the socket is already connected, but the exact
00268                      * address cannot be determined.
00269                      */
00270                     i18n("the socket is already connected to a network address")
00271                 );
00272             }
00273             explain_buffer_software_error(sb);
00274         }
00275         break;
00276 
00277     case ENETUNREACH:
00278         /* FIXME: diagnose more routing table cases */
00279         explain_buffer_gettext
00280         (
00281             sb,
00282             /*
00283              * xgettext: This message is used to explain an ENETUNREACH
00284              * error reported by the connect(2) system call, in the case
00285              * where network or host is unreachable.
00286              */
00287             i18n("network or host is unreachable; sometimes this is a "
00288             "routing issue, sometimes the network is physically "
00289             "disconnected, sometimes a router is turned off, sometimes "
00290             "the host is physically disconnected, sometimes the host is "
00291             "turned off")
00292         );
00293         break;
00294 
00295     case ENOTSOCK:
00296         explain_buffer_enotsock(sb, fildes, "fildes");
00297         break;
00298 
00299     case ETIMEDOUT:
00300         explain_buffer_gettext
00301         (
00302             sb,
00303             /*
00304              * xgettext: This message is used to explain an ETIMEDOUT
00305              * error reported by the connect(2) system call, in the case
00306              * where the connection attempt took to long.
00307              */
00308             i18n("the connection attempt took to long; the server may be too "
00309             "busy to accept new connections, or an intervening firewall "
00310             "may be discarding your packets")
00311         );
00312         break;
00313 
00314     default:
00315         explain_buffer_errno_generic(sb, errnum, "connect");
00316         break;
00317     }
00318 }
00319 
00320 
00321 void
00322 explain_buffer_errno_connect(explain_string_buffer_t *sb, int errnum,
00323     int fildes, const struct sockaddr *serv_addr, int serv_addr_size)
00324 {
00325     explain_explanation_t exp;
00326 
00327     explain_explanation_init(&exp, errnum);
00328     explain_buffer_errno_connect_system_call
00329     (
00330         &exp.system_call_sb,
00331         errnum,
00332         fildes,
00333         serv_addr,
00334         serv_addr_size
00335     );
00336     explain_buffer_errno_connect_explanation
00337     (
00338         &exp.explanation_sb,
00339         errnum,
00340         fildes,
00341         serv_addr,
00342         serv_addr_size
00343     );
00344     explain_explanation_assemble(&exp, sb);
00345 }
00346 
00347 
00348 /* vim: set ts=8 sw=4 et : */