send/recv: use _libssh2_recv and _libssh2_send now
Starting now, we unconditionally use the internal replacement functions for send() and recv() - creatively named _libssh2_recv() and _libssh2_send(). On errors, these functions return the negative 'errno' value instead of the traditional -1. This design allows systems that have no "natural" errno support to not have to invent it. It also means that no code outside of these two transfer functions should use the errno variable.
This commit is contained in:
parent
aff9c825c8
commit
ca2e81eb1f
20
src/agent.c
20
src/agent.c
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 by Daiki Ueno
|
* Copyright (c) 2009 by Daiki Ueno
|
||||||
|
* Copyright (C) 2010 by Daniel Stenberg
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@ -176,9 +177,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
|||||||
/* Send the length of the request */
|
/* Send the length of the request */
|
||||||
if (transctx->state == agent_NB_state_request_created) {
|
if (transctx->state == agent_NB_state_request_created) {
|
||||||
_libssh2_htonu32(buf, transctx->request_len);
|
_libssh2_htonu32(buf, transctx->request_len);
|
||||||
rc = send(agent->fd, buf, sizeof buf, 0);
|
rc = _libssh2_send(agent->fd, buf, sizeof buf, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (errno == EAGAIN)
|
if (rc == -EAGAIN)
|
||||||
return LIBSSH2_ERROR_EAGAIN;
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||||
"agent send failed");
|
"agent send failed");
|
||||||
@ -188,10 +189,10 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
|||||||
|
|
||||||
/* Send the request body */
|
/* Send the request body */
|
||||||
if (transctx->state == agent_NB_state_request_length_sent) {
|
if (transctx->state == agent_NB_state_request_length_sent) {
|
||||||
rc = send(agent->fd, transctx->request,
|
rc = _libssh2_send(agent->fd, transctx->request,
|
||||||
transctx->request_len, 0);
|
transctx->request_len, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (errno == EAGAIN)
|
if (rc == -EAGAIN)
|
||||||
return LIBSSH2_ERROR_EAGAIN;
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||||
"agent send failed");
|
"agent send failed");
|
||||||
@ -201,9 +202,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
|||||||
|
|
||||||
/* Receive the length of a response */
|
/* Receive the length of a response */
|
||||||
if (transctx->state == agent_NB_state_request_sent) {
|
if (transctx->state == agent_NB_state_request_sent) {
|
||||||
rc = recv(agent->fd, buf, sizeof buf, 0);
|
rc = _libssh2_recv(agent->fd, buf, sizeof buf, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (errno == EAGAIN)
|
if (rc == -EAGAIN)
|
||||||
return LIBSSH2_ERROR_EAGAIN;
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
|
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
|
||||||
"agent recv failed");
|
"agent recv failed");
|
||||||
@ -219,9 +220,10 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
|||||||
|
|
||||||
/* Receive the response body */
|
/* Receive the response body */
|
||||||
if (transctx->state == agent_NB_state_response_length_received) {
|
if (transctx->state == agent_NB_state_response_length_received) {
|
||||||
rc = recv(agent->fd, transctx->response, transctx->response_len, 0);
|
rc = _libssh2_recv(agent->fd, transctx->response,
|
||||||
|
transctx->response_len, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (errno == EAGAIN)
|
if (rc == -EAGAIN)
|
||||||
return LIBSSH2_ERROR_EAGAIN;
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||||
"agent recv failed");
|
"agent recv failed");
|
||||||
|
@ -998,13 +998,10 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
|||||||
#define SSH_OPEN_UNKNOWN_CHANNELTYPE 3
|
#define SSH_OPEN_UNKNOWN_CHANNELTYPE 3
|
||||||
#define SSH_OPEN_RESOURCE_SHORTAGE 4
|
#define SSH_OPEN_RESOURCE_SHORTAGE 4
|
||||||
|
|
||||||
#if defined( WIN32 ) || defined( __VMS )
|
ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer,
|
||||||
ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, size_t length, int flags);
|
size_t length, int flags);
|
||||||
ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length, int flags);
|
ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer,
|
||||||
#else
|
size_t length, int flags);
|
||||||
#define _libssh2_recv(a,b,c,d) recv(a,b,c,d)
|
|
||||||
#define _libssh2_send(a,b,c,d) send(a,b,c,d)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
|
#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
|
||||||
waiting for more data to arrive */
|
waiting for more data to arrive */
|
||||||
|
49
src/misc.c
49
src/misc.c
@ -1,5 +1,5 @@
|
|||||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||||
* Copyright (c) 2009 by Daniel Stenberg
|
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||||
* Copyright (c) 2010 Simon Josefsson
|
* Copyright (c) 2010 Simon Josefsson
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -89,53 +89,56 @@ static int wsa2errno(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _libssh2_recv
|
|
||||||
/* _libssh2_recv
|
/* _libssh2_recv
|
||||||
*
|
*
|
||||||
* Wrapper around standard recv to allow WIN32 systems
|
* Replacement for the standard recv, return -errno on failure.
|
||||||
* to set errno
|
|
||||||
*/
|
*/
|
||||||
ssize_t
|
ssize_t
|
||||||
_libssh2_recv(libssh2_socket_t socket, void *buffer, size_t length, int flags)
|
_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags)
|
||||||
{
|
{
|
||||||
ssize_t rc = recv(socket, buffer, length, flags);
|
ssize_t rc = recv(sock, buffer, length, flags);
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (rc < 0 )
|
if (rc < 0 )
|
||||||
errno = wsa2errno();
|
return -wsa2errno();
|
||||||
#endif
|
#elsif defined(__VMS)
|
||||||
#ifdef __VMS
|
|
||||||
if (rc < 0 ){
|
if (rc < 0 ){
|
||||||
if ( errno == EWOULDBLOCK ) errno = EAGAIN;
|
if ( errno == EWOULDBLOCK )
|
||||||
|
return -EAGAIN;
|
||||||
|
else
|
||||||
|
return -errno;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (rc < 0 )
|
||||||
|
return -errno;
|
||||||
#endif
|
#endif
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#endif /* _libssh2_recv */
|
|
||||||
|
|
||||||
#ifndef _libssh2_send
|
|
||||||
|
|
||||||
/* _libssh2_send
|
/* _libssh2_send
|
||||||
*
|
*
|
||||||
* Wrapper around standard send to allow WIN32 systems
|
* Replacement for the standard send, return -errno on failure.
|
||||||
* to set errno
|
|
||||||
*/
|
*/
|
||||||
ssize_t
|
ssize_t
|
||||||
_libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length,
|
_libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
ssize_t rc = send(socket, buffer, length, flags);
|
ssize_t rc = send(sock, buffer, length, flags);
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (rc < 0 )
|
if (rc < 0 )
|
||||||
errno = wsa2errno();
|
return -wsa2errno();
|
||||||
#endif
|
#elsif defined(__VMS)
|
||||||
#ifdef VMS
|
if (rc < 0 ) {
|
||||||
if (rc < 0 ){
|
if ( errno == EWOULDBLOCK )
|
||||||
if ( errno == EWOULDBLOCK ) errno = EAGAIN;
|
return -EAGAIN;
|
||||||
|
else
|
||||||
|
return -errno;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (rc < 0 )
|
||||||
|
return -errno;
|
||||||
#endif
|
#endif
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#endif /* _libssh2_recv */
|
|
||||||
|
|
||||||
/* libssh2_ntohu32
|
/* libssh2_ntohu32
|
||||||
*/
|
*/
|
||||||
|
20
src/scp.c
20
src/scp.c
@ -510,13 +510,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
|||||||
|
|
||||||
*(p++) = '\0';
|
*(p++) = '\0';
|
||||||
/* Make sure we don't get fooled by leftover values */
|
/* Make sure we don't get fooled by leftover values */
|
||||||
errno = 0;
|
|
||||||
session->scpRecv_mtime = strtol((char *) s, NULL, 10);
|
session->scpRecv_mtime = strtol((char *) s, NULL, 10);
|
||||||
if (errno) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
|
||||||
"Invalid response from SCP server, invalid mtime");
|
|
||||||
goto scp_recv_error;
|
|
||||||
}
|
|
||||||
s = (unsigned char *) strchr((char *) p, ' ');
|
s = (unsigned char *) strchr((char *) p, ' ');
|
||||||
if (!s || ((s - p) <= 0)) {
|
if (!s || ((s - p) <= 0)) {
|
||||||
/* No spaces or space in the wrong spot */
|
/* No spaces or space in the wrong spot */
|
||||||
@ -537,13 +532,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
|||||||
|
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
/* Make sure we don't get fooled by leftover values */
|
/* Make sure we don't get fooled by leftover values */
|
||||||
errno = 0;
|
|
||||||
session->scpRecv_atime = strtol((char *) s, NULL, 10);
|
session->scpRecv_atime = strtol((char *) s, NULL, 10);
|
||||||
if (errno) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
|
||||||
"Invalid response from SCP server, invalid atime");
|
|
||||||
goto scp_recv_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SCP ACK */
|
/* SCP ACK */
|
||||||
session->scpRecv_response[0] = '\0';
|
session->scpRecv_response[0] = '\0';
|
||||||
@ -676,9 +665,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
|||||||
|
|
||||||
*(p++) = '\0';
|
*(p++) = '\0';
|
||||||
/* Make sure we don't get fooled by leftover values */
|
/* Make sure we don't get fooled by leftover values */
|
||||||
errno = 0;
|
|
||||||
session->scpRecv_mode = strtol(s, &e, 8);
|
session->scpRecv_mode = strtol(s, &e, 8);
|
||||||
if ((e && *e) || errno) {
|
if (e && *e) {
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||||
"Invalid response from SCP server, invalid mode");
|
"Invalid response from SCP server, invalid mode");
|
||||||
goto scp_recv_error;
|
goto scp_recv_error;
|
||||||
@ -694,9 +683,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
|||||||
|
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
/* Make sure we don't get fooled by leftover values */
|
/* Make sure we don't get fooled by leftover values */
|
||||||
errno = 0;
|
|
||||||
session->scpRecv_size = scpsize_strtol(p, &e, 10);
|
session->scpRecv_size = scpsize_strtol(p, &e, 10);
|
||||||
if ((e && *e) || errno) {
|
if (e && *e) {
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||||
"Invalid response from SCP server, invalid size");
|
"Invalid response from SCP server, invalid size");
|
||||||
goto scp_recv_error;
|
goto scp_recv_error;
|
||||||
|
@ -115,17 +115,17 @@ banner_receive(LIBSSH2_SESSION * session)
|
|||||||
ret = _libssh2_recv(session->socket_fd, &c, 1,
|
ret = _libssh2_recv(session->socket_fd, &c, 1,
|
||||||
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if(session->api_block_mode || (errno != EAGAIN))
|
if(session->api_block_mode || (ret != -EAGAIN))
|
||||||
/* ignore EAGAIN when non-blocking */
|
/* ignore EAGAIN when non-blocking */
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Error recving %d bytes: %d", 1, errno);
|
"Error recving %d bytes: %d", 1, -ret);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Recved %d bytes banner", ret);
|
"Recved %d bytes banner", ret);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EAGAIN) {
|
if (ret == -EAGAIN) {
|
||||||
session->socket_block_directions =
|
session->socket_block_directions =
|
||||||
LIBSSH2_SESSION_BLOCK_INBOUND;
|
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||||
session->banner_TxRx_total_send = banner_len;
|
session->banner_TxRx_total_send = banner_len;
|
||||||
@ -231,7 +231,7 @@ banner_send(LIBSSH2_SESSION * session)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Error sending %d bytes: %d",
|
"Error sending %d bytes: %d",
|
||||||
banner_len - session->banner_TxRx_total_send, errno);
|
banner_len - session->banner_TxRx_total_send, -ret);
|
||||||
else
|
else
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Sent %d/%d bytes at %p+%d", ret,
|
"Sent %d/%d bytes at %p+%d", ret,
|
||||||
@ -239,7 +239,7 @@ banner_send(LIBSSH2_SESSION * session)
|
|||||||
banner, session->banner_TxRx_total_send);
|
banner, session->banner_TxRx_total_send);
|
||||||
|
|
||||||
if (ret != (banner_len - session->banner_TxRx_total_send)) {
|
if (ret != (banner_len - session->banner_TxRx_total_send)) {
|
||||||
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
|
if ((ret > 0) || ((ret == -1) && (ret == -EAGAIN))) {
|
||||||
/* the whole packet could not be sent, save the what was */
|
/* the whole packet could not be sent, save the what was */
|
||||||
session->socket_block_directions =
|
session->socket_block_directions =
|
||||||
LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||||
|
@ -347,17 +347,17 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
|||||||
_libssh2_recv(session->socket_fd, &p->buf[remainbuf],
|
_libssh2_recv(session->socket_fd, &p->buf[remainbuf],
|
||||||
PACKETBUFSIZE - remainbuf,
|
PACKETBUFSIZE - remainbuf,
|
||||||
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||||
if (nread <= 0) {
|
if (nread <= 0) {
|
||||||
/* check if this is due to EAGAIN and return the special
|
/* check if this is due to EAGAIN and return the special
|
||||||
return code if so, error out normally otherwise */
|
return code if so, error out normally otherwise */
|
||||||
if ((nread < 0) && (errno == EAGAIN)) {
|
if ((nread < 0) && (nread == -EAGAIN)) {
|
||||||
session->socket_block_directions |=
|
session->socket_block_directions |=
|
||||||
LIBSSH2_SESSION_BLOCK_INBOUND;
|
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||||
return LIBSSH2_ERROR_EAGAIN;
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
}
|
}
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Error recving %d bytes (got %d): %d",
|
"Error recving %d bytes (got %d)",
|
||||||
PACKETBUFSIZE - remainbuf, nread, errno);
|
PACKETBUFSIZE - remainbuf, -nread);
|
||||||
return LIBSSH2_ERROR_SOCKET_RECV;
|
return LIBSSH2_ERROR_SOCKET_RECV;
|
||||||
}
|
}
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
@ -600,7 +600,7 @@ send_existing(LIBSSH2_SESSION *session, const unsigned char *data,
|
|||||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Error sending %d bytes: %d", length, errno);
|
"Error sending %d bytes: %d", length, -rc);
|
||||||
else
|
else
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Sent %d/%d bytes at %p+%d", rc, length, p->outbuf,
|
"Sent %d/%d bytes at %p+%d", rc, length, p->outbuf,
|
||||||
@ -621,7 +621,7 @@ send_existing(LIBSSH2_SESSION *session, const unsigned char *data,
|
|||||||
}
|
}
|
||||||
else if (rc < 0) {
|
else if (rc < 0) {
|
||||||
/* nothing was sent */
|
/* nothing was sent */
|
||||||
if (errno != EAGAIN)
|
if (rc != -EAGAIN)
|
||||||
/* send failure! */
|
/* send failure! */
|
||||||
return LIBSSH2_ERROR_SOCKET_SEND;
|
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||||
|
|
||||||
@ -812,7 +812,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
|||||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
"Error sending %d bytes: %d", total_length, errno);
|
"Error sending %d bytes: %d", total_length, -ret);
|
||||||
else
|
else
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p",
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p",
|
||||||
ret, total_length, p->outbuf);
|
ret, total_length, p->outbuf);
|
||||||
@ -821,7 +821,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
|||||||
debugdump(session, "libssh2_transport_write send()", p->outbuf, ret);
|
debugdump(session, "libssh2_transport_write send()", p->outbuf, ret);
|
||||||
}
|
}
|
||||||
if (ret != total_length) {
|
if (ret != total_length) {
|
||||||
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
|
if ((ret > 0) || ((ret == -1) && (ret == -EAGAIN))) {
|
||||||
/* the whole packet could not be sent, save the rest */
|
/* the whole packet could not be sent, save the rest */
|
||||||
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||||
p->odata = orgdata;
|
p->odata = orgdata;
|
||||||
|
Loading…
Reference in New Issue
Block a user