📄 sockunion.c
字号:
/* Socket union related function. * Copyright (c) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */#include <zebra.h>#include "prefix.h"#include "vty.h"#include "sockunion.h"#include "memory.h"#include "str.h"#include "log.h"#ifndef HAVE_INET_ATONintinet_aton (const char *cp, struct in_addr *inaddr){ int dots = 0; register u_long addr = 0; register u_long val = 0, base = 10; do { register char c = *cp; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': val = (val * base) + (c - '0'); break; case '.': if (++dots > 3) return 0; case '\0': if (val > 255) return 0; addr = addr << 8 | val; val = 0; break; default: return 0; } } while (*cp++) ; if (dots < 3) addr <<= 8 * (3 - dots); if (inaddr) inaddr->s_addr = htonl (addr); return 1;}#endif /* ! HAVE_INET_ATON */#ifndef HAVE_INET_PTONintinet_pton (int family, const char *strptr, void *addrptr){ if (family == AF_INET) { struct in_addr in_val; if (inet_aton (strptr, &in_val)) { memcpy (addrptr, &in_val, sizeof (struct in_addr)); return 1; } return 0; } errno = EAFNOSUPPORT; return -1;}#endif /* ! HAVE_INET_PTON */#ifndef HAVE_INET_NTOPconst char *inet_ntop (int family, const void *addrptr, char *strptr, size_t len){ unsigned char *p = (unsigned char *) addrptr; if (family == AF_INET) { char temp[INET_ADDRSTRLEN]; snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); if (strlen(temp) >= len) { errno = ENOSPC; return NULL; } strcpy(strptr, temp); return strptr; } errno = EAFNOSUPPORT; return NULL;}#endif /* ! HAVE_INET_NTOP */const char *inet_sutop (union sockunion *su, char *str){ switch (su->sa.sa_family) { case AF_INET: inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN); break;#ifdef HAVE_IPV6 case AF_INET6: inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN); break;#endif /* HAVE_IPV6 */ } return str;}intstr2sockunion (char *str, union sockunion *su){ int ret; memset (su, 0, sizeof (union sockunion)); ret = inet_pton (AF_INET, str, &su->sin.sin_addr); if (ret > 0) /* Valid IPv4 address format. */ { su->sin.sin_family = AF_INET;#ifdef HAVE_SIN_LEN su->sin.sin_len = sizeof(struct sockaddr_in);#endif /* HAVE_SIN_LEN */ return 0; }#ifdef HAVE_IPV6 ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); if (ret > 0) /* Valid IPv6 address format. */ { su->sin6.sin6_family = AF_INET6;#ifdef SIN6_LEN su->sin6.sin6_len = sizeof(struct sockaddr_in6);#endif /* SIN6_LEN */ return 0; }#endif /* HAVE_IPV6 */ return -1;}const char *sockunion2str (union sockunion *su, char *buf, size_t len){ if (su->sa.sa_family == AF_INET) return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);#ifdef HAVE_IPV6 else if (su->sa.sa_family == AF_INET6) return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);#endif /* HAVE_IPV6 */ return NULL;}union sockunion *sockunion_str2su (char *str){ int ret; union sockunion *su; su = XMALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); memset (su, 0, sizeof (union sockunion)); ret = inet_pton (AF_INET, str, &su->sin.sin_addr); if (ret > 0) /* Valid IPv4 address format. */ { su->sin.sin_family = AF_INET;#ifdef HAVE_SIN_LEN su->sin.sin_len = sizeof(struct sockaddr_in);#endif /* HAVE_SIN_LEN */ return su; }#ifdef HAVE_IPV6 ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); if (ret > 0) /* Valid IPv6 address format. */ { su->sin6.sin6_family = AF_INET6;#ifdef SIN6_LEN su->sin6.sin6_len = sizeof(struct sockaddr_in6);#endif /* SIN6_LEN */ return su; }#endif /* HAVE_IPV6 */ XFREE (MTYPE_SOCKUNION, su); return NULL;}char *sockunion_su2str (union sockunion *su){ char str[INET6_ADDRSTRLEN]; switch (su->sa.sa_family) { case AF_INET: inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str)); break;#ifdef HAVE_IPV6 case AF_INET6: inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str)); break;#endif /* HAVE_IPV6 */ } return strdup (str);}/* Return socket of sockunion. */intsockunion_socket (union sockunion *su){ int sock; sock = socket (su->sa.sa_family, SOCK_STREAM, 0); if (sock < 0) { zlog (NULL, LOG_WARNING, "Can't make socket : %s", strerror (errno)); return -1; } return sock;}/* Return accepted new socket file descriptor. */intsockunion_accept (int sock, union sockunion *su){ socklen_t len; int client_sock; len = sizeof (union sockunion); client_sock = accept (sock, (struct sockaddr *) su, &len); /* Convert IPv4 compatible IPv6 address to IPv4 address. */#ifdef HAVE_IPV6 if (su->sa.sa_family == AF_INET6) { if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) { struct sockaddr_in sin; memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); memcpy (su, &sin, sizeof (struct sockaddr_in)); } }#endif /* HAVE_IPV6 */ return client_sock;}/* Return sizeof union sockunion. */intsockunion_sizeof (union sockunion *su){ int ret; ret = 0; switch (su->sa.sa_family) { case AF_INET: ret = sizeof (struct sockaddr_in); break;#ifdef HAVE_IPV6 case AF_INET6: ret = sizeof (struct sockaddr_in6); break;#endif /* AF_INET6 */ } return ret;}/* return sockunion structure : this function should be revised. */char *sockunion_log (union sockunion *su){ static char buf[SU_ADDRSTRLEN]; switch (su->sa.sa_family) { case AF_INET: snprintf (buf, BUFSIZ, "%s", inet_ntoa (su->sin.sin_addr)); break;#ifdef HAVE_IPV6 case AF_INET6: snprintf (buf, BUFSIZ, "%s", inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, BUFSIZ)); break;#endif /* HAVE_IPV6 */ default: snprintf (buf, BUFSIZ, "af_unknown %d ", su->sa.sa_family); break; } return buf;}/* sockunion_connect returns -1 : error occured 0 : connect success 1 : connect is in progress */enum connect_resultsockunion_connect (int fd, union sockunion *peersu, unsigned short port, unsigned int ifindex){ int ret; int val; union sockunion su; memcpy (&su, peersu, sizeof (union sockunion)); switch (su.sa.sa_family) { case AF_INET: su.sin.sin_port = port; break;#ifdef HAVE_IPV6 case AF_INET6: su.sin6.sin6_port = port;#ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) {#ifdef HAVE_SIN6_SCOPE_ID /* su.sin6.sin6_scope_id = ifindex; */#endif /* HAVE_SIN6_SCOPE_ID */ SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); }#endif /* KAME */ break;#endif /* HAVE_IPV6 */ } /* Make socket non-block. */ val = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, val|O_NONBLOCK); /* Call connect function. */ ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su)); /* Immediate success */ if (ret == 0) { fcntl (fd, F_SETFL, val); return connect_success; } /* If connect is in progress then return 1 else it's real error. */ if (ret < 0) { if (errno != EINPROGRESS) { zlog_info ("can't connect to %s fd %d : %s", sockunion_log (&su), fd, strerror (errno)); return connect_error; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -