/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2025 Martin Preuss, all rights reserved. * * The license for this file can be found in the file COPYING which you * should have received along with this file. ****************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include "./tcp_object.h" #include #include #include #include #include #include #include #include /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static int _socketSetBlocking(int sk, int fl); static int _translateHError(int herr); static int _setHostAddr(struct in_addr *inetAddr, const char *sAddr); static int _setHostName(struct in_addr *inetAddr, const char *sAddr); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ int AQH_TcpObject_CreateConnectedSocket(const char *addr, int port) { int sk; struct sockaddr_in inetAddr; int rv; memset(&inetAddr, 0, sizeof(inetAddr)); inetAddr.sin_family=AF_INET; rv=_setHostAddr(&inetAddr.sin_addr, addr); /* try tuple */ if (rv<0) { rv=_setHostName(&inetAddr.sin_addr, addr); /* lookup name */ if (rv<0) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); return rv; } } inetAddr.sin_port=htons(port); sk=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sk<0) { DBG_INFO(AQH_LOGDOMAIN, "socket(): %s", strerror(errno)); return GWEN_ERROR_IO; } rv=connect(sk, (struct sockaddr*) &inetAddr, sizeof(inetAddr)); if (rv<0) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); close(sk); return rv; } rv=_socketSetBlocking(sk, 0); if (rv<0) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); close(sk); return rv; } return sk; } int _setHostAddr(struct in_addr *inetAddr, const char *sAddr) { inetAddr->s_addr=0; if (!inet_aton(sAddr, inetAddr)) { DBG_ERROR(AQH_LOGDOMAIN, "Invalid address \"%s\"", sAddr); return GWEN_ERROR_INVALID; } return 0; } int _setHostName(struct in_addr *inetAddr, const char *sAddr) { struct hostent *he; he=gethostbyname(sAddr); if (!he) { DBG_ERROR(AQH_LOGDOMAIN, "gethostbyname(\"%s\"): %s", sAddr, hstrerror(h_errno)); return _translateHError(h_errno); } /* name resolved, store address */ memcpy(inetAddr, he->h_addr_list[0], sizeof(struct in_addr)); return 0; } int _socketSetBlocking(int sk, int fl) { int prevFlags; int newFlags; /* get current socket flags */ prevFlags=fcntl(sk, F_GETFL); if (prevFlags==-1) { DBG_INFO(AQH_LOGDOMAIN, "fcntl(): %s", strerror(errno)); return GWEN_ERROR_IO; } /* set nonblocking/blocking */ if (fl) newFlags=prevFlags&(~O_NONBLOCK); else newFlags=prevFlags|O_NONBLOCK; if (-1==fcntl(sk, F_SETFL, newFlags)) { DBG_INFO(AQH_LOGDOMAIN, "fcntl(): %s", strerror(errno)); return GWEN_ERROR_IO; } prevFlags=fcntl(sk, F_GETFL); if (prevFlags!=newFlags) { DBG_ERROR(AQH_LOGDOMAIN, "fcntl() did not set flags correctly (%08x!=%08x)", prevFlags, newFlags); return GWEN_ERROR_IO; } return 0; } int _translateHError(int herr) { int rv; switch (herr) { case HOST_NOT_FOUND: rv=GWEN_ERROR_HOST_NOT_FOUND; break; #ifdef NO_ADDRESS case NO_ADDRESS: rv=GWEN_ERROR_NO_ADDRESS; break; #endif case NO_RECOVERY: rv=GWEN_ERROR_NO_RECOVERY; break; case TRY_AGAIN: rv=GWEN_ERROR_TRY_AGAIN; break; default: rv=GWEN_ERROR_UNKNOWN_DNS_ERROR; break; } /* switch */ return rv; }