Resync new repository with old repo r5166
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
5bec43869a
commit
94acbb2e37
@ -329,4 +329,7 @@
|
|||||||
discussed at http://www.drdobbs.com/web-development/\
|
discussed at http://www.drdobbs.com/web-development/\
|
||||||
an-embeddable-lightweight-xml-rpc-server/184405364. Contributed by
|
an-embeddable-lightweight-xml-rpc-server/184405364. Contributed by
|
||||||
Max Holtzberg.
|
Max Holtzberg.
|
||||||
|
* apps/netutils/uip_listenon.c: Logic in uip_server.c that creates
|
||||||
|
the listening socket was moved to this new file to support re-use.
|
||||||
|
Contributed by Kate.
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ config EXAMPLES_XMLRPC
|
|||||||
config EXAMPLES_XMLRPC_BUFFERSIZE
|
config EXAMPLES_XMLRPC_BUFFERSIZE
|
||||||
int "HTTP buffer size"
|
int "HTTP buffer size"
|
||||||
default 1024
|
default 1024
|
||||||
|
depends on EXAMPLES_XMLRPC
|
||||||
|
|
||||||
config EXAMPLES_XMLRPC_DHCPC
|
config EXAMPLES_XMLRPC_DHCPC
|
||||||
bool "DHCP Client"
|
bool "DHCP Client"
|
||||||
|
@ -84,9 +84,13 @@ extern "C" {
|
|||||||
|
|
||||||
#define HTTPD_IOBUFFER_SIZE (3*UIP_TCP_MSS)
|
#define HTTPD_IOBUFFER_SIZE (3*UIP_TCP_MSS)
|
||||||
|
|
||||||
/* this is the maximum size of a file path */
|
/* This is the maximum size of a file path */
|
||||||
|
|
||||||
|
#if defined(CONFIG_NETUTILS_HTTPD_MMAP) || defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
|
||||||
|
#define HTTPD_MAX_FILENAME PATH_MAX
|
||||||
|
#else
|
||||||
#define HTTPD_MAX_FILENAME 20
|
#define HTTPD_MAX_FILENAME 20
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public types
|
* Public types
|
||||||
@ -96,7 +100,7 @@ struct httpd_fs_file
|
|||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
int len;
|
int len;
|
||||||
#ifdef CONFIG_NETUTILS_HTTPD_MMAP
|
#if defined(CONFIG_NETUTILS_HTTPD_MMAP) || defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
|
||||||
int fd;
|
int fd;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -3,8 +3,13 @@
|
|||||||
* DNS resolver code header file.
|
* DNS resolver code header file.
|
||||||
* Author Adam Dunkels <adam@dunkels.com>
|
* Author Adam Dunkels <adam@dunkels.com>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002-2003, Adam Dunkels.
|
* Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
|
||||||
* All rights reserved.
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* Inspired by/based on uIP logic by Adam Dunkels:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2003, Adam Dunkels.
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -41,6 +46,8 @@
|
|||||||
|
|
||||||
#include <nuttx/net/uip/uipopt.h>
|
#include <nuttx/net/uip/uipopt.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Function Prototypes
|
* Public Function Prototypes
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -58,13 +65,13 @@ extern "C" {
|
|||||||
EXTERN int resolv_init(void);
|
EXTERN int resolv_init(void);
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IPv6
|
#ifdef CONFIG_NET_IPv6
|
||||||
EXTERN void resolv_conf(const struct in6_addr *dnsserver);
|
EXTERN void resolv_conf(FAR const struct in6_addr *dnsserver);
|
||||||
EXTERN void resolv_getserver(const struct in_addr *dnsserver);
|
EXTERN void resolv_getserver(FAR const struct in_addr *dnsserver);
|
||||||
EXTERN int resolv_query(const char *name, struct sockaddr_in6 *addr);
|
EXTERN int resolv_query(FAR const char *name, FAR struct sockaddr_in6 *addr);
|
||||||
#else
|
#else
|
||||||
EXTERN void resolv_conf(const struct in_addr *dnsserver);
|
EXTERN void resolv_conf(FAR const struct in_addr *dnsserver);
|
||||||
EXTERN void resolv_getserver(struct in_addr *dnsserver);
|
EXTERN void resolv_getserver(FAR struct in_addr *dnsserver);
|
||||||
EXTERN int resolv_query(const char *name, struct sockaddr_in *addr);
|
EXTERN int resolv_query(FAR const char *name, FAR struct sockaddr_in *addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
|
@ -132,6 +132,7 @@ EXTERN int uip_parsehttpurl(const char *url, uint16_t *port,
|
|||||||
|
|
||||||
/* Generic server logic */
|
/* Generic server logic */
|
||||||
|
|
||||||
|
EXTERN int uip_listenon(uint16_t portno);
|
||||||
EXTERN void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize);
|
EXTERN void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize);
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
|
@ -14,8 +14,8 @@ uIP Applications
|
|||||||
|
|
||||||
This directory contains most of the network applications contained
|
This directory contains most of the network applications contained
|
||||||
under the uIP-1.0 apps directory. As the uIP apps/README says,
|
under the uIP-1.0 apps directory. As the uIP apps/README says,
|
||||||
these applications "are not all heavily tested." These uIP apps
|
these applications "are not all heavily tested." These uIP-based
|
||||||
include:
|
apps include:
|
||||||
|
|
||||||
dhcpc - Dynamic Host Configuration Protocol (DHCP) client. See
|
dhcpc - Dynamic Host Configuration Protocol (DHCP) client. See
|
||||||
apps/include/netutils/dhcpc.h for interface information.
|
apps/include/netutils/dhcpc.h for interface information.
|
||||||
@ -29,7 +29,9 @@ include:
|
|||||||
for interface information.
|
for interface information.
|
||||||
|
|
||||||
You may find additional information on these apps in the uIP forum
|
You may find additional information on these apps in the uIP forum
|
||||||
accessible through: http://www.sics.se/~adam/uip/index.php/Main_Page
|
accessible through: http://www.sics.se/~adam/uip/index.php/Main_Page .
|
||||||
|
Some of these (such as the uIP web server) have grown some additional
|
||||||
|
functionality due primarily to NuttX user contributions.
|
||||||
|
|
||||||
Other Network Applications
|
Other Network Applications
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -41,7 +41,13 @@ include $(APPDIR)/Make.defs
|
|||||||
|
|
||||||
ASRCS =
|
ASRCS =
|
||||||
CSRCS = uiplib.c uip_sethostaddr.c uip_gethostaddr.c uip_setdraddr.c \
|
CSRCS = uiplib.c uip_sethostaddr.c uip_gethostaddr.c uip_setdraddr.c \
|
||||||
uip_setnetmask.c uip_parsehttpurl.c uip_server.c
|
uip_setnetmask.c uip_parsehttpurl.c
|
||||||
|
|
||||||
|
# These require TCP support
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_NET_TCP),y)
|
||||||
|
CSRCS += uip_server.c uip_listenon.c
|
||||||
|
endif
|
||||||
|
|
||||||
# No MAC address support for SLIP (Ethernet only)
|
# No MAC address support for SLIP (Ethernet only)
|
||||||
|
|
||||||
|
131
netutils/uiplib/uip_listenon.c
Normal file
131
netutils/uiplib/uip_listenon.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* netutils/uiplib/uip_listenon.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* 2. 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.
|
||||||
|
* 3. Neither the name Gregory Nutt nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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 OWNER 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <apps/netutils/uiplib.h>
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: uip_listenon
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Implement basic server listening
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* portno The port to listen on (in network byte order)
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* A valid listening socket or -1 on error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int uip_listenon(uint16_t portno)
|
||||||
|
{
|
||||||
|
struct sockaddr_in myaddr;
|
||||||
|
int listensd;
|
||||||
|
#ifdef CONFIG_NET_HAVE_REUSEADDR
|
||||||
|
int optval;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Create a new TCP socket to use to listen for connections */
|
||||||
|
|
||||||
|
listensd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
if (listensd < 0)
|
||||||
|
{
|
||||||
|
ndbg("socket failure: %d\n", errno);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set socket to reuse address */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_HAVE_REUSEADDR
|
||||||
|
optval = 1;
|
||||||
|
if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0)
|
||||||
|
{
|
||||||
|
ndbg("setsockopt SO_REUSEADDR failure: %d\n", errno);
|
||||||
|
goto errout_with_socket;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Bind the socket to a local address */
|
||||||
|
|
||||||
|
myaddr.sin_family = AF_INET;
|
||||||
|
myaddr.sin_port = portno;
|
||||||
|
myaddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0)
|
||||||
|
{
|
||||||
|
ndbg("bind failure: %d\n", errno);
|
||||||
|
goto errout_with_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Listen for connections on the bound TCP socket */
|
||||||
|
|
||||||
|
if (listen(listensd, 5) < 0)
|
||||||
|
{
|
||||||
|
ndbg("listen failure %d\n", errno);
|
||||||
|
goto errout_with_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin accepting connections */
|
||||||
|
|
||||||
|
nvdbg("Accepting connections on port %d\n", ntohs(portno));
|
||||||
|
return listensd;
|
||||||
|
|
||||||
|
errout_with_socket:
|
||||||
|
close(listensd);
|
||||||
|
return ERROR;
|
||||||
|
}
|
@ -41,12 +41,14 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include <apps/netutils/uiplib.h>
|
#include <apps/netutils/uiplib.h>
|
||||||
@ -87,53 +89,17 @@ void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize)
|
|||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
int listensd;
|
int listensd;
|
||||||
int acceptsd;
|
int acceptsd;
|
||||||
#ifdef CONFIG_NET_HAVE_REUSEADDR
|
|
||||||
int optval;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Create a new TCP socket to use to listen for connections */
|
/* Create a new TCP socket to use to listen for connections */
|
||||||
|
|
||||||
listensd = socket(PF_INET, SOCK_STREAM, 0);
|
listensd = uip_listenon(portno);
|
||||||
if (listensd < 0)
|
if (listensd < 0)
|
||||||
{
|
{
|
||||||
ndbg("socket failure: %d\n", errno);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set socket to reuse address */
|
/* Begin serving connections */
|
||||||
|
|
||||||
#ifdef CONFIG_NET_HAVE_REUSEADDR
|
|
||||||
optval = 1;
|
|
||||||
if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0)
|
|
||||||
{
|
|
||||||
ndbg("setsockopt SO_REUSEADDR failure: %d\n", errno);
|
|
||||||
goto errout_with_socket;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Bind the socket to a local address */
|
|
||||||
|
|
||||||
myaddr.sin_family = AF_INET;
|
|
||||||
myaddr.sin_port = portno;
|
|
||||||
myaddr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
|
|
||||||
if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0)
|
|
||||||
{
|
|
||||||
ndbg("bind failure: %d\n", errno);
|
|
||||||
goto errout_with_socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Listen for connections on the bound TCP socket */
|
|
||||||
|
|
||||||
if (listen(listensd, 5) < 0)
|
|
||||||
{
|
|
||||||
ndbg("listen failure %d\n", errno);
|
|
||||||
goto errout_with_socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Begin accepting connections */
|
|
||||||
|
|
||||||
nvdbg("Accepting connections on port %d\n", ntohs(portno));
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
addrlen = sizeof(struct sockaddr_in);
|
addrlen = sizeof(struct sockaddr_in);
|
||||||
@ -143,6 +109,7 @@ void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize)
|
|||||||
ndbg("accept failure: %d\n", errno);
|
ndbg("accept failure: %d\n", errno);
|
||||||
break;;
|
break;;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvdbg("Connection accepted -- spawning sd=%d\n", acceptsd);
|
nvdbg("Connection accepted -- spawning sd=%d\n", acceptsd);
|
||||||
|
|
||||||
/* Configure to "linger" until all data is sent when the socket is closed */
|
/* Configure to "linger" until all data is sent when the socket is closed */
|
||||||
@ -154,7 +121,7 @@ void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize)
|
|||||||
{
|
{
|
||||||
close(acceptsd);
|
close(acceptsd);
|
||||||
ndbg("setsockopt SO_LINGER failure: %d\n", errno);
|
ndbg("setsockopt SO_LINGER failure: %d\n", errno);
|
||||||
break;;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -179,6 +146,5 @@ void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize)
|
|||||||
(void)pthread_detach(child);
|
(void)pthread_detach(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
errout_with_socket:
|
|
||||||
close(listensd);
|
close(listensd);
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@ static const char g_httpcontenttypehtml[] = "Content-type: text/html\r\n\r\n";
|
|||||||
static const char g_httpcontenttypejpg[] = "Content-type: image/jpeg\r\n\r\n";
|
static const char g_httpcontenttypejpg[] = "Content-type: image/jpeg\r\n\r\n";
|
||||||
static const char g_httpcontenttypeplain[] = "Content-type: text/plain\r\n\r\n";
|
static const char g_httpcontenttypeplain[] = "Content-type: text/plain\r\n\r\n";
|
||||||
static const char g_httpcontenttypepng[] = "Content-type: image/png\r\n\r\n";
|
static const char g_httpcontenttypepng[] = "Content-type: image/png\r\n\r\n";
|
||||||
|
static const char g_httpcontenttypejs[] = "Content-type: text/javascript\r\n\r\n";
|
||||||
|
|
||||||
#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
|
#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
|
||||||
static const char g_httpextensionshtml[] = ".shtml";
|
static const char g_httpextensionshtml[] = ".shtml";
|
||||||
@ -109,6 +110,7 @@ static const char g_httpextensioncss[] = ".css";
|
|||||||
static const char g_httpextensionpng[] = ".png";
|
static const char g_httpextensionpng[] = ".png";
|
||||||
static const char g_httpextensiongif[] = ".gif";
|
static const char g_httpextensiongif[] = ".gif";
|
||||||
static const char g_httpextensionjpg[] = ".jpg";
|
static const char g_httpextensionjpg[] = ".jpg";
|
||||||
|
static const char g_httpextensionjs[] = ".js";
|
||||||
|
|
||||||
static const char g_http404path[] = "/404.html";
|
static const char g_http404path[] = "/404.html";
|
||||||
#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
|
#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
|
||||||
@ -391,6 +393,10 @@ static int send_headers(struct httpd_state *pstate, const char *statushdr, int l
|
|||||||
{
|
{
|
||||||
ret = httpd_addchunk(pstate, g_httpcontenttypejpg, strlen(g_httpcontenttypejpg));
|
ret = httpd_addchunk(pstate, g_httpcontenttypejpg, strlen(g_httpcontenttypejpg));
|
||||||
}
|
}
|
||||||
|
else if (strncmp(g_httpextensionjs, ptr, strlen(g_httpextensionjs)) == 0)
|
||||||
|
{
|
||||||
|
ret = httpd_addchunk(pstate, g_httpcontenttypejs, strlen(g_httpcontenttypejs));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = httpd_addchunk(pstate, g_httpcontenttypeplain, strlen(g_httpcontenttypeplain));
|
ret = httpd_addchunk(pstate, g_httpcontenttypeplain, strlen(g_httpcontenttypeplain));
|
||||||
|
@ -164,6 +164,7 @@ int nsh_netinit(void)
|
|||||||
dhcpc_close(handle);
|
dhcpc_close(handle);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user