libexplain  1.4.D001
libexplain/buffer/errno/setsockopt.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2009, 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/netinet/in.h>
00021 #include <libexplain/ac/sys/socket.h>
00022 
00023 #include <libexplain/buffer/char_data.h>
00024 #include <libexplain/buffer/ebadf.h>
00025 #include <libexplain/buffer/efault.h>
00026 #include <libexplain/buffer/einval.h>
00027 #include <libexplain/buffer/enoprotoopt.h>
00028 #include <libexplain/buffer/enotsock.h>
00029 #include <libexplain/buffer/errno/generic.h>
00030 #include <libexplain/buffer/errno/setsockopt.h>
00031 #include <libexplain/buffer/fildes_to_pathname.h>
00032 #include <libexplain/buffer/int.h>
00033 #include <libexplain/buffer/pointer.h>
00034 #include <libexplain/buffer/sockaddr.h>
00035 #include <libexplain/buffer/socklen.h>
00036 #include <libexplain/buffer/sockopt_level.h>
00037 #include <libexplain/buffer/sockopt_name.h>
00038 #include <libexplain/buffer/timeval.h>
00039 #include <libexplain/explanation.h>
00040 #include <libexplain/is_efault.h>
00041 
00042 
00043 static void
00044 explain_buffer_sockopt(explain_string_buffer_t *sb, int level, int name,
00045     const void *data, socklen_t data_size)
00046 {
00047     if (explain_is_efault_pointer(data, data_size))
00048     {
00049         explain_buffer_pointer(sb, data);
00050         return;
00051     }
00052     switch (level)
00053     {
00054     /* FIXME: add support for SOL_AAL */
00055     /* FIXME: add support for SOL_ATALK */
00056     /* FIXME: add support for SOL_ATM */
00057     /* FIXME: add support for SOL_AX25 */
00058     /* FIXME: add support for SOL_BLUETOOTH */
00059     /* FIXME: add support for SOL_DCCP */
00060     /* FIXME: add support for SOL_DECNET */
00061     /* FIXME: add support for SOL_ICMP */
00062     /* FIXME: add support for SOL_ICMPV6 */
00063 
00064 #ifdef SOL_IP
00065     case SOL_IP:
00066         switch (name)
00067         {
00068         case IP_TOS:
00069         case IP_TTL:
00070         case IP_HDRINCL:
00071 #ifdef IP_ROUTER_ALERT
00072         case IP_ROUTER_ALERT:
00073 #endif
00074         case IP_RECVOPTS:
00075 #ifdef IP_PKTINFO
00076         case IP_PKTINFO:
00077 #endif
00078 #ifdef IP_MTU_DISCOVER
00079         case IP_MTU_DISCOVER:
00080 #endif
00081 #ifdef IP_RECVERR
00082         case IP_RECVERR:
00083 #endif
00084         case IP_RECVTTL:
00085 #ifdef IP_RECVTOS
00086         case IP_RECVTOS:
00087 #endif
00088         case IP_MULTICAST_TTL:
00089         case IP_MULTICAST_LOOP:
00090             if (data_size >= sizeof(int))
00091             {
00092                 explain_buffer_int_star(sb, data);
00093                 break;
00094             }
00095             goto dunno;
00096 
00097 #ifndef __bsd__
00098         case IP_OPTIONS:
00099         case IP_RETOPTS:
00100             if (data_size >= sizeof(struct ip_opts))
00101             {
00102                 const struct ip_opts *p;
00103 
00104                 p = data;
00105                 explain_string_buffer_puts(sb, "{ ip_dst = ");
00106                 explain_buffer_in_addr(sb, &p->ip_dst);
00107                 explain_string_buffer_puts(sb, ", ip_opts = ");
00108                 explain_buffer_char_data(sb, p->ip_opts, sizeof(p->ip_opts));
00109                 explain_string_buffer_putc(sb, '}');
00110                 break;
00111             }
00112             goto dunno;
00113 #endif
00114 
00115         case IP_PKTOPTIONS:
00116             goto dunno;
00117 
00118         case IP_MSFILTER:
00119         case MCAST_MSFILTER:
00120             if (data_size >= sizeof(struct ip_msfilter))
00121             {
00122                 const struct ip_msfilter *p;
00123                 size_t          j;
00124 
00125                 p = data;
00126                 explain_string_buffer_puts(sb, "{ imsf_multiaddr = ");
00127                 explain_buffer_in_addr(sb, &p->imsf_multiaddr);
00128                 explain_string_buffer_puts(sb, ", imsf_interface = ");
00129                 explain_buffer_in_addr(sb, &p->imsf_interface);
00130                 explain_string_buffer_printf
00131                 (
00132                     sb,
00133                     ", imsf_fmode = 0x%08lX, imsf_numsrc = 0x%08lX, "
00134                         "imsf_slist = { ",
00135                     (long)p->imsf_fmode,
00136                     (long)p->imsf_numsrc
00137                 );
00138                 for (j = 0; j < p->imsf_numsrc; ++j)
00139                 {
00140                     const struct in_addr *q;
00141                     const char      *end;
00142 
00143                     q = &p->imsf_slist[j];
00144                     end = (const char *)(q + 1);
00145                     if ((socklen_t)(end - (const char *)data) > data_size)
00146                         break;
00147                     if (j)
00148                         explain_string_buffer_puts(sb, ", ");
00149                     explain_buffer_in_addr(sb, q);
00150                 }
00151                 explain_string_buffer_puts(sb, " }}");
00152                 break;
00153             }
00154             goto dunno;
00155 
00156         case IP_MULTICAST_IF:
00157             if (data_size >= sizeof(struct in_addr))
00158             {
00159                 const struct in_addr *p;
00160 
00161                 p = data;
00162                 explain_string_buffer_puts(sb, "{ ");
00163                 explain_buffer_in_addr(sb, p);
00164                 explain_string_buffer_puts(sb, " }");
00165                 break;
00166             }
00167             goto dunno;
00168 
00169         case IP_ADD_MEMBERSHIP:
00170         case IP_DROP_MEMBERSHIP:
00171             if (data_size == sizeof(struct ip_mreq))
00172             {
00173                 const struct ip_mreq *p;
00174 
00175                 p = data;
00176                 explain_string_buffer_puts(sb, "{ imr_multiaddr = ");
00177                 explain_buffer_in_addr(sb, &p->imr_multiaddr);
00178                 explain_string_buffer_puts(sb, ", imr_interface = ");
00179                 explain_buffer_in_addr(sb, &p->imr_interface);
00180                 explain_string_buffer_puts(sb, " }");
00181                 break;
00182             }
00183             if (data_size >= sizeof(struct ip_mreqn))
00184             {
00185                 const struct ip_mreqn *p;
00186 
00187                 p = data;
00188                 explain_string_buffer_puts(sb, "{ imr_multiaddr = ");
00189                 explain_buffer_in_addr(sb, &p->imr_multiaddr);
00190                 explain_string_buffer_puts(sb, ", imr_address = ");
00191                 explain_buffer_in_addr(sb, &p->imr_address);
00192                 explain_string_buffer_printf
00193                 (
00194                     sb,
00195                     ", imr_ifindex = %d }",
00196                     p->imr_ifindex
00197                 );
00198                 break;
00199             }
00200             goto dunno;
00201 
00202         case IP_UNBLOCK_SOURCE:
00203         case IP_BLOCK_SOURCE:
00204         case IP_ADD_SOURCE_MEMBERSHIP:
00205         case IP_DROP_SOURCE_MEMBERSHIP:
00206             if (data_size >= sizeof(struct ip_mreq_source))
00207             {
00208                 const struct ip_mreq_source *p;
00209 
00210                 p = data;
00211                 explain_string_buffer_puts(sb, "{ imr_multiaddr = ");
00212                 explain_buffer_in_addr(sb, &p->imr_multiaddr);
00213                 explain_string_buffer_puts(sb, ", imr_interface = ");
00214                 explain_buffer_in_addr(sb, &p->imr_interface);
00215                 explain_string_buffer_puts(sb, ", imr_sourceaddr = ");
00216                 explain_buffer_in_addr(sb, &p->imr_sourceaddr);
00217                 explain_string_buffer_puts(sb, " }");
00218                 break;
00219             }
00220             goto dunno;
00221 
00222         case MCAST_JOIN_GROUP:
00223         case MCAST_LEAVE_GROUP:
00224             if (data_size >= sizeof(struct group_req))
00225             {
00226                 const struct group_req *p;
00227 
00228                 p = data;
00229                 explain_string_buffer_printf
00230                 (
00231                     sb,
00232                     "{ gr_interface = %lu, gr_group = ",
00233                     (long)p->gr_interface
00234                 );
00235                 explain_buffer_sockaddr
00236                 (
00237                     sb,
00238                     (const struct sockaddr *)&p->gr_group,
00239                     sizeof(p->gr_group)
00240                 );
00241                 explain_string_buffer_puts(sb, " }");
00242                 break;
00243             }
00244             goto dunno;
00245 
00246         case MCAST_BLOCK_SOURCE:
00247         case MCAST_UNBLOCK_SOURCE:
00248         case MCAST_JOIN_SOURCE_GROUP:
00249         case MCAST_LEAVE_SOURCE_GROUP:
00250             if (data_size >= sizeof(struct group_source_req))
00251             {
00252                 const struct group_source_req *p;
00253 
00254                 p = data;
00255                 explain_string_buffer_printf
00256                 (
00257                     sb,
00258                     "{ gsr_interface = %lu, gsr_group = ",
00259                     (unsigned long)p->gsr_interface
00260                 );
00261                 explain_buffer_sockaddr
00262                 (
00263                     sb,
00264                     (const struct sockaddr *)&p->gsr_group,
00265                     sizeof(p->gsr_group)
00266                 );
00267                 explain_string_buffer_puts(sb, ", gsr_source = ");
00268                 explain_buffer_sockaddr
00269                 (
00270                     sb,
00271                     (const struct sockaddr *)&p->gsr_source,
00272                     sizeof(p->gsr_source)
00273                 );
00274                 explain_string_buffer_puts(sb, " }");
00275                 break;
00276             }
00277             goto dunno;
00278 
00279         default:
00280             goto dunno;
00281         }
00282         break;
00283 #endif
00284 
00285     /* FIXME: add support for SOL_IPV6 */
00286     /* FIXME: add support for SOL_IPX */
00287     /* FIXME: add support for SOL_IRDA */
00288     /* FIXME: add support for SOL_LLC */
00289     /* FIXME: add support for SOL_NETBEUI */
00290     /* FIXME: add support for SOL_NETLINK */
00291     /* FIXME: add support for SOL_NETROM */
00292     /* FIXME: add support for SOL_PACKET */
00293     /* FIXME: add support for SOL_PPPOL2TP */
00294     /* FIXME: add support for SOL_RAW */
00295     /* FIXME: add support for SOL_ROSE */
00296     /* FIXME: add support for SOL_RXRPC */
00297     /* FIXME: add support for SOL_SCTP */
00298 
00299     case SOL_SOCKET:
00300         switch (name)
00301         {
00302 #ifdef SO_BINDTODEVICE
00303         case SO_BINDTODEVICE:
00304             explain_string_buffer_puts_quoted_n(sb, data, data_size);
00305             break;
00306 #endif
00307 
00308         case SO_LINGER:
00309             if (data_size >= sizeof(struct linger))
00310             {
00311                 const struct linger *p;
00312 
00313                 p = data;
00314                 explain_string_buffer_printf
00315                 (
00316                     sb,
00317                     "{ l_onoff = %d, l_linger = %d }",
00318                     p->l_onoff,
00319                     p->l_linger
00320                 );
00321                 break;
00322             }
00323             goto dunno;
00324 
00325         case SO_RCVTIMEO:
00326         case SO_SNDTIMEO:
00327             if (data_size >= sizeof(struct timeval))
00328             {
00329                 explain_buffer_timeval(sb, data);
00330                 break;
00331             }
00332             goto dunno;
00333 
00334         default:
00335             goto dunno;
00336         }
00337         break;
00338 
00339     /* FIXME: add supoirt for SOL_TCP */
00340     /* FIXME: add supoirt for SOL_TIPC */
00341     /* FIXME: add supoirt for SOL_UDP */
00342     /* FIXME: add supoirt for SOL_UDPLITE */
00343     /* FIXME: add supoirt for SOL_X25 */
00344 
00345     default:
00346         dunno:
00347         if (data_size == sizeof(int))
00348             explain_buffer_int_star(sb, data);
00349         else
00350             explain_buffer_char_data(sb, data, data_size);
00351         break;
00352     }
00353 }
00354 
00355 
00356 static void
00357 explain_buffer_errno_setsockopt_system_call(explain_string_buffer_t *sb,
00358     int errnum, int fildes, int level, int name, void *data,
00359     socklen_t data_size)
00360 {
00361     (void)errnum;
00362     explain_string_buffer_printf(sb, "setsockopt(fildes = %d", fildes);
00363     explain_buffer_fildes_to_pathname(sb, fildes);
00364     explain_string_buffer_puts(sb, ", level = ");
00365     explain_buffer_sockopt_level(sb, level);
00366     explain_string_buffer_puts(sb, ", name = ");
00367     explain_buffer_sockopt_name(sb, level, name);
00368     explain_string_buffer_puts(sb, ", data = ");
00369     explain_buffer_sockopt(sb, level, name, data, data_size);
00370     explain_string_buffer_puts(sb, ", data_size = ");
00371     explain_buffer_socklen(sb, data_size);
00372     explain_string_buffer_putc(sb, ')');
00373 }
00374 
00375 
00376 static void
00377 explain_buffer_errno_setsockopt_explanation(explain_string_buffer_t *sb,
00378     int errnum, int fildes, int level, int name, void *data,
00379     socklen_t data_size)
00380 {
00381     /*
00382      * http://www.opengroup.org/onlinepubs/009695399/functions/setsockopt.html
00383      */
00384     (void)level;
00385     (void)name;
00386     (void)data;
00387     switch (errnum)
00388     {
00389     case EBADF:
00390         explain_buffer_ebadf(sb, fildes, "fildes");
00391         break;
00392 
00393     case EFAULT:
00394         explain_buffer_efault(sb, "data");
00395         break;
00396 
00397     case EINVAL:
00398         explain_buffer_einval_too_small(sb, "data_size", data_size);
00399         break;
00400 
00401     case ENOPROTOOPT:
00402         explain_buffer_enoprotoopt(sb, "name");
00403         break;
00404 
00405     case ENOTSOCK:
00406         explain_buffer_enotsock(sb, fildes, "fildes");
00407         break;
00408 
00409     default:
00410         explain_buffer_errno_generic(sb, errnum, "setsockopt");
00411         break;
00412     }
00413 }
00414 
00415 
00416 void
00417 explain_buffer_errno_setsockopt(explain_string_buffer_t *sb, int errnum,
00418     int fildes, int level, int name, void *data, socklen_t data_size)
00419 {
00420     explain_explanation_t exp;
00421 
00422     explain_explanation_init(&exp, errnum);
00423     explain_buffer_errno_setsockopt_system_call
00424     (
00425         &exp.system_call_sb,
00426         errnum,
00427         fildes,
00428         level,
00429         name,
00430         data,
00431         data_size
00432     );
00433     explain_buffer_errno_setsockopt_explanation
00434     (
00435         &exp.explanation_sb,
00436         errnum,
00437         fildes,
00438         level,
00439         name,
00440         data,
00441         data_size
00442     );
00443     explain_explanation_assemble(&exp, sb);
00444 }
00445 
00446 /* vim: set ts=8 sw=4 et : */