395 lines
8.7 KiB
C
395 lines
8.7 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;
|
|
|
|
#if defined(_WIN32)
|
|
int option_len;
|
|
#else
|
|
unsigned int option_len;
|
|
#endif
|
|
|
|
/* 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;
|
|
|
|
#if defined(_WIN32)
|
|
int i;
|
|
#else
|
|
unsigned int i;
|
|
#endif
|
|
|
|
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;
|
|
|
|
#if defined(_WIN32)
|
|
int option_len;
|
|
#else
|
|
unsigned int option_len;
|
|
#endif
|
|
|
|
/* 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;
|
|
|
|
#if defined(_WIN32)
|
|
int opt_len;
|
|
#else
|
|
unsigned int opt_len;
|
|
#endif
|
|
|
|
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
|
|
}
|