HTTP_C::Implement Context::MakeRequest (#4754)
* HTTP_C::Implement Context::MakeRequest * httplib: Add add_client_cert_ASN1 and set_verify * HTTP_C: Fix request methode strings case in MakeRequest * HTTP_C: clang-format and cleanups * HTTP_C: Add comment about async in BeginRequest and BeginRequestAsync * Update httplib to contain all the changes we need; adapt http_c and web_services to the changes in httplib; addressed minor review comments * Add android-ifaddrs
This commit is contained in:
		
							
								
								
									
										5
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -96,9 +96,14 @@ if (ENABLE_WEB_SERVICE)
 | 
			
		||||
    # lurlparser
 | 
			
		||||
    add_subdirectory(lurlparser EXCLUDE_FROM_ALL)
 | 
			
		||||
 | 
			
		||||
    if(ANDROID)
 | 
			
		||||
        add_subdirectory(android-ifaddrs)
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
    # httplib
 | 
			
		||||
    add_library(httplib INTERFACE)
 | 
			
		||||
    target_include_directories(httplib INTERFACE ./httplib)
 | 
			
		||||
    target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
 | 
			
		||||
 | 
			
		||||
    # cpp-jwt
 | 
			
		||||
    add_library(cpp-jwt INTERFACE)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								externals/android-ifaddrs/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								externals/android-ifaddrs/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
add_library(ifaddrs
 | 
			
		||||
    ifaddrs.c
 | 
			
		||||
    ifaddrs.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
create_target_directory_groups(ifaddrs)
 | 
			
		||||
 | 
			
		||||
target_include_directories(ifaddrs INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
 | 
			
		||||
							
								
								
									
										600
									
								
								externals/android-ifaddrs/ifaddrs.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										600
									
								
								externals/android-ifaddrs/ifaddrs.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,600 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright (c) 2013, Kenneth MacKay
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
are permitted provided that the following conditions are met:
 | 
			
		||||
 * Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
   list of conditions and the following disclaimer.
 | 
			
		||||
 * Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
   this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
   and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
			
		||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 | 
			
		||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "ifaddrs.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <net/if_arp.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <linux/netlink.h>
 | 
			
		||||
#include <linux/rtnetlink.h>
 | 
			
		||||
 | 
			
		||||
typedef struct NetlinkList
 | 
			
		||||
{
 | 
			
		||||
    struct NetlinkList *m_next;
 | 
			
		||||
    struct nlmsghdr *m_data;
 | 
			
		||||
    unsigned int m_size;
 | 
			
		||||
} NetlinkList;
 | 
			
		||||
 | 
			
		||||
static int netlink_socket(void)
 | 
			
		||||
{
 | 
			
		||||
    int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 | 
			
		||||
    if(l_socket < 0)
 | 
			
		||||
    {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    struct sockaddr_nl l_addr;
 | 
			
		||||
    memset(&l_addr, 0, sizeof(l_addr));
 | 
			
		||||
    l_addr.nl_family = AF_NETLINK;
 | 
			
		||||
    if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
 | 
			
		||||
    {
 | 
			
		||||
        close(l_socket);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return l_socket;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int netlink_send(int p_socket, int p_request)
 | 
			
		||||
{
 | 
			
		||||
    char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
 | 
			
		||||
    memset(l_buffer, 0, sizeof(l_buffer));
 | 
			
		||||
    struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer;
 | 
			
		||||
    struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
 | 
			
		||||
    
 | 
			
		||||
    l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
 | 
			
		||||
    l_hdr->nlmsg_type = p_request;
 | 
			
		||||
    l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
 | 
			
		||||
    l_hdr->nlmsg_pid = 0;
 | 
			
		||||
    l_hdr->nlmsg_seq = p_socket;
 | 
			
		||||
    l_msg->rtgen_family = AF_UNSPEC;
 | 
			
		||||
    
 | 
			
		||||
    struct sockaddr_nl l_addr;
 | 
			
		||||
    memset(&l_addr, 0, sizeof(l_addr));
 | 
			
		||||
    l_addr.nl_family = AF_NETLINK;
 | 
			
		||||
    return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
 | 
			
		||||
{
 | 
			
		||||
    struct msghdr l_msg;
 | 
			
		||||
    struct iovec l_iov = { p_buffer, p_len };
 | 
			
		||||
    struct sockaddr_nl l_addr;
 | 
			
		||||
    int l_result;
 | 
			
		||||
 | 
			
		||||
    for(;;)
 | 
			
		||||
    {
 | 
			
		||||
        l_msg.msg_name = (void *)&l_addr;
 | 
			
		||||
        l_msg.msg_namelen = sizeof(l_addr);
 | 
			
		||||
        l_msg.msg_iov = &l_iov;
 | 
			
		||||
        l_msg.msg_iovlen = 1;
 | 
			
		||||
        l_msg.msg_control = NULL;
 | 
			
		||||
        l_msg.msg_controllen = 0;
 | 
			
		||||
        l_msg.msg_flags = 0;
 | 
			
		||||
        int l_result = recvmsg(p_socket, &l_msg, 0);
 | 
			
		||||
        
 | 
			
		||||
        if(l_result < 0)
 | 
			
		||||
        {
 | 
			
		||||
            if(errno == EINTR)
 | 
			
		||||
            {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            return -2;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(l_msg.msg_flags & MSG_TRUNC)
 | 
			
		||||
        { // buffer was too small
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        return l_result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
 | 
			
		||||
{
 | 
			
		||||
    size_t l_size = 4096;
 | 
			
		||||
    void *l_buffer = NULL;
 | 
			
		||||
    
 | 
			
		||||
    for(;;)
 | 
			
		||||
    {
 | 
			
		||||
        free(l_buffer);
 | 
			
		||||
        l_buffer = malloc(l_size);
 | 
			
		||||
        
 | 
			
		||||
        int l_read = netlink_recv(p_socket, l_buffer, l_size);
 | 
			
		||||
        *p_size = l_read;
 | 
			
		||||
        if(l_read == -2)
 | 
			
		||||
        {
 | 
			
		||||
            free(l_buffer);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        if(l_read >= 0)
 | 
			
		||||
        {
 | 
			
		||||
            pid_t l_pid = getpid();
 | 
			
		||||
            struct nlmsghdr *l_hdr;
 | 
			
		||||
            for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
 | 
			
		||||
            {
 | 
			
		||||
                if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
 | 
			
		||||
                {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if(l_hdr->nlmsg_type == NLMSG_DONE)
 | 
			
		||||
                {
 | 
			
		||||
                    *p_done = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if(l_hdr->nlmsg_type == NLMSG_ERROR)
 | 
			
		||||
                {
 | 
			
		||||
                    free(l_buffer);
 | 
			
		||||
                    return NULL;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return l_buffer;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        l_size *= 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
 | 
			
		||||
{
 | 
			
		||||
    NetlinkList *l_item = malloc(sizeof(NetlinkList));
 | 
			
		||||
    l_item->m_next = NULL;
 | 
			
		||||
    l_item->m_data = p_data;
 | 
			
		||||
    l_item->m_size = p_size;
 | 
			
		||||
    return l_item;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void freeResultList(NetlinkList *p_list)
 | 
			
		||||
{
 | 
			
		||||
    NetlinkList *l_cur;
 | 
			
		||||
    while(p_list)
 | 
			
		||||
    {
 | 
			
		||||
        l_cur = p_list;
 | 
			
		||||
        p_list = p_list->m_next;
 | 
			
		||||
        free(l_cur->m_data);
 | 
			
		||||
        free(l_cur);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static NetlinkList *getResultList(int p_socket, int p_request)
 | 
			
		||||
{
 | 
			
		||||
    if(netlink_send(p_socket, p_request) < 0)
 | 
			
		||||
    {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    NetlinkList *l_list = NULL;
 | 
			
		||||
    NetlinkList *l_end = NULL;
 | 
			
		||||
    int l_size;
 | 
			
		||||
    int l_done = 0;
 | 
			
		||||
    while(!l_done)
 | 
			
		||||
    {
 | 
			
		||||
        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
 | 
			
		||||
        if(!l_hdr)
 | 
			
		||||
        { // error
 | 
			
		||||
            freeResultList(l_list);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        NetlinkList *l_item = newListItem(l_hdr, l_size);
 | 
			
		||||
        if(!l_list)
 | 
			
		||||
        {
 | 
			
		||||
            l_list = l_item;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            l_end->m_next = l_item;
 | 
			
		||||
        }
 | 
			
		||||
        l_end = l_item;
 | 
			
		||||
    }
 | 
			
		||||
    return l_list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t maxSize(size_t a, size_t b)
 | 
			
		||||
{
 | 
			
		||||
    return (a > b ? a : b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
 | 
			
		||||
{
 | 
			
		||||
    switch(p_family)
 | 
			
		||||
    {
 | 
			
		||||
        case AF_INET:
 | 
			
		||||
            return sizeof(struct sockaddr_in);
 | 
			
		||||
        case AF_INET6:
 | 
			
		||||
            return sizeof(struct sockaddr_in6);
 | 
			
		||||
        case AF_PACKET:
 | 
			
		||||
            return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
 | 
			
		||||
        default:
 | 
			
		||||
            return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
 | 
			
		||||
{
 | 
			
		||||
    switch(p_family)
 | 
			
		||||
    {
 | 
			
		||||
        case AF_INET:
 | 
			
		||||
            memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
 | 
			
		||||
            break;
 | 
			
		||||
        case AF_INET6:
 | 
			
		||||
            memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
 | 
			
		||||
            break;
 | 
			
		||||
        case AF_PACKET:
 | 
			
		||||
            memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
 | 
			
		||||
            ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            memcpy(p_dest->sa_data, p_data, p_size);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    p_dest->sa_family = p_family;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
 | 
			
		||||
{
 | 
			
		||||
    if(!*p_resultList)
 | 
			
		||||
    {
 | 
			
		||||
        *p_resultList = p_entry;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        struct ifaddrs *l_cur = *p_resultList;
 | 
			
		||||
        while(l_cur->ifa_next)
 | 
			
		||||
        {
 | 
			
		||||
            l_cur = l_cur->ifa_next;
 | 
			
		||||
        }
 | 
			
		||||
        l_cur->ifa_next = p_entry;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
 | 
			
		||||
{
 | 
			
		||||
    struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
 | 
			
		||||
 | 
			
		||||
    size_t l_nameSize = 0;
 | 
			
		||||
    size_t l_addrSize = 0;
 | 
			
		||||
    size_t l_dataSize = 0;
 | 
			
		||||
    
 | 
			
		||||
    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
 | 
			
		||||
    struct rtattr *l_rta;
 | 
			
		||||
    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
 | 
			
		||||
    {
 | 
			
		||||
        void *l_rtaData = RTA_DATA(l_rta);
 | 
			
		||||
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
 | 
			
		||||
        switch(l_rta->rta_type)
 | 
			
		||||
        {
 | 
			
		||||
            case IFLA_ADDRESS:
 | 
			
		||||
            case IFLA_BROADCAST:
 | 
			
		||||
                l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
 | 
			
		||||
                break;
 | 
			
		||||
            case IFLA_IFNAME:
 | 
			
		||||
                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
 | 
			
		||||
                break;
 | 
			
		||||
            case IFLA_STATS:
 | 
			
		||||
                l_dataSize += NLMSG_ALIGN(l_rtaSize);
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize);
 | 
			
		||||
    memset(l_entry, 0, sizeof(struct ifaddrs));
 | 
			
		||||
    l_entry->ifa_name = "";
 | 
			
		||||
    
 | 
			
		||||
    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
 | 
			
		||||
    char *l_addr = l_name + l_nameSize;
 | 
			
		||||
    char *l_data = l_addr + l_addrSize;
 | 
			
		||||
    
 | 
			
		||||
    l_entry->ifa_flags = l_info->ifi_flags;
 | 
			
		||||
    
 | 
			
		||||
    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
 | 
			
		||||
    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
 | 
			
		||||
    {
 | 
			
		||||
        void *l_rtaData = RTA_DATA(l_rta);
 | 
			
		||||
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
 | 
			
		||||
        switch(l_rta->rta_type)
 | 
			
		||||
        {
 | 
			
		||||
            case IFLA_ADDRESS:
 | 
			
		||||
            case IFLA_BROADCAST:
 | 
			
		||||
            {
 | 
			
		||||
                size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
 | 
			
		||||
                makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
 | 
			
		||||
                ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
 | 
			
		||||
                ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
 | 
			
		||||
                if(l_rta->rta_type == IFLA_ADDRESS)
 | 
			
		||||
                {
 | 
			
		||||
                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
 | 
			
		||||
                }
 | 
			
		||||
                l_addr += NLMSG_ALIGN(l_addrLen);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case IFLA_IFNAME:
 | 
			
		||||
                strncpy(l_name, l_rtaData, l_rtaDataSize);
 | 
			
		||||
                l_name[l_rtaDataSize] = '\0';
 | 
			
		||||
                l_entry->ifa_name = l_name;
 | 
			
		||||
                break;
 | 
			
		||||
            case IFLA_STATS:
 | 
			
		||||
                memcpy(l_data, l_rtaData, l_rtaDataSize);
 | 
			
		||||
                l_entry->ifa_data = l_data;
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    addToEnd(p_resultList, l_entry);
 | 
			
		||||
    p_links[l_info->ifi_index - 1] = l_entry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
 | 
			
		||||
{
 | 
			
		||||
    struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
 | 
			
		||||
 | 
			
		||||
    size_t l_nameSize = 0;
 | 
			
		||||
    size_t l_addrSize = 0;
 | 
			
		||||
    
 | 
			
		||||
    int l_addedNetmask = 0;
 | 
			
		||||
    
 | 
			
		||||
    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
 | 
			
		||||
    struct rtattr *l_rta;
 | 
			
		||||
    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
 | 
			
		||||
    {
 | 
			
		||||
        void *l_rtaData = RTA_DATA(l_rta);
 | 
			
		||||
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
 | 
			
		||||
        if(l_info->ifa_family == AF_PACKET)
 | 
			
		||||
        {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        switch(l_rta->rta_type)
 | 
			
		||||
        {
 | 
			
		||||
            case IFA_ADDRESS:
 | 
			
		||||
            case IFA_LOCAL:
 | 
			
		||||
                if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
 | 
			
		||||
                { // make room for netmask
 | 
			
		||||
                    l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
 | 
			
		||||
                    l_addedNetmask = 1;
 | 
			
		||||
                }
 | 
			
		||||
            case IFA_BROADCAST:
 | 
			
		||||
                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
 | 
			
		||||
                break;
 | 
			
		||||
            case IFA_LABEL:
 | 
			
		||||
                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
 | 
			
		||||
    memset(l_entry, 0, sizeof(struct ifaddrs));
 | 
			
		||||
    l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name;
 | 
			
		||||
    
 | 
			
		||||
    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
 | 
			
		||||
    char *l_addr = l_name + l_nameSize;
 | 
			
		||||
    
 | 
			
		||||
    l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags;
 | 
			
		||||
    
 | 
			
		||||
    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
 | 
			
		||||
    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
 | 
			
		||||
    {
 | 
			
		||||
        void *l_rtaData = RTA_DATA(l_rta);
 | 
			
		||||
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
 | 
			
		||||
        switch(l_rta->rta_type)
 | 
			
		||||
        {
 | 
			
		||||
            case IFA_ADDRESS:
 | 
			
		||||
            case IFA_BROADCAST:
 | 
			
		||||
            case IFA_LOCAL:
 | 
			
		||||
            {
 | 
			
		||||
                size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
 | 
			
		||||
                makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
 | 
			
		||||
                if(l_info->ifa_family == AF_INET6)
 | 
			
		||||
                {
 | 
			
		||||
                    if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
 | 
			
		||||
                    {
 | 
			
		||||
                        ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if(l_rta->rta_type == IFA_ADDRESS)
 | 
			
		||||
                { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
 | 
			
		||||
                    if(l_entry->ifa_addr)
 | 
			
		||||
                    {
 | 
			
		||||
                        l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        l_entry->ifa_addr = (struct sockaddr *)l_addr;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else if(l_rta->rta_type == IFA_LOCAL)
 | 
			
		||||
                {
 | 
			
		||||
                    if(l_entry->ifa_addr)
 | 
			
		||||
                    {
 | 
			
		||||
                        l_entry->ifa_dstaddr = l_entry->ifa_addr;
 | 
			
		||||
                    }
 | 
			
		||||
                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
 | 
			
		||||
                }
 | 
			
		||||
                l_addr += NLMSG_ALIGN(l_addrLen);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case IFA_LABEL:
 | 
			
		||||
                strncpy(l_name, l_rtaData, l_rtaDataSize);
 | 
			
		||||
                l_name[l_rtaDataSize] = '\0';
 | 
			
		||||
                l_entry->ifa_name = l_name;
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
 | 
			
		||||
    {
 | 
			
		||||
        unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
 | 
			
		||||
        unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
 | 
			
		||||
        char l_mask[16] = {0};
 | 
			
		||||
        unsigned i;
 | 
			
		||||
        for(i=0; i<(l_prefix/8); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            l_mask[i] = 0xff;
 | 
			
		||||
        }
 | 
			
		||||
        l_mask[i] = 0xff << (8 - (l_prefix % 8));
 | 
			
		||||
        
 | 
			
		||||
        makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
 | 
			
		||||
        l_entry->ifa_netmask = (struct sockaddr *)l_addr;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    addToEnd(p_resultList, l_entry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
 | 
			
		||||
{
 | 
			
		||||
    pid_t l_pid = getpid();
 | 
			
		||||
    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
 | 
			
		||||
    {
 | 
			
		||||
        unsigned int l_nlsize = p_netlinkList->m_size;
 | 
			
		||||
        struct nlmsghdr *l_hdr;
 | 
			
		||||
        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
 | 
			
		||||
        {
 | 
			
		||||
            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
 | 
			
		||||
            {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(l_hdr->nlmsg_type == NLMSG_DONE)
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(l_hdr->nlmsg_type == RTM_NEWLINK)
 | 
			
		||||
            {
 | 
			
		||||
                interpretLink(l_hdr, p_links, p_resultList);
 | 
			
		||||
            }
 | 
			
		||||
            else if(l_hdr->nlmsg_type == RTM_NEWADDR)
 | 
			
		||||
            {
 | 
			
		||||
                interpretAddr(l_hdr, p_links, p_resultList);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList)
 | 
			
		||||
{
 | 
			
		||||
    unsigned l_links = 0;
 | 
			
		||||
    pid_t l_pid = getpid();
 | 
			
		||||
    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
 | 
			
		||||
    {
 | 
			
		||||
        unsigned int l_nlsize = p_netlinkList->m_size;
 | 
			
		||||
        struct nlmsghdr *l_hdr;
 | 
			
		||||
        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
 | 
			
		||||
        {
 | 
			
		||||
            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
 | 
			
		||||
            {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(l_hdr->nlmsg_type == NLMSG_DONE)
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(l_hdr->nlmsg_type == RTM_NEWLINK)
 | 
			
		||||
            {
 | 
			
		||||
                ++l_links;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return l_links;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int getifaddrs(struct ifaddrs **ifap)
 | 
			
		||||
{
 | 
			
		||||
    if(!ifap)
 | 
			
		||||
    {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    *ifap = NULL;
 | 
			
		||||
    
 | 
			
		||||
    int l_socket = netlink_socket();
 | 
			
		||||
    if(l_socket < 0)
 | 
			
		||||
    {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
 | 
			
		||||
    if(!l_linkResults)
 | 
			
		||||
    {
 | 
			
		||||
        close(l_socket);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
 | 
			
		||||
    if(!l_addrResults)
 | 
			
		||||
    {
 | 
			
		||||
        close(l_socket);
 | 
			
		||||
        freeResultList(l_linkResults);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults);
 | 
			
		||||
    struct ifaddrs *l_links[l_numLinks];
 | 
			
		||||
    memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *));
 | 
			
		||||
    
 | 
			
		||||
    interpret(l_socket, l_linkResults, l_links, ifap);
 | 
			
		||||
    interpret(l_socket, l_addrResults, l_links, ifap);
 | 
			
		||||
 | 
			
		||||
    freeResultList(l_linkResults);
 | 
			
		||||
    freeResultList(l_addrResults);
 | 
			
		||||
    close(l_socket);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void freeifaddrs(struct ifaddrs *ifa)
 | 
			
		||||
{
 | 
			
		||||
    struct ifaddrs *l_cur;
 | 
			
		||||
    while(ifa)
 | 
			
		||||
    {
 | 
			
		||||
        l_cur = ifa;
 | 
			
		||||
        ifa = ifa->ifa_next;
 | 
			
		||||
        free(l_cur);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								externals/android-ifaddrs/ifaddrs.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								externals/android-ifaddrs/ifaddrs.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 1995, 1999
 | 
			
		||||
 *	Berkeley Software Design, Inc.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 *	BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef	_IFADDRS_H_
 | 
			
		||||
#define	_IFADDRS_H_
 | 
			
		||||
 | 
			
		||||
struct ifaddrs {
 | 
			
		||||
	struct ifaddrs  *ifa_next;
 | 
			
		||||
	char		*ifa_name;
 | 
			
		||||
	unsigned int	 ifa_flags;
 | 
			
		||||
	struct sockaddr	*ifa_addr;
 | 
			
		||||
	struct sockaddr	*ifa_netmask;
 | 
			
		||||
	struct sockaddr	*ifa_dstaddr;
 | 
			
		||||
	void		*ifa_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
 | 
			
		||||
 * to be included it must be included before this header file.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef	ifa_broadaddr
 | 
			
		||||
#define	ifa_broadaddr	ifa_dstaddr	/* broadcast address interface */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <sys/cdefs.h>
 | 
			
		||||
 | 
			
		||||
__BEGIN_DECLS
 | 
			
		||||
extern int getifaddrs(struct ifaddrs **ifap);
 | 
			
		||||
extern void freeifaddrs(struct ifaddrs *ifa);
 | 
			
		||||
__END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										3
									
								
								externals/httplib/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								externals/httplib/README.md
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
From https://github.com/yhirose/cpp-httplib/commit/d9479bc0b12e8a1e8bce2d34da4feeef488581f3
 | 
			
		||||
From https://github.com/yhirose/cpp-httplib/commit/b251668522dd459d2c6a75c10390a11b640be708
 | 
			
		||||
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
@@ -13,3 +13,4 @@ It's extremely easy to setup. Just include httplib.h file in your code!
 | 
			
		||||
Inspired by Sinatra and express.
 | 
			
		||||
 | 
			
		||||
© 2017 Yuji Hirose
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6186
									
								
								externals/httplib/httplib.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6186
									
								
								externals/httplib/httplib.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -466,9 +466,17 @@ create_target_directory_groups(core)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
 | 
			
		||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives)
 | 
			
		||||
 | 
			
		||||
if (ENABLE_WEB_SERVICE)
 | 
			
		||||
    target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
 | 
			
		||||
    target_link_libraries(core PRIVATE web_service)
 | 
			
		||||
    get_directory_property(OPENSSL_LIBS
 | 
			
		||||
        DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl
 | 
			
		||||
        DEFINITION OPENSSL_LIBS)
 | 
			
		||||
 | 
			
		||||
    target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE -DCPPHTTPLIB_OPENSSL_SUPPORT)
 | 
			
		||||
    target_link_libraries(core PRIVATE web_service ${OPENSSL_LIBS} httplib lurlparser)
 | 
			
		||||
    if (ANDROID)
 | 
			
		||||
        target_link_libraries(core PRIVATE ifaddrs)
 | 
			
		||||
    endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (ARCHITECTURE_x86_64)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,13 @@
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#ifdef ENABLE_WEB_SERVICE
 | 
			
		||||
#include <LUrlParser.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <cryptopp/aes.h>
 | 
			
		||||
#include <cryptopp/modes.h>
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/file_sys/archive_ncch.h"
 | 
			
		||||
#include "core/file_sys/file_backend.h"
 | 
			
		||||
@@ -48,6 +53,82 @@ const ResultCode ERROR_WRONG_CERT_HANDLE = // 0xD8A0A0C9
 | 
			
		||||
const ResultCode ERROR_CERT_ALREADY_SET = // 0xD8A0A03D
 | 
			
		||||
    ResultCode(61, ErrorModule::HTTP, ErrorSummary::InvalidState, ErrorLevel::Permanent);
 | 
			
		||||
 | 
			
		||||
void Context::MakeRequest() {
 | 
			
		||||
    ASSERT(state == RequestState::NotStarted);
 | 
			
		||||
 | 
			
		||||
#ifdef ENABLE_WEB_SERVICE
 | 
			
		||||
    LUrlParser::clParseURL parsedUrl = LUrlParser::clParseURL::ParseURL(url);
 | 
			
		||||
    int port;
 | 
			
		||||
    std::unique_ptr<httplib::Client> client;
 | 
			
		||||
    if (parsedUrl.m_Scheme == "http") {
 | 
			
		||||
        if (!parsedUrl.GetPort(&port)) {
 | 
			
		||||
            port = 80;
 | 
			
		||||
        }
 | 
			
		||||
        // TODO(B3N30): Support for setting timeout
 | 
			
		||||
        // Figure out what the default timeout on 3DS is
 | 
			
		||||
        client = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port);
 | 
			
		||||
    } else {
 | 
			
		||||
        if (!parsedUrl.GetPort(&port)) {
 | 
			
		||||
            port = 443;
 | 
			
		||||
        }
 | 
			
		||||
        // TODO(B3N30): Support for setting timeout
 | 
			
		||||
        // Figure out what the default timeout on 3DS is
 | 
			
		||||
 | 
			
		||||
        auto ssl_client = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host, port);
 | 
			
		||||
        SSL_CTX* ctx = ssl_client->ssl_context();
 | 
			
		||||
        client = std::move(ssl_client);
 | 
			
		||||
 | 
			
		||||
        if (auto client_cert = ssl_config.client_cert_ctx.lock()) {
 | 
			
		||||
            SSL_CTX_use_certificate_ASN1(ctx, client_cert->certificate.size(),
 | 
			
		||||
                                         client_cert->certificate.data());
 | 
			
		||||
            SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ctx, client_cert->private_key.data(),
 | 
			
		||||
                                        client_cert->private_key.size());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO(B3N30): Check for SSLOptions-Bits and set the verify method accordingly
 | 
			
		||||
        // https://www.3dbrew.org/wiki/SSL_Services#SSLOpt
 | 
			
		||||
        // Hack: Since for now RootCerts are not implemented we set the VerifyMode to None.
 | 
			
		||||
        SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    state = RequestState::InProgress;
 | 
			
		||||
 | 
			
		||||
    static const std::unordered_map<RequestMethod, std::string> request_method_strings{
 | 
			
		||||
        {RequestMethod::Get, "GET"},       {RequestMethod::Post, "POST"},
 | 
			
		||||
        {RequestMethod::Head, "HEAD"},     {RequestMethod::Put, "PUT"},
 | 
			
		||||
        {RequestMethod::Delete, "DELETE"}, {RequestMethod::PostEmpty, "POST"},
 | 
			
		||||
        {RequestMethod::PutEmpty, "PUT"},
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    httplib::Request request;
 | 
			
		||||
    request.method = request_method_strings.at(method);
 | 
			
		||||
    request.path = url;
 | 
			
		||||
    // TODO(B3N30): Add post data body
 | 
			
		||||
    request.progress = [this](u64 current, u64 total) -> bool {
 | 
			
		||||
        // TODO(B3N30): Is there a state that shows response header are available
 | 
			
		||||
        current_download_size_bytes = current;
 | 
			
		||||
        total_download_size_bytes = total;
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (const auto& header : headers) {
 | 
			
		||||
        request.headers.emplace(header.name, header.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!client->send(request, response)) {
 | 
			
		||||
        LOG_ERROR(Service_HTTP, "Request failed");
 | 
			
		||||
        state = RequestState::TimedOut;
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_DEBUG(Service_HTTP, "Request successful");
 | 
			
		||||
        // TODO(B3N30): Verify this state on HW
 | 
			
		||||
        state = RequestState::ReadyToDownloadContent;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    LOG_ERROR(Service_HTTP, "Tried to make request but WebServices is not enabled in this build");
 | 
			
		||||
    state = RequestState::TimedOut;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HTTP_C::Initialize(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x1, 1, 4);
 | 
			
		||||
    const u32 shmem_size = rp.Pop<u32>();
 | 
			
		||||
@@ -152,7 +233,15 @@ void HTTP_C::BeginRequest(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    auto itr = contexts.find(context_handle);
 | 
			
		||||
    ASSERT(itr != contexts.end());
 | 
			
		||||
 | 
			
		||||
    // TODO(B3N30): Make the request
 | 
			
		||||
    // On a 3DS BeginRequest and BeginRequestAsync will push the Request to a worker queue.
 | 
			
		||||
    // You can only enqueue 8 requests at the same time.
 | 
			
		||||
    // trying to enqueue any more will either fail (BeginRequestAsync), or block (BeginRequest)
 | 
			
		||||
    // Note that you only can have 8 Contexts at a time. So this difference shouldn't matter
 | 
			
		||||
    // Then there are 3? worker threads that pop the requests from the queue and send them
 | 
			
		||||
    // For now make every request async in it's own thread.
 | 
			
		||||
 | 
			
		||||
    itr->second.request_future =
 | 
			
		||||
        std::async(std::launch::async, &Context::MakeRequest, std::ref(itr->second));
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
@@ -197,7 +286,15 @@ void HTTP_C::BeginRequestAsync(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    auto itr = contexts.find(context_handle);
 | 
			
		||||
    ASSERT(itr != contexts.end());
 | 
			
		||||
 | 
			
		||||
    // TODO(B3N30): Make the request
 | 
			
		||||
    // On a 3DS BeginRequest and BeginRequestAsync will push the Request to a worker queue.
 | 
			
		||||
    // You can only enqueue 8 requests at the same time.
 | 
			
		||||
    // trying to enqueue any more will either fail (BeginRequestAsync), or block (BeginRequest)
 | 
			
		||||
    // Note that you only can have 8 Contexts at a time. So this difference shouldn't matter
 | 
			
		||||
    // Then there are 3? worker threads that pop the requests from the queue and send them
 | 
			
		||||
    // For now make every request async in it's own thread.
 | 
			
		||||
 | 
			
		||||
    itr->second.request_future =
 | 
			
		||||
        std::async(std::launch::async, &Context::MakeRequest, std::ref(itr->second));
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
@@ -260,7 +357,7 @@ void HTTP_C::CreateContext(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    contexts.emplace(++context_counter, Context());
 | 
			
		||||
    contexts.try_emplace(++context_counter);
 | 
			
		||||
    contexts[context_counter].url = std::move(url);
 | 
			
		||||
    contexts[context_counter].method = method;
 | 
			
		||||
    contexts[context_counter].state = RequestState::NotStarted;
 | 
			
		||||
@@ -307,10 +404,9 @@ void HTTP_C::CloseContext(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO(Subv): What happens if you try to close a context that's currently being used?
 | 
			
		||||
    ASSERT(itr->second.state == RequestState::NotStarted);
 | 
			
		||||
 | 
			
		||||
    // TODO(Subv): Make sure that only the session that created the context can close it.
 | 
			
		||||
 | 
			
		||||
    // Note that this will block if a request is still in progress
 | 
			
		||||
    contexts.erase(itr);
 | 
			
		||||
    session_data->num_http_contexts--;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,18 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <future>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#ifdef ENABLE_WEB_SERVICE
 | 
			
		||||
#if defined(__ANDROID__)
 | 
			
		||||
#include <ifaddrs.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <httplib.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include "core/hle/kernel/shared_memory.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
 | 
			
		||||
@@ -78,8 +85,7 @@ public:
 | 
			
		||||
    Context(const Context&) = delete;
 | 
			
		||||
    Context& operator=(const Context&) = delete;
 | 
			
		||||
 | 
			
		||||
    Context(Context&& other) = default;
 | 
			
		||||
    Context& operator=(Context&&) = default;
 | 
			
		||||
    void MakeRequest();
 | 
			
		||||
 | 
			
		||||
    struct Proxy {
 | 
			
		||||
        std::string url;
 | 
			
		||||
@@ -116,13 +122,20 @@ public:
 | 
			
		||||
    u32 session_id;
 | 
			
		||||
    std::string url;
 | 
			
		||||
    RequestMethod method;
 | 
			
		||||
    RequestState state = RequestState::NotStarted;
 | 
			
		||||
    std::atomic<RequestState> state = RequestState::NotStarted;
 | 
			
		||||
    std::optional<Proxy> proxy;
 | 
			
		||||
    std::optional<BasicAuth> basic_auth;
 | 
			
		||||
    SSLConfig ssl_config{};
 | 
			
		||||
    u32 socket_buffer_size;
 | 
			
		||||
    std::vector<RequestHeader> headers;
 | 
			
		||||
    std::vector<PostData> post_data;
 | 
			
		||||
 | 
			
		||||
    std::future<void> request_future;
 | 
			
		||||
    std::atomic<u64> current_download_size_bytes;
 | 
			
		||||
    std::atomic<u64> total_download_size_bytes;
 | 
			
		||||
#ifdef ENABLE_WEB_SERVICE
 | 
			
		||||
    httplib::Response response;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,3 +18,6 @@ get_directory_property(OPENSSL_LIBS
 | 
			
		||||
        DEFINITION OPENSSL_LIBS)
 | 
			
		||||
target_compile_definitions(web_service PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT)
 | 
			
		||||
target_link_libraries(web_service PRIVATE common network json-headers ${OPENSSL_LIBS} httplib lurlparser cpp-jwt)
 | 
			
		||||
if (ANDROID)
 | 
			
		||||
    target_link_libraries(web_service PRIVATE ifaddrs)
 | 
			
		||||
endif()
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,9 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <LUrlParser.h>
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
#if defined(__ANDROID__)
 | 
			
		||||
#include <ifaddrs.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <httplib.h>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
@@ -73,14 +76,14 @@ struct Client::Impl {
 | 
			
		||||
                if (!parsedUrl.GetPort(&port)) {
 | 
			
		||||
                    port = HTTP_PORT;
 | 
			
		||||
                }
 | 
			
		||||
                cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port,
 | 
			
		||||
                                                        TIMEOUT_SECONDS);
 | 
			
		||||
                cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port);
 | 
			
		||||
                cli->set_timeout_sec(TIMEOUT_SECONDS);
 | 
			
		||||
            } else if (parsedUrl.m_Scheme == "https") {
 | 
			
		||||
                if (!parsedUrl.GetPort(&port)) {
 | 
			
		||||
                    port = HTTPS_PORT;
 | 
			
		||||
                }
 | 
			
		||||
                cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port,
 | 
			
		||||
                                                           TIMEOUT_SECONDS);
 | 
			
		||||
                cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port);
 | 
			
		||||
                cli->set_timeout_sec(TIMEOUT_SECONDS);
 | 
			
		||||
            } else {
 | 
			
		||||
                LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme);
 | 
			
		||||
                return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme"};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user