xrdp/tests/gtcp_proxy/gtcp.c

373 lines
8.5 KiB
C

/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2013
*
* Licensed 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.
*/
#include "gtcp.h"
/**
* Return a newly created socket or -1 on error
*****************************************************************************/
int tcp_socket_create(void)
{
int rv;
int option_value;
socklen_t option_len;
/* in win32 a socket is an unsigned int, in linux, it's an int */
if ((rv = (int) socket(PF_INET, SOCK_STREAM, 0)) < 0)
return -1;
option_len = sizeof(option_value);
if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value,
&option_len) == 0)
{
if (option_value == 0)
{
option_value = 1;
option_len = sizeof(option_value);
setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value,
option_len);
}
}
option_len = sizeof(option_value);
if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value,
&option_len) == 0)
{
if (option_value < (1024 * 32))
{
option_value = 1024 * 32;
option_len = sizeof(option_value);
setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value,
option_len);
}
}
return rv;
}
/**
* Place specified socket in non blocking mode
*****************************************************************************/
void tcp_set_non_blocking(int skt)
{
unsigned long i;
#if defined(_WIN32)
i = 1;
ioctlsocket(skt, FIONBIO, &i);
#else
i = fcntl(skt, F_GETFL);
i = i | O_NONBLOCK;
fcntl(skt, F_SETFL, i);
#endif
}
/**
* Assign name to socket
*
* @param skt the socket to bind
* @param port the port to bind to
*
* @return 0 on success, -1 on error
*****************************************************************************/
int tcp_bind(int skt, char *port)
{
struct sockaddr_in s;
memset(&s, 0, sizeof(struct sockaddr_in));
s.sin_family = AF_INET;
s.sin_port = htons((uint16_t) atoi(port));
s.sin_addr.s_addr = INADDR_ANY;
return bind(skt, (struct sockaddr *) &s, sizeof(struct sockaddr_in));
}
/**
* Listen for incoming connections
*
* @param skt the socket to listen on
*
* @return 0 on success, -1 on error
*****************************************************************************/
int tcp_listen(int skt)
{
return listen(skt, 2);
}
/**
* Accept incoming connection
*
* @param skt socket to accept incoming connection on
*
* @return 0 on success, -1 on error
*****************************************************************************/
int tcp_accept(int skt)
{
int ret ;
char ipAddr[256] ;
struct sockaddr_in s;
socklen_t i;
i = sizeof(struct sockaddr_in);
memset(&s, 0, i);
return accept(skt, (struct sockaddr *)&s, &i);
}
/**
* Check if the socket would block
*
* @return TRUE if would block, else FALSE
*****************************************************************************/
int tcp_last_error_would_block()
{
#if defined(_WIN32)
return WSAGetLastError() == WSAEWOULDBLOCK;
#else
return (errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINPROGRESS);
#endif
}
/**
* Close specified socket
*****************************************************************************/
void tcp_close(int skt)
{
if (skt <= 0)
return;
#if defined(_WIN32)
closesocket(skt);
#else
close(skt);
#endif
}
/**
* Create a new socket
*
* @return new socket or -1 on error
*****************************************************************************/
int tcp_socket(void)
{
int rv;
int option_value;
socklen_t option_len;
/* in win32 a socket is an unsigned int, in linux, it's an int */
if ((rv = (int) socket(PF_INET, SOCK_STREAM, 0)) < 0)
return -1;
option_len = sizeof(option_value);
if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value,
&option_len) == 0)
{
if (option_value == 0)
{
option_value = 1;
option_len = sizeof(option_value);
setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value,
option_len);
}
}
option_len = sizeof(option_value);
if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value,
&option_len) == 0)
{
if (option_value < (1024 * 32))
{
option_value = 1024 * 32;
option_len = sizeof(option_value);
setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value,
option_len);
}
}
return rv;
}
/**
* Connect to a server
*
* @param skt opaque socket obj
* @param address connect to this server
* @param port using this port
*
* @return 0 on success, -1 on error
*****************************************************************************/
int tcp_connect(int skt, const char *hostname, const char *port)
{
struct sockaddr_in s;
struct hostent *h;
memset(&s, 0, sizeof(struct sockaddr_in));
s.sin_family = AF_INET;
s.sin_port = htons((uint16_t) atoi(port));
s.sin_addr.s_addr = inet_addr(hostname);
if (s.sin_addr.s_addr == INADDR_NONE)
{
h = gethostbyname(hostname);
if (h != 0)
{
if (h->h_name != 0)
{
if (h->h_addr_list != 0)
{
if ((*(h->h_addr_list)) != 0)
{
s.sin_addr.s_addr = *((int *)(*(h->h_addr_list)));
}
}
}
}
}
return connect(skt, (struct sockaddr *) &s, sizeof(struct sockaddr_in));
}
/**
* Return 1 if we can write to the socket, 0 otherwise
*****************************************************************************/
int tcp_can_send(int skt, int millis)
{
fd_set wfds;
struct timeval time;
int rv;
time.tv_sec = millis / 1000;
time.tv_usec = (millis * 1000) % 1000000;
FD_ZERO(&wfds);
if (skt > 0)
{
FD_SET(((unsigned int) skt), &wfds);
rv = select(skt + 1, 0, &wfds, 0, &time);
if (rv > 0)
{
return tcp_socket_ok(skt);
}
}
return 0;
}
/**
* Return 1 if socket is OK, 0 otherwise
*****************************************************************************/
int tcp_socket_ok(int skt)
{
int opt;
socklen_t opt_len = sizeof(opt);
if (getsockopt(skt, SOL_SOCKET, SO_ERROR, (char *) (&opt), &opt_len) == 0)
{
if (opt == 0)
return 1;
}
return 0;
}
/**
* Check if specified sockets can be operated on without blocking
*
* @return 1 if they can be operated on or 0 if blocking would occur
*****************************************************************************/
int tcp_select(int sck1, int sck2)
{
fd_set rfds;
struct timeval time;
int max = 0;
int rv = 0;
memset(&rfds, 0, sizeof(fd_set));
memset(&time, 0, sizeof(struct timeval));
time.tv_sec = 0;
time.tv_usec = 0;
FD_ZERO(&rfds);
if (sck1 > 0)
FD_SET(((unsigned int) sck1), &rfds);
if (sck2 > 0)
FD_SET(((unsigned int) sck2), &rfds);
max = sck1;
if (sck2 > max)
max = sck2;
rv = select(max + 1, &rfds, 0, 0, &time);
if (rv > 0)
{
rv = 0;
if (FD_ISSET(((unsigned int) sck1), &rfds))
rv = rv | 1;
if (FD_ISSET(((unsigned int)sck2), &rfds))
rv = rv | 2;
}
else
{
rv = 0;
}
return rv;
}
int tcp_recv(int skt, void *ptr, int len, int flags)
{
#if defined(_WIN32)
return recv(skt, (char *) ptr, len, flags);
#else
return recv(skt, ptr, len, flags);
#endif
}
int tcp_send(int skt, const void *ptr, int len, int flags)
{
#if defined(_WIN32)
return send(skt, (const char *)ptr, len, flags);
#else
return send(skt, ptr, len, flags);
#endif
}