nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* source: sysutils.c */
2 /* Copyright Gerhard Rieger */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4  
5 /* translate socket addresses into human readable form */
6  
7 #include "config.h"
8 #include "xioconfig.h"
9  
10 #include "sysincludes.h"
11  
12 #include "compat.h" /* socklen_t */
13 #include "mytypes.h"
14 #include "error.h"
15 #include "sycls.h"
16 #include "utils.h"
17 #include "sysutils.h"
18  
19 /* Substitute for Write():
20 Try to write all bytes before returning; this handles EINTR,
21 EAGAIN/EWOULDBLOCK, and partial write situations. The drawback is that this
22 function might block even with O_NONBLOCK option.
23 Returns <0 on unhandled error, errno valid
24 Will only return <0 or bytes
25 */
26 ssize_t writefull(int fd, const void *buff, size_t bytes) {
27 size_t writt = 0;
28 ssize_t chk;
29 while (1) {
30 chk = Write(fd, (const char *)buff + writt, bytes - writt);
31 if (chk < 0) {
32 switch (errno) {
33 case EINTR:
34 case EAGAIN:
35 #if EAGAIN != EWOULDBLOCK
36 case EWOULDBLOCK:
37 #endif
38 Warn4("write(%d, %p, "F_Zu"): %s", fd, (const char *)buff+writt, bytes-writt, strerror(errno));
39 Sleep(1); continue;
40 default: return -1;
41 }
42 } else if (writt+chk < bytes) {
43 Warn4("write(%d, %p, "F_Zu"): only wrote "F_Zu" bytes, trying to continue ",
44 fd, (const char *)buff+writt, bytes-writt, chk);
45 writt += chk;
46 } else {
47 writt = bytes;
48 break;
49 }
50 }
51 return writt;
52 }
53  
54 #if WITH_UNIX
55 void socket_un_init(struct sockaddr_un *sa) {
56 #if HAVE_STRUCT_SOCKADDR_SALEN
57 sa->sun_len = sizeof(struct sockaddr_un);
58 #endif
59 sa->sun_family = AF_UNIX;
60 memset(sa->sun_path, '\0', sizeof(sa->sun_path));
61 }
62 #endif /* WITH_UNIX */
63  
64 #if WITH_IP4
65 void socket_in_init(struct sockaddr_in *sa) {
66 #if HAVE_STRUCT_SOCKADDR_SALEN
67 sa->sin_len = sizeof(struct sockaddr_in);
68 #endif
69 sa->sin_family = AF_INET;
70 sa->sin_port = 0;
71 sa->sin_addr.s_addr = 0;
72 sa->sin_zero[0] = 0;
73 sa->sin_zero[1] = 0;
74 sa->sin_zero[2] = 0;
75 sa->sin_zero[3] = 0;
76 sa->sin_zero[4] = 0;
77 sa->sin_zero[5] = 0;
78 sa->sin_zero[6] = 0;
79 sa->sin_zero[7] = 0;
80 }
81 #endif /* WITH_IP4 */
82  
83 #if WITH_IP6
84 void socket_in6_init(struct sockaddr_in6 *sa) {
85 #if HAVE_STRUCT_SOCKADDR_SALEN
86 sa->sin6_len = sizeof(struct sockaddr_in6);
87 #endif
88 sa->sin6_family = AF_INET6;
89 sa->sin6_port = 0;
90 sa->sin6_flowinfo = 0;
91 #if HAVE_IP6_SOCKADDR==0
92 sa->sin6_addr.s6_addr[0] = 0;
93 sa->sin6_addr.s6_addr[1] = 0;
94 sa->sin6_addr.s6_addr[2] = 0;
95 sa->sin6_addr.s6_addr[3] = 0;
96 sa->sin6_addr.s6_addr[4] = 0;
97 sa->sin6_addr.s6_addr[5] = 0;
98 sa->sin6_addr.s6_addr[6] = 0;
99 sa->sin6_addr.s6_addr[7] = 0;
100 sa->sin6_addr.s6_addr[8] = 0;
101 sa->sin6_addr.s6_addr[9] = 0;
102 sa->sin6_addr.s6_addr[10] = 0;
103 sa->sin6_addr.s6_addr[11] = 0;
104 sa->sin6_addr.s6_addr[12] = 0;
105 sa->sin6_addr.s6_addr[13] = 0;
106 sa->sin6_addr.s6_addr[14] = 0;
107 sa->sin6_addr.s6_addr[15] = 0;
108 #elif HAVE_IP6_SOCKADDR==1
109 sa->sin6_addr.u6_addr.u6_addr32[0] = 0;
110 sa->sin6_addr.u6_addr.u6_addr32[1] = 0;
111 sa->sin6_addr.u6_addr.u6_addr32[2] = 0;
112 sa->sin6_addr.u6_addr.u6_addr32[3] = 0;
113 #elif HAVE_IP6_SOCKADDR==2
114 sa->sin6_addr.u6_addr32[0] = 0;
115 sa->sin6_addr.u6_addr32[1] = 0;
116 sa->sin6_addr.u6_addr32[2] = 0;
117 sa->sin6_addr.u6_addr32[3] = 0;
118 #elif HAVE_IP6_SOCKADDR==3
119 sa->sin6_addr.in6_u.u6_addr32[0] = 0;
120 sa->sin6_addr.in6_u.u6_addr32[1] = 0;
121 sa->sin6_addr.in6_u.u6_addr32[2] = 0;
122 sa->sin6_addr.in6_u.u6_addr32[3] = 0;
123 #elif HAVE_IP6_SOCKADDR==4
124 sa->sin6_addr._S6_un._S6_u32[0] = 0;
125 sa->sin6_addr._S6_un._S6_u32[1] = 0;
126 sa->sin6_addr._S6_un._S6_u32[2] = 0;
127 sa->sin6_addr._S6_un._S6_u32[3] = 0;
128 #elif HAVE_IP6_SOCKADDR==5
129 sa->sin6_addr.__u6_addr.__u6_addr32[0] = 0;
130 sa->sin6_addr.__u6_addr.__u6_addr32[1] = 0;
131 sa->sin6_addr.__u6_addr.__u6_addr32[2] = 0;
132 sa->sin6_addr.__u6_addr.__u6_addr32[3] = 0;
133 #endif
134 }
135 #endif /* WITH_IP6 */
136  
137  
138 #if _WITH_SOCKET
139 /* initializes the socket address of the specified address family. Returns the
140 length of the specific socket address, or 0 on error. */
141 socklen_t socket_init(int af, union sockaddr_union *sa) {
142 switch (af) {
143 case AF_UNSPEC: memset(sa, 0, sizeof(*sa)); return sizeof(*sa);
144 #if WITH_UNIX
145 case AF_UNIX: socket_un_init(&sa->un); return sizeof(sa->un);
146 #endif
147 #if WITH_IP4
148 case AF_INET: socket_in_init(&sa->ip4); return sizeof(sa->ip4);
149 #endif
150 #if WITH_IP6
151 case AF_INET6: socket_in6_init(&sa->ip6); return sizeof(sa->ip6);
152 #endif
153 default: Info1("socket_init(): unknown address family %d", af);
154 memset(sa, 0, sizeof(union sockaddr_union));
155 sa->soa.sa_family = af;
156 return 0;
157 }
158 }
159 #endif /* _WITH_SOCKET */
160  
161 #if WITH_UNIX
162 #define XIOUNIXSOCKOVERHEAD (sizeof(struct sockaddr_un)-sizeof(((struct sockaddr_un*)0)->sun_path))
163 #endif
164  
165 #if _WITH_SOCKET
166 /* writes a textual human readable representation of the sockaddr contents to buff and returns a pointer to buff
167 writes at most blen bytes to buff including the terminating \0 byte
168 */
169 char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size_t blen) {
170 union sockaddr_union *sau = (union sockaddr_union *)sa;
171 char *lbuff = buff;
172 char *cp = lbuff;
173 int n;
174  
175 #if HAVE_STRUCT_SOCKADDR_SALEN
176 n = xio_snprintf(cp, blen, "LEN=%d ", sau->soa.sa_len);
177 if (n < 0 || n >= blen) {
178 Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
179 *buff = '\0';
180 return buff;
181 }
182 cp += n, blen -= n;
183 #endif
184 n = xio_snprintf(cp, blen, "AF=%d ", sau->soa.sa_family);
185 if (n < 0 || n >= blen) {
186 Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
187 *buff = '\0';
188 return buff;
189 }
190 cp += n, blen -= n;
191  
192 switch (sau->soa.sa_family) {
193 #if WITH_UNIX
194 case 0:
195 case AF_UNIX: sockaddr_unix_info(&sau->un, salen, cp+1, blen-1);
196 cp[0] = '"';
197 strncat(cp+1, "\"", 1);
198 break;
199 #endif
200 #if WITH_IP4
201 case AF_INET: sockaddr_inet4_info(&sau->ip4, cp, blen);
202 break;
203 #endif
204 #if WITH_IP6
205 case AF_INET6: sockaddr_inet6_info(&sau->ip6, cp, blen);
206 break;
207 #endif
208 default:
209 n = xio_snprintf(cp, blen, "AF=%d ", sa->sa_family);
210 if (n < 0 || n >= blen) {
211 Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
212 *buff = '\0';
213 return buff;
214 }
215 cp += n, blen -= n;
216 n = xio_snprintf(cp, blen,
217 "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
218 ((unsigned char *)sau->soa.sa_data)[0],
219 ((unsigned char *)sau->soa.sa_data)[1],
220 ((unsigned char *)sau->soa.sa_data)[2],
221 ((unsigned char *)sau->soa.sa_data)[3],
222 ((unsigned char *)sau->soa.sa_data)[4],
223 ((unsigned char *)sau->soa.sa_data)[5],
224 ((unsigned char *)sau->soa.sa_data)[6],
225 ((unsigned char *)sau->soa.sa_data)[7],
226 ((unsigned char *)sau->soa.sa_data)[8],
227 ((unsigned char *)sau->soa.sa_data)[9],
228 ((unsigned char *)sau->soa.sa_data)[10],
229 ((unsigned char *)sau->soa.sa_data)[11],
230 ((unsigned char *)sau->soa.sa_data)[12],
231 ((unsigned char *)sau->soa.sa_data)[13]);
232 if (n < 0 || n >= blen) {
233 Warn("sockaddr_info(): buffer too short");
234 *buff = '\0';
235 return buff;
236 }
237 }
238 return lbuff;
239 }
240 #endif /* _WITH_SOCKET */
241  
242  
243 #if WITH_UNIX
244 char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *buff, size_t blen) {
245 char ubuff[5*UNIX_PATH_MAX+3];
246 char *nextc;
247  
248 #if WITH_ABSTRACT_UNIXSOCKET
249 if (salen > XIOUNIXSOCKOVERHEAD &&
250 sa->sun_path[0] == '\0') {
251 nextc =
252 sanitize_string(sa->sun_path, salen-XIOUNIXSOCKOVERHEAD,
253 ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
254 } else
255 #endif /* WITH_ABSTRACT_UNIXSOCKET */
256 {
257 if (salen <= XIOUNIXSOCKOVERHEAD) {
258 nextc = sanitize_string ("<anon>", MIN(UNIX_PATH_MAX, strlen("<anon>")),
259 ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
260 } else {
261 nextc = sanitize_string(sa->sun_path,
262 MIN(UNIX_PATH_MAX, strlen(sa->sun_path)),
263 ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
264 }
265 }
266 *nextc = '\0';
267 buff[0] = '\0'; strncat(buff, ubuff, blen-1);
268 return buff;
269 }
270 #endif /* WITH_UNIX */
271  
272 #if WITH_IP4
273 /* addr in host byte order! */
274 char *inet4addr_info(uint32_t addr, char *buff, size_t blen) {
275 if (xio_snprintf(buff, blen, "%u.%u.%u.%u",
276 (unsigned int)(addr >> 24), (unsigned int)((addr >> 16) & 0xff),
277 (unsigned int)((addr >> 8) & 0xff), (unsigned int)(addr & 0xff)) >= blen) {
278 Warn("inet4addr_info(): buffer too short");
279 buff[blen-1] = '\0';
280 }
281 return buff;
282 }
283 #endif /* WITH_IP4 */
284  
285 #if WITH_IP4
286 char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen) {
287 if (xio_snprintf(buff, blen, "%u.%u.%u.%u:%hu",
288 ((unsigned char *)&sa->sin_addr.s_addr)[0],
289 ((unsigned char *)&sa->sin_addr.s_addr)[1],
290 ((unsigned char *)&sa->sin_addr.s_addr)[2],
291 ((unsigned char *)&sa->sin_addr.s_addr)[3],
292 htons(sa->sin_port)) >= blen) {
293 Warn("sockaddr_inet4_info(): buffer too short");
294 buff[blen-1] = '\0';
295 }
296 return buff;
297 }
298 #endif /* WITH_IP4 */
299  
300 #if !HAVE_INET_NTOP
301 /* http://www.opengroup.org/onlinepubs/000095399/functions/inet_ntop.html */
302 const char *inet_ntop(int pf, const void *binaddr,
303 char *addrtext, socklen_t textlen) {
304 size_t retlen;
305 switch (pf) {
306 case PF_INET:
307 if ((retlen =
308 xio_snprintf(addrtext, textlen, "%u.%u.%u.%u",
309 ((unsigned char *)binaddr)[0],
310 ((unsigned char *)binaddr)[1],
311 ((unsigned char *)binaddr)[2],
312 ((unsigned char *)binaddr)[3]))
313 >= textlen) {
314 errno = ENOSPC; return NULL; /* errno is valid */
315 }
316 break;
317 #if WITH_IP6
318 case PF_INET6:
319 if ((retlen =
320 xio_snprintf(addrtext, textlen, "%x:%x:%x:%x:%x:%x:%x:%x",
321 ntohs(((uint16_t *)binaddr)[0]),
322 ntohs(((uint16_t *)binaddr)[1]),
323 ntohs(((uint16_t *)binaddr)[2]),
324 ntohs(((uint16_t *)binaddr)[3]),
325 ntohs(((uint16_t *)binaddr)[4]),
326 ntohs(((uint16_t *)binaddr)[5]),
327 ntohs(((uint16_t *)binaddr)[6]),
328 ntohs(((uint16_t *)binaddr)[7])
329 ))
330 >= 0 textlen) {
331 errno = ENOSPC; return NULL; /* errno is valid */
332 }
333 break;
334 #endif /* WITH_IP6 */
335 default:
336 errno = EAFNOSUPPORT;
337 return NULL;
338 }
339 addrtext[retlen] = '\0';
340 return addrtext;
341 }
342 #endif /* !HAVE_INET_NTOP */
343  
344 #if WITH_IP6
345 /* convert the IP6 socket address to human readable form. buff should be at
346 least 50 chars long. output includes the port number */
347 char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen) {
348 if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu",
349 #if HAVE_IP6_SOCKADDR==0
350 (sa->sin6_addr.s6_addr[0]<<8)+
351 sa->sin6_addr.s6_addr[1],
352 (sa->sin6_addr.s6_addr[2]<<8)+
353 sa->sin6_addr.s6_addr[3],
354 (sa->sin6_addr.s6_addr[4]<<8)+
355 sa->sin6_addr.s6_addr[5],
356 (sa->sin6_addr.s6_addr[6]<<8)+
357 sa->sin6_addr.s6_addr[7],
358 (sa->sin6_addr.s6_addr[8]<<8)+
359 sa->sin6_addr.s6_addr[9],
360 (sa->sin6_addr.s6_addr[10]<<8)+
361 sa->sin6_addr.s6_addr[11],
362 (sa->sin6_addr.s6_addr[12]<<8)+
363 sa->sin6_addr.s6_addr[13],
364 (sa->sin6_addr.s6_addr[14]<<8)+
365 sa->sin6_addr.s6_addr[15],
366 #elif HAVE_IP6_SOCKADDR==1
367 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[0]),
368 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[1]),
369 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[2]),
370 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[3]),
371 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[4]),
372 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[5]),
373 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[6]),
374 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[7]),
375 #elif HAVE_IP6_SOCKADDR==2
376 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[0]),
377 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[1]),
378 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[2]),
379 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[3]),
380 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[4]),
381 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[5]),
382 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[6]),
383 ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[7]),
384 #elif HAVE_IP6_SOCKADDR==3
385 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[0]),
386 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[1]),
387 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[2]),
388 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[3]),
389 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[4]),
390 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[5]),
391 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[6]),
392 ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[7]),
393 #elif HAVE_IP6_SOCKADDR==4
394 (sa->sin6_addr._S6_un._S6_u8[0]<<8)|(sa->sin6_addr._S6_un._S6_u8[1]&0xff),
395 (sa->sin6_addr._S6_un._S6_u8[2]<<8)|(sa->sin6_addr._S6_un._S6_u8[3]&0xff),
396 (sa->sin6_addr._S6_un._S6_u8[4]<<8)|(sa->sin6_addr._S6_un._S6_u8[5]&0xff),
397 (sa->sin6_addr._S6_un._S6_u8[6]<<8)|(sa->sin6_addr._S6_un._S6_u8[7]&0xff),
398 (sa->sin6_addr._S6_un._S6_u8[8]<<8)|(sa->sin6_addr._S6_un._S6_u8[9]&0xff),
399 (sa->sin6_addr._S6_un._S6_u8[10]<<8)|(sa->sin6_addr._S6_un._S6_u8[11]&0xff),
400 (sa->sin6_addr._S6_un._S6_u8[12]<<8)|(sa->sin6_addr._S6_un._S6_u8[13]&0xff),
401 (sa->sin6_addr._S6_un._S6_u8[14]<<8)|(sa->sin6_addr._S6_un._S6_u8[15]&0xff),
402 #elif HAVE_IP6_SOCKADDR==5
403 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[0]),
404 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[1]),
405 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[2]),
406 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[3]),
407 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[4]),
408 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[5]),
409 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[6]),
410 ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[7]),
411 #endif
412 ntohs(sa->sin6_port)) >= blen) {
413 Warn("sockaddr_inet6_info(): buffer too short");
414 }
415 return buff;
416 }
417 #endif /* WITH_IP6 */
418  
419 #if HAVE_GETGROUPLIST || (defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT))
420 /* fills the list with the supplementary group ids of user.
421 caller passes size of list in ngroups, function returns number of groups in
422 ngroups.
423 function returns 0 if 0 or more groups were found, or 1 if the list is too
424 short. */
425 int getusergroups(const char *user, gid_t *list, int *ngroups) {
426 #if HAVE_GETGROUPLIST
427 /* we prefer getgrouplist because it may be much faster with many groups, but it is not standard */
428 gid_t grp, twogrps[2];
429 int two = 2;
430 /* getgrouplist requires to pass an extra group id, typically the users primary group, that is then added to the supplementary group list. We don't want such an additional group in the result, but there is not "unspecified" gid value available. Thus we try to find an abitrary supplementary group id that we then pass in a second call to getgrouplist. */
431 grp = 0;
432 Getgrouplist(user, grp, twogrps, &two);
433 if (two == 1) {
434 /* either user has just this supp group, or none; we try another id */
435 grp = 1; two = 2;
436 Getgrouplist(user, grp, twogrps, &two);
437 if (two == 1) {
438 /* user has no supp group */
439 *ngroups = 0;
440 return 0;
441 }
442 /* user has just the first tried group */
443 *ngroups = 1; list[0] = grp;
444 return 0;
445 }
446 /* find the first supp group that is not our grp, and use its id */
447 if (twogrps[0] == grp) {
448 grp = twogrps[1];
449 } else {
450 grp = twogrps[0];
451 }
452 if (Getgrouplist(user, grp, list, ngroups) < 0) {
453 return 1;
454 }
455 return 0;
456  
457 #elif defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
458 /* this is standard (POSIX) but may be slow */
459  
460 struct group *grp;
461 int i = 0;
462  
463 setgrent();
464 while (grp = getgrent()) {
465 char **gusr = grp->gr_mem;
466 while (*gusr) {
467 if (!strcmp(*gusr, user)) {
468 if (i == *ngroups)
469 return 1;
470 list[i++] = grp->gr_gid;
471 break;
472 }
473 ++gusr;
474 }
475 }
476 endgrent();
477 *ngroups = i;
478 return 0;
479 #endif /* HAVE_SETGRENT... */
480 }
481 #endif
482  
483 #if !HAVE_HSTRERROR
484 const char *hstrerror(int err) {
485 static const char *h_messages[] = {
486 "success",
487 "authoritative answer not found",
488 "non-authoritative, host not found, or serverfail",
489 "Host name lookup failure", /* "non recoverable error" */
490 "valid name, no data record of requested type" };
491  
492 assert(HOST_NOT_FOUND==1);
493 assert(TRY_AGAIN==2);
494 assert(NO_RECOVERY==3);
495 assert(NO_DATA==4);
496 if ((err < 0) || err > sizeof(h_messages)/sizeof(const char *)) {
497 return "";
498 }
499 return h_messages[err];
500 }
501 #endif /* !HAVE_HSTRERROR */
502  
503  
504 /* this function behaves like poll(). It tries to do so even when the poll()
505 system call is not available. */
506 /* note: glibc 5.4 does not know nfds_t */
507 int xiopoll(struct pollfd fds[], unsigned long nfds, struct timeval *timeout) {
508 int i, n = 0;
509 int result = 0;
510  
511 while (true) { /* should be if (), but we want to break */
512 fd_set readfds;
513 fd_set writefds;
514 fd_set exceptfds;
515  
516 FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
517 for (i = 0; i < nfds; ++i) {
518 fds[i].revents = 0;
519 if (fds[i].fd < 0) { continue; }
520 if (fds[i].fd > FD_SETSIZE) { break; /* use poll */ }
521 if (fds[i].events & POLLIN) {
522 FD_SET(fds[i].fd, &readfds); n = MAX(n, fds[i].fd); }
523 if (fds[i].events & POLLOUT) {
524 FD_SET(fds[i].fd, &writefds); n = MAX(n, fds[i].fd); }
525 }
526 if (i < nfds) { break; /* use poll */ }
527  
528 result = Select(n+1, &readfds, &writefds, &exceptfds, timeout);
529 if (result < 0) { return result; }
530 for (i = 0; i < nfds; ++i) {
531 if (fds[i].fd < 0) { continue; }
532 if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds)) {
533 fds[i].revents |= POLLIN; ++result;
534 }
535 if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds)) {
536 fds[i].revents |= POLLOUT; ++result;
537 }
538 }
539 return result;
540 }
541 #if HAVE_POLL
542 {
543 int ms = 0;
544 if (timeout == NULL) {
545 ms = -1;
546 } else {
547 ms = 1000*timeout->tv_sec + timeout->tv_usec/1000;
548 }
549 /*! timeout */
550 return Poll(fds, nfds, ms);
551 #else /* HAVE_POLL */
552 } else {
553 Error("poll() not available");
554 return -1;
555 #endif /* !HAVE_POLL */
556 }
557 }
558  
559  
560 #if _WITH_TCP || _WITH_UDP
561 /* returns port in network byte order;
562 ipproto==IPPROTO_UDP resolves as UDP service, every other value resolves as
563 TCP */
564 int parseport(const char *portname, int ipproto) {
565 struct servent *se;
566 char *extra;
567 int result;
568  
569 if (isdigit(portname[0]&0xff)) {
570 result = htons(strtoul(portname, &extra, 0));
571 if (*extra != '\0') {
572 Error3("parseport(\"%s\", %d): extra trailing data \"%s\"",
573 portname, ipproto, extra);
574 }
575 return result;
576 }
577  
578 if ((se = getservbyname(portname, ipproto==IPPROTO_UDP?"udp":"tcp")) == NULL) {
579 Error2("cannot resolve service \"%s/%d\"", portname, ipproto);
580 return 0;
581 }
582  
583 return se->s_port;
584 }
585 #endif /* _WITH_TCP || _WITH_UDP */
586  
587  
588 #if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
589 /* check the systems interfaces for ifname and return its index
590 or -1 if no interface with this name was found
591 The system calls require an arbitrary socket; the calling program may
592 provide one in anysock to avoid creation of a dummy socket. anysock must be
593 <0 if it does not specify a socket fd.
594 */
595 int ifindexbyname(const char *ifname, int anysock) {
596 /* Linux: man 7 netdevice */
597 /* FreeBSD: man 4 networking */
598 /* Solaris: man 7 if_tcp */
599  
600 #if defined(HAVE_STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX)
601 /* currently we support Linux, FreeBSD; not Solaris */
602  
603 #define IFBUFSIZ 32*sizeof(struct ifreq) /*1024*/
604 int s;
605 struct ifreq ifr;
606  
607 if (ifname[0] == '\0') {
608 return -1;
609 }
610 if (anysock >= 0) {
611 s = anysock;
612 } else if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
613 Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
614 return -1;
615 }
616  
617 strncpy(ifr.ifr_name, ifname, IFNAMSIZ); /* ok */
618 if (Ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
619 Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}): %s",
620 s, ifr.ifr_name, strerror(errno));
621 Close(s);
622 return -1;
623 }
624 Close(s);
625 #if HAVE_STRUCT_IFREQ_IFR_INDEX
626 Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
627 s, ifname, ifr.ifr_index);
628 return ifr.ifr_index;
629 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
630 Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
631 s, ifname, ifr.ifr_ifindex);
632 return ifr.ifr_ifindex;
633 #endif /* HAVE_STRUCT_IFREQ_IFR_IFINDEX */
634  
635 #else /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */
636 return -1;
637 #endif /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */
638 }
639 #endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
640  
641  
642 #if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
643 /* like ifindexbyname(), but also allows the index number as input - in this
644 case it does not lookup the index.
645 writes the resulting index to *ifindex and returns 0,
646 or returns -1 on error */
647 int ifindex(const char *ifname, unsigned int *ifindex, int anysock) {
648 char *endptr;
649 long int val;
650  
651 if (ifname[0] == '\0') {
652 return -1;
653 }
654 val = strtol(ifname, &endptr, 0);
655 if (endptr[0] == '\0') {
656 *ifindex = val;
657 return 0;
658 }
659  
660 if ((val = ifindexbyname(ifname, anysock)) < 0) {
661 return -1;
662 }
663 *ifindex = val;
664 return 0;
665 }
666 #endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
667  
668  
669 int _xiosetenv(const char *envname, const char *value, int overwrite, const char *sep) {
670 char *oldval;
671 char *newval;
672 if (overwrite >= 2 && (oldval = getenv(envname)) != NULL) {
673 size_t newlen = strlen(oldval)+strlen(sep)+strlen(value)+1;
674 if ((newval = Malloc(newlen+1)) == NULL) {
675 return -1;
676 }
677 snprintf(newval, newlen+1, "%s%s%s", oldval, sep, value);
678 } else {
679 newval = (char *)value;
680 }
681 if (Setenv(envname, newval, overwrite) < 0) {
682 Warn3("setenv(\"%s\", \"%s\", 1): %s",
683 envname, value, strerror(errno));
684 #if HAVE_UNSETENV
685 Unsetenv(envname); /* dont want to have a wrong value */
686 #endif
687 return -1;
688 }
689 return 0;
690 }
691  
692 /* constructs an environment variable whose name is built from socats uppercase
693 program name, and underscore and varname;
694 if the variable of this name already exists arg overwrite determines:
695 0: keep old value
696 1: overwrite with new value
697 2: append to old value, separated by *sep
698 returns 0 on success or <0 if an error occurred. */
699 int xiosetenv(const char *varname, const char *value, int overwrite, const char *sep) {
700 # define XIO_ENVNAMELEN 256
701 const char *progname;
702 char envname[XIO_ENVNAMELEN];
703 size_t i, l;
704  
705 progname = diag_get_string('p');
706 envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
707 l = strlen(envname);
708 for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
709 strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
710 l += 1;
711 strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
712 return _xiosetenv(envname, value, overwrite, sep);
713 # undef XIO_ENVNAMELEN
714 }
715  
716 int xiosetenv2(const char *varname, const char *varname2, const char *value,
717 int overwrite, const char *sep) {
718 # define XIO_ENVNAMELEN 256
719 const char *progname;
720 char envname[XIO_ENVNAMELEN];
721 size_t i, l;
722  
723 progname = diag_get_string('p');
724 envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
725 l = strlen(progname);
726 strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
727 l += 1;
728 strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
729 l += strlen(envname+l);
730 strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
731 l += 1;
732 strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
733 l += strlen(envname+l);
734 for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
735 return _xiosetenv(envname, value, overwrite, sep);
736 # undef XIO_ENVNAMELEN
737 }
738  
739 int xiosetenv3(const char *varname, const char *varname2, const char *varname3,
740 const char *value,
741 int overwrite, const char *sep) {
742 # define XIO_ENVNAMELEN 256
743 const char *progname;
744 char envname[XIO_ENVNAMELEN];
745 size_t i, l;
746  
747 progname = diag_get_string('p');
748 envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
749 l = strlen(progname);
750 strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
751 l += 1;
752 strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
753 l += strlen(envname+l);
754 strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
755 l += 1;
756 strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
757 l += strlen(envname+l);
758 strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
759 l += 1;
760 strncat(envname+l, varname3, XIO_ENVNAMELEN-l-1);
761 l += strlen(envname+l);
762 for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
763 return _xiosetenv(envname, value, overwrite, sep);
764 # undef XIO_ENVNAMELEN
765 }
766  
767  
768 /* like xiosetenv(), but uses an unsigned long value */
769 int xiosetenvulong(const char *varname, unsigned long value, int overwrite) {
770 # define XIO_LONGLEN 21 /* should suffice for 64bit longs with \0 */
771 char envbuff[XIO_LONGLEN];
772  
773 snprintf(envbuff, XIO_LONGLEN, "%lu", value);
774 return xiosetenv(varname, envbuff, overwrite, NULL);
775 # undef XIO_LONGLEN
776 }
777  
778 /* like xiosetenv(), but uses an unsigned short value */
779 int xiosetenvushort(const char *varname, unsigned short value, int overwrite) {
780 # define XIO_SHORTLEN 11 /* should suffice for 32bit shorts with \0 */
781 char envbuff[XIO_SHORTLEN];
782  
783 snprintf(envbuff, XIO_SHORTLEN, "%hu", value);
784 return xiosetenv(varname, envbuff, overwrite, NULL);
785 # undef XIO_SHORTLEN
786 }