/* ** Copyright (c) 2001 The OSSP Project ** Copyright (c) 2001 Cable & Wireless Deutschland ** ** This file is part of OSSP lmtp2nntp, an LMTP speaking local ** mailer which forwards mails as Usenet news articles via NNTP. ** It can be found at http://www.ossp.org/pkg/lmtp2nntp/. ** ** This program 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.0 of the License, or (at your option) any later version. ** ** This program 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 this file; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ** USA, or contact the OSSP project . ** ** sa.c: Socket Address library */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(HAVE_DMALLOC_H) && defined(DMALLOC) #include "dmalloc.h" #endif #include "sa.h" #if !defined(AF_LOCAL) && defined(AF_UNIX) #define AF_LOCAL AF_UNIX #endif #ifndef HAVE_INET_PTON #ifdef HAVE_INET_ATON static int inet_pton(int family, const char *strptr, void *addrptr) { struct in_addr in_val; if (family == AF_INET) { if (inet_aton(strptr, &in_val)) { memcpy(addrptr, &in_val, sizeof(struct in_addr)); return 1; } return 0; } errno = EAFNOSUPPORT; return -1; } #else #error "neither inet_pton nor inet_aton available" #endif #endif #ifndef NUL #define NUL '\0' #endif sa_t *sa_create(int sa_type, ...) { va_list ap; sa_t *rc; int nPort; socklen_t sl; struct sockaddr *sa; struct sockaddr_in sa4; #ifdef AF_INET6 struct sockaddr_in6 sa6; #endif struct sockaddr_un sau; struct hostent *he; struct servent *se; struct protoent *pe; int bNumeric; int i; char *cpPath; int nPath; char *cpProto; int nProto; char *cpHost; char *cpPort; va_start(ap, sa_type); sa = NULL; sl = 0; if (sa_type == SA_UNIX) { #if defined(AF_LOCAL) if ((cpPath = va_arg(ap, char *)) == NULL) return NULL; if ((nPath = strlen(cpPath)) >= (sizeof(sau.sun_path)-1)) return NULL; nProto = 0; memset(&sau, 0, sizeof(sau)); sau.sun_family = AF_LOCAL; memcpy(sau.sun_path, cpPath, nPath + 1); sa = (struct sockaddr *)&sau; sl = sizeof(sau); #else return NULL; #endif } else if (sa_type == SA_IP) { if ((cpProto = va_arg(ap, char *)) == NULL) return NULL; if ((cpHost = va_arg(ap, char *)) == NULL) return NULL; if ((cpPort = va_arg(ap, char *)) == NULL) return NULL; /* resolve protocol */ if ((pe = getprotobyname(cpProto)) == NULL) return NULL; nProto = pe->p_proto; /* resolve port */ bNumeric = 1; for (i = 0; cpPort[i] != NUL; i++) { if (!isdigit((int)cpPort[i])) { bNumeric = 0; break; } } if (bNumeric) nPort = atoi(cpPort); else { if ((se = getservbyname(cpPort, cpProto)) == NULL) return NULL; nPort = ntohs(se->s_port); } /* mandatory initialization */ memset(&sa4, 0, sizeof(sa4)); #ifdef AF_INET6 memset(&sa6, 0, sizeof(sa6)); #endif /* resolve host */ if (inet_pton(AF_INET, cpHost, &sa4.sin_addr.s_addr) == 1) { sa4.sin_family = AF_INET; sa4.sin_port = htons(nPort); sa = (struct sockaddr *)&sa4; sl = sizeof(sa4); } #ifdef AF_INET6 else if (inet_pton(AF_INET6, cpHost, &sa6.sin6_addr.s6_addr) == 1) { sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(nPort); sa = (struct sockaddr *)&sa6; sl = sizeof(sa6); } #endif else if ((he = gethostbyname(cpHost)) != NULL) { if (he->h_addrtype == AF_INET) { sa4.sin_family = AF_INET; sa4.sin_port = htons(nPort); memcpy(&sa4.sin_addr.s_addr, he->h_addr_list[0], sizeof(sa4.sin_addr.s_addr)); sa = (struct sockaddr *)&sa4; sl = sizeof(sa4); } #ifdef AF_INET6 else if (he->h_addrtype == AF_INET6) { sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(nPort); memcpy(&sa6.sin6_addr.s6_addr, he->h_addr_list[0], sizeof(sa6.sin6_addr.s6_addr)); sa = (struct sockaddr *)&sa6; sl = sizeof(sa6); } #endif } } else return NULL; va_end(ap); if (sa == NULL) return NULL; if ((rc = (sa_t *)malloc(sizeof(sa_t))) == NULL) return NULL; if ((rc->sa_buf = (struct sockaddr *)malloc(sl)) == NULL) { free(rc); return NULL; } memcpy(rc->sa_buf, sa, sl); rc->sa_len = sl; rc->sa_proto = nProto; return rc; } void sa_destroy(sa_t *sa) { if (sa == NULL) return; if (sa->sa_buf != NULL) free(sa->sa_buf); free(sa); return; }