/**************************************************************************** * apps/netutils/netlib/netlib_checkhttpconnectivity.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_LIBC_NETDB # include #endif #include #include /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: eai_to_errno * * Description: * Convert EAI_* error code to errno value for unified error handling. * * Parameters: * eai_error The EAI_* error code from getaddrinfo(). * * Return: * Corresponding errno value. * ****************************************************************************/ #ifdef CONFIG_LIBC_NETDB static int eai_to_errno(int eai_error) { switch (eai_error) { case EAI_AGAIN: return EAGAIN; /* Temporary failure, try again */ case EAI_BADFLAGS: return EINVAL; /* Invalid flags */ case EAI_FAIL: return EHOSTUNREACH; /* Non-recoverable failure */ case EAI_FAMILY: return EAFNOSUPPORT; /* Address family not supported */ case EAI_MEMORY: return ENOMEM; /* Memory allocation failure */ case EAI_NONAME: return EHOSTUNREACH; /* Host name not found */ case EAI_SERVICE: return EINVAL; /* Service not recognized */ case EAI_SOCKTYPE: return EINVAL; /* Socket type not supported */ case EAI_SYSTEM: return errno; /* System error, use errno */ case EAI_OVERFLOW: return EOVERFLOW; /* Buffer overflow */ default: return EINVAL; /* Unknown error, use invalid argument */ } } #endif /**************************************************************************** * Name: httpget_gethostip * * Description: * Check the http status code * * Parameters: * hostname The host name to use in the nslookup. * dest The location to return the IPv4 address. * * Return: * 0 on success; a negative errno value on failure. * ****************************************************************************/ static int httpget_gethostip(FAR const char *hostname, FAR struct in_addr *dest) { #ifdef CONFIG_LIBC_NETDB /* Netdb DNS client support is enabled */ int ret; FAR struct addrinfo hint; FAR struct addrinfo *info; FAR struct sockaddr_in *addr; memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_INET; ret = getaddrinfo(hostname, NULL, &hint, &info); if (ret != OK) { return -eai_to_errno(ret); } addr = (FAR struct sockaddr_in *)info->ai_addr; memcpy(dest, &addr->sin_addr, sizeof(struct in_addr)); freeaddrinfo(info); return OK; #else /* CONFIG_LIBC_NETDB */ /* No host name support */ /* Convert strings to numeric IPv4 address */ int ret = inet_pton(AF_INET, hostname, dest); /* The inet_pton() function returns 1 if the conversion succeeds. It will * return 0 if the input is not a valid IPv4 dotted-decimal string or -1 * with errno set to EAFNOSUPPORT if the address family argument is * unsupported. */ if (ret != 1) { /* ret == 0: invalid IP address string, set errno to EINVAL * ret == -1: system error, errno is already set to EAFNOSUPPORT */ if (ret == 0) { set_errno(EINVAL); } return -errno; } return OK; #endif /* CONFIG_LIBC_NETDB */ } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: netlib_check_httpconnectivity * * Description: * Check the http status code * * Parameters: * host The remote host to check * getmsg The http GET message * port The port of remote host * expect_code The except http code of http code * * Return: * 0 on success; a nagtive on failure. * ****************************************************************************/ int netlib_check_httpconnectivity(FAR const char *host, FAR const char *getmsg, int port, int expect_code) { int sock; int ret; int status_code = -1; struct sockaddr_in server_addr; char buf[256]; ret = httpget_gethostip(host, &server_addr.sin_addr); if (ret < 0) { nerr("Failed to get host ip"); return ret; } sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { nerr("Failed to create socket"); return -errno; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); ret = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (ret < 0) { nerr("Connection failed: %s", strerror(errno)); goto exit_with_socket; } snprintf(buf, sizeof(buf), "GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", getmsg, host); ret = send(sock, buf, strlen(buf), 0); if (ret < 0) { nerr("send failed: %s", strerror(errno)); goto exit_with_socket; } if ((ret = recv(sock, buf, sizeof(buf), 0)) < 0) { nerr("recv failed: %s", strerror(errno)); goto exit_with_socket; } /* get the http code, and check with except code */ if (sscanf(buf, "HTTP/1.1 %d", &status_code) == 1 && status_code == expect_code) { ninfo("HTTP connectivity is ok"); ret = OK; } else { nerr("HTTP connectivity is not ok status code: %d\n", status_code); ret = -status_code; } exit_with_socket: close(sock); return ret; }