1 /*
2  * Copyright (c) 2011, 2012, 2013
3  *      Inferno Nettverk A/S, Norway.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. The above copyright notice, this list of conditions and the following
9  *    disclaimer must appear in all copies of the software, derivative works
10  *    or modified versions, and any portions thereof, aswell as in all
11  *    supporting documentation.
12  * 2. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by
15  *      Inferno Nettverk A/S, Norway.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Inferno Nettverk A/S requests users of this software to return to
31  *
32  *  Software Distribution Coordinator  or  sdc@inet.no
33  *  Inferno Nettverk A/S
34  *  Oslo Research Park
35  *  Gaustadall�en 21
36  *  NO-0349 Oslo
37  *  Norway
38  *
39  * any improvements or extensions that they make and grant Inferno Nettverk A/S
40  * the rights to redistribute these changes.
41  *
42  */
43 
44 #include "common.h"
45 
46 #include "qos.h"
47 
48 static const char rcsid[] =
49 "$Id: sockopt.c,v 1.26 2013/10/25 12:55:01 karls Exp $";
50 
51 struct option {
52    int level;
53    int optname;
54    char *optstr;
55 };
56 static const struct option option[];
57 static const sockopt_t sockopts[];
58 static const sockoptvalsym_t sockoptvalsyms[];
59 
60 
61 int
socketoptdup(s,new_s)62 socketoptdup(s, new_s)
63    int s;
64    int new_s;
65 {
66    const char *function = "socketoptdup()";
67    unsigned int i;
68    int flags, errno_s;
69    socklen_t len;
70    socketoptvalue_t val;
71 
72    errno_s = errno;
73 
74    slog(LOG_DEBUG, "%s: fd %d, fd %d", function, s, new_s);
75 
76    if (new_s == -1) {
77       struct sockaddr_storage addr;
78       int domain;
79 
80       len = sizeof(addr);
81       if (getsockname(s, TOSA(&addr), &len) == -1) {
82          swarn("%s: getsockname(2) failed" , function);
83          return -1;
84       }
85 
86       domain = addr.ss_family;
87 
88       len = sizeof(val.int_val);
89       if (getsockopt(s, SOL_SOCKET, SO_TYPE, &val, &len) == -1) {
90          swarn("%s: getsockopt(SO_TYPE) failed", function);
91          return -1;
92       }
93 
94       if ((new_s = socket(domain, val.int_val, 0)) == -1) {
95          swarn("%s: socket(%d, %d)", function, domain, val.int_val);
96          return -1;
97       }
98    }
99 
100    for (i = 0; i < HAVE_DUPSOCKOPT_MAX; ++i) {
101       len = sizeof(val);
102       if (getsockopt(s, option[i].level, option[i].optname, &val, &len) == -1) {
103          if (errno != ENOPROTOOPT)
104             slog(LOG_DEBUG, "%s: getsockopt(%d, %d) failed: %s",
105                  function, option[i].level, option[i].optname, strerror(errno));
106 
107          continue;
108       }
109 
110       if (setsockopt(new_s, option[i].level, option[i].optname, &val, len)
111       == -1)
112          if (errno != ENOPROTOOPT)
113             slog(LOG_DEBUG, "%s: setsockopt(%d, %d) failed: %s",
114                  function, option[i].level, option[i].optname, strerror(errno));
115    }
116 
117    if ((flags = fcntl(s, F_GETFL, 0))          == -1
118    ||           fcntl(new_s, F_SETFL, flags)   == -1)
119       swarn("%s: fcntl(F_GETFL/F_SETFL)", function);
120 
121    errno = errno_s;
122    return new_s;
123 }
124 
125 #if DEBUG
126 void
printsocketopts(s)127 printsocketopts(s)
128    const int s;
129 {
130    const char *function = "printsocketopts()";
131    unsigned int i;
132    int flags, errno_s;
133    socklen_t len;
134    socketoptvalue_t val;
135 
136    errno_s = errno;
137 
138    len = sizeof(val);
139    if (getsockopt(s, SOL_SOCKET, SO_TYPE, &val, &len) == -1) {
140       swarn("%s: getsockopt(SO_TYPE)", function);
141       return;
142    }
143 
144    for (i = 0; i < HAVE_DUPSOCKOPT_MAX; ++i) {
145       len = sizeof(val);
146       if (getsockopt(s, option[i].level, option[i].optname, &val, &len) == -1) {
147          if (errno != ENOPROTOOPT)
148             swarn("%s: getsockopt(%s) failed", function, option[i].optstr);
149 
150          continue;
151       }
152 
153       slog(LOG_DEBUG, "%s: value of socket option \"%s\" is %d\n",
154            function, option[i].optstr, val.int_val);
155    }
156 
157    if ((flags = fcntl(s, F_GETFL, 0)) == -1)
158       swarn("%s: fcntl(F_GETFL)", function);
159    else
160       slog(LOG_DEBUG, "%s: value of file status flags: %d\n", function, flags);
161 
162    if ((flags = fcntl(s, F_GETFD, 0)) == -1)
163       swarn("fcntl(F_GETFD)");
164    else
165       slog(LOG_DEBUG, "%s: value of file descriptor flags: %d\n",
166            function, flags);
167 
168    errno = errno_s;
169 }
170 
171 #endif /* DEBUG */
172 
173 void
sockopts_dump(void)174 sockopts_dump(void)
175 {
176    const char *function = "sockopts_dump()";
177    int i;
178 
179    slog(LOG_DEBUG, "%s: socket option name (level/value) (%d entries):",
180         function, HAVE_SOCKOPTVAL_MAX);
181 
182    for (i = 0; i < HAVE_SOCKOPTVAL_MAX; i++)
183       slog(LOG_DEBUG, "%s: %02d: %s (%d/%d)",
184            function, i, sockopts[i].name, sockopts[i].level, sockopts[i].value);
185 
186    slog(LOG_DEBUG, "%s: socket option symbolic values (%d entries):",
187         function, HAVE_SOCKOPTVALSYM_MAX);
188 
189    for (i = 0; i < HAVE_SOCKOPTVALSYM_MAX; i++) {
190       const sockopt_t *opt;
191 
192       SASSERTX(sockoptvalsyms[i].optid < HAVE_SOCKOPTVAL_MAX);
193 
194       opt = &sockopts[sockoptvalsyms[i].optid];
195 
196       slog(LOG_DEBUG, "%s: %02d: %s: %s (%s)",
197            function,
198            i,
199            opt->name,
200            sockoptvalsyms[i].name,
201            sockoptval2string(sockoptvalsyms[i].symval, opt->opttype, NULL, 0));
202    }
203 }
204 
205 const sockopt_t *
optname2sockopt(char * name)206 optname2sockopt(char *name)
207 {
208    int i;
209 
210    for (i = 0; i < HAVE_SOCKOPTVAL_MAX; i++) {
211       if (strcmp(name, sockopts[i].name) == 0)
212          return &sockopts[i];
213    }
214 
215    return NULL;
216 }
217 
218 const sockopt_t *
optval2sockopt(int level,int value)219 optval2sockopt(int level, int value)
220 {
221    int i;
222 
223    for (i = 0; i < HAVE_SOCKOPTVAL_MAX; i++) {
224       if (level == sockopts[i].level && value == sockopts[i].value)
225          return &sockopts[i];
226    }
227 
228    return NULL;
229 }
230 
231 const sockopt_t *
optid2sockopt(size_t optid)232 optid2sockopt(size_t optid)
233 {
234    SASSERTX(optid < HAVE_SOCKOPTVAL_MAX);
235 
236    return &sockopts[optid];
237 }
238 
239 const sockoptvalsym_t *
optval2valsym(size_t optid,char * name)240 optval2valsym(size_t optid, char *name)
241 {
242    int i;
243 
244    for (i = 0; i < HAVE_SOCKOPTVALSYM_MAX; i++) {
245       if (optid == sockoptvalsyms[i].optid
246       && strcmp(name, sockoptvalsyms[i].name) == 0)
247          return &sockoptvalsyms[i];
248    }
249 
250    return NULL;
251 }
252 
253 /*
254  * Include platform dependent socket option code.
255  */
256 #include "sockopt_gen.c"
257