// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. // Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved. // // This file is part of the VNC system. // // The VNC system is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // // TightVNC distribution homepage on the Web: http://www.tightvnc.com/ // // If the source code for the VNC system is not available from the place // whence you received this file, check http://www.uk.research.att.com/vnc or contact // the authors on vnc@uk.research.att.com for information on obtaining it. // VSocket.cpp // The VSocket class provides a platform-independent socket abstraction // with the simple functionality required for an RFB server. class VSocket; //////////////////////////////////////////////////////// // System includes #include "stdhdrs.h" // Visual C++ .NET 2003 compatibility #if (_MSC_VER>= 1300) #include #else #include #endif #include #ifdef __WIN32__ #include #include #else #include #include #include #include #include #include #include #include #include #include #endif #include //////////////////////////////////////////////////////// // Custom includes #include "VTypes.h" //////////////////////////////////////////////////////// // *** Lovely hacks to make Win32 work. Hurrah! #if defined(__WIN32__) && !defined(EWOULDBLOCK) #define EWOULDBLOCK WSAEWOULDBLOCK #endif //////////////////////////////////////////////////////// // Socket implementation #include "VSocket.h" // The socket timeout value (currently 5 seconds, for no reason...) // *** THIS IS NOT CURRENTLY USED ANYWHERE const VInt rfbMaxClientWait = 5000; //////////////////////////// // Socket implementation initialisation static WORD winsockVersion = 0; VSocketSystem::VSocketSystem() { // Initialise the socket subsystem // This is only provided for compatibility with Windows. #ifdef __WIN32__ // Initialise WinPoxySockets on Win32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) != 0) { m_status = VFalse; return; } winsockVersion = wsaData.wVersion; #else // Disable the nasty read/write failure signals on UNIX signal(SIGPIPE, SIG_IGN); #endif // If successful, or if not required, then continue! m_status = VTrue; } VSocketSystem::~VSocketSystem() { /*if (m_status) { WSACleanup(); }*/ } //////////////////////////// VSocket::VSocket() { // Clear out the internal socket fields sock = -1; hCloseEvent = NULL; out_queue = NULL; } VSocket::VSocket( WSAPROTOCOL_INFO * pSocketInfo, HANDLE hClose ) { sock = (int)WSASocket( AF_INET, SOCK_STREAM, 0, pSocketInfo, 0, 0 ); if( sock == INVALID_SOCKET ) sock = -1; //BREAK_ON_WSAERROR( "[VNCDLL] vncdll_run. WSASocketA failed" ); // Clear out the internal socket fields //sock = (int)socket; hCloseEvent = hClose; out_queue = NULL; } //////////////////////////// VSocket::~VSocket() { // Close the socket Close(); } //////////////////////////// VBool VSocket::Create() { const int one = 1; // Check that the old socket was closed if (sock >= 0) Close(); // Create the socket if ((sock = (int)socket(AF_INET, SOCK_STREAM, 0)) < 0) { return VFalse; } // Set the socket options: if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one))) { return VFalse; } if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one))) { return VFalse; } return VTrue; } //////////////////////////// extern HANDLE hCloseEvent; VBool VSocket::Close() { if( sock >= 0 ) { //shutdown(sock, SD_BOTH); //closesocket(sock); //CloseHandle( (HANDLE)sock ); sock = -1; SetEvent( hCloseEvent ); } while (out_queue) { AIOBlock *next = out_queue->next; delete out_queue; out_queue = next; } return VTrue; } //////////////////////////// VBool VSocket::Shutdown() { /*if (sock >= 0) { shutdown(sock, SD_BOTH); }*/ while (out_queue) { AIOBlock *next = out_queue->next; delete out_queue; out_queue = next; } return VTrue; } //////////////////////////// VBool VSocket::Bind(const VCard port, const VBool localOnly, const VBool checkIfInUse) { return VFalse; /*struct sockaddr_in addr; // Check that the socket is open! if (sock < 0) return VFalse; // If a specific port is being set then check it's not already used! if (port != 0 && checkIfInUse) { VSocket dummy; if (dummy.Create()) { // If we're able to connect then the port number is in use... if (dummy.Connect("localhost", port)) return VFalse; } } // Set up the address to bind the socket to addr.sin_family = AF_INET; addr.sin_port = htons(port); if (localOnly) addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else addr.sin_addr.s_addr = htonl(INADDR_ANY); // And do the binding if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) return VFalse; return VTrue;*/ } //////////////////////////// VBool VSocket::Connect(VStringConst address, const VCard port) { return VFalse; /* // Check the socket if (sock < 0) return VFalse; // Create an address structure and clear it struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); // Fill in the address if possible addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(address); // Was the string a valid IP address? if (addr.sin_addr.s_addr == -1) { // No, so get the actual IP address of the host name specified struct hostent *pHost; pHost = gethostbyname(address); if (pHost != NULL) { if (pHost->h_addr == NULL) return VFalse; addr.sin_addr.s_addr = ((struct in_addr *)pHost->h_addr)->s_addr; } else return VFalse; } // Set the port number in the correct format addr.sin_port = htons(port); // Actually connect the socket if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) return VFalse; // Put the socket into non-blocking mode #ifdef __WIN32__ u_long arg = 1; if (ioctlsocket(sock, FIONBIO, &arg) != 0) return VFalse; #else if (fcntl(sock, F_SETFL, O_NDELAY) != 0) return VFalse; #endif return VTrue;*/ } //////////////////////////// VBool VSocket::Listen() { return VFalse; /* // Check socket if (sock < 0) return VFalse; // Set it to listen if (listen(sock, 5) < 0) return VFalse; return VTrue;*/ } //////////////////////////// VSocket * VSocket::Accept() { return VFalse; /* const int one = 1; int new_socket_id; VSocket * new_socket; // Check this socket if (sock < 0) return NULL; // Accept an incoming connection if ((new_socket_id = (int)accept(sock, NULL, 0)) < 0) return NULL; // Create a new VSocket and return it new_socket = new VSocket; if (new_socket != NULL) { new_socket->sock = new_socket_id; } else { shutdown(new_socket_id, SD_BOTH); closesocket(new_socket_id); return NULL; } // Attempt to set the new socket's options setsockopt(new_socket->sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)); // Put the socket into non-blocking mode #ifdef __WIN32__ u_long arg = 1; if (ioctlsocket(new_socket->sock, FIONBIO, &arg) != 0) { delete new_socket; new_socket = NULL; } #else if (fcntl(new_socket->sock, F_SETFL, O_NDELAY) != 0) { delete new_socket; new_socket = NULL; } #endif return new_socket;*/ } //////////////////////////// VBool VSocket::TryAccept(VSocket **new_socket, long ms) { return VFalse; /* // Check this socket if (sock < 0) return NULL; struct fd_set fds; struct timeval tm; FD_ZERO(&fds); FD_SET((unsigned int)sock, &fds); tm.tv_sec = ms / 1000; tm.tv_usec = (ms % 1000) * 1000; int ready = select(sock + 1, &fds, NULL, NULL, &tm); if (ready == 0) { // Timeout *new_socket = NULL; return VTrue; } else if (ready != 1) { // Error return VFalse; } // Ready to accept new connection VSocket *s = Accept(); if (s == NULL) return VFalse; // Success *new_socket = s; return VTrue;*/ } //////////////////////////// VString VSocket::GetPeerName() { return ""; } //////////////////////////// VString VSocket::GetSockName() { return ""; } //////////////////////////// VCard32 VSocket::Resolve(VStringConst address) { VCard32 addr; // Try converting the address as IP addr = inet_addr(address); // Was it a valid IP address? if (addr == 0xffffffff) { // No, so get the actual IP address of the host name specified struct hostent *pHost; pHost = gethostbyname(address); if (pHost != NULL) { if (pHost->h_addr == NULL) return 0; addr = ((struct in_addr *)pHost->h_addr)->s_addr; } else return 0; } // Return the resolved IP address as an integer return addr; } //////////////////////////// VBool VSocket::SetTimeout(VCard32 secs) { //if (LOBYTE(winsockVersion) < 2) // return VFalse; int timeout=secs; if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR) { return VFalse; } if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR) { return VFalse; } return VTrue; } //////////////////////////// VInt VSocket::Send(const char *buff, const VCard bufflen) { errno = 0; VInt bytes = send(sock, buff, bufflen, 0); if (bytes < 0) { int wsa_error = WSAGetLastError(); #ifdef __WIN32__ if (wsa_error == WSAEWOULDBLOCK) errno = EWOULDBLOCK; #endif } return bytes; } //////////////////////////// VBool VSocket::SendExact(const char *buff, const VCard bufflen) { struct fd_set write_fds; struct timeval tm; int count; // Put the data into the queue SendQueued(buff, bufflen); while (out_queue) { // Wait until some data can be sent do { FD_ZERO(&write_fds); FD_SET((unsigned int)sock, &write_fds); tm.tv_sec = 1; tm.tv_usec = 0; count = select(sock + 1, NULL, &write_fds, NULL, &tm); } while (count == 0); if (count < 0 || count > 1) { return VFalse; } // Actually send some data if (FD_ISSET((unsigned int)sock, &write_fds)) { if (!SendFromQueue()) return VFalse; } } return VTrue; } //////////////////////////// VBool VSocket::SendQueued(const char *buff, const VCard bufflen) { omni_mutex_lock l(queue_lock); // Just append new bytes to the output queue if (!out_queue) { out_queue = new AIOBlock(bufflen, buff); bytes_sent = 0; } else { AIOBlock *last = out_queue; while (last->next) last = last->next; last->next = new AIOBlock(bufflen, buff); } return VTrue; } //////////////////////////// VBool VSocket::SendFromQueue() { omni_mutex_lock l(queue_lock); // Is there something to send? if (!out_queue) return VTrue; // Maximum data size to send at once size_t portion_size = out_queue->data_size - bytes_sent; if (portion_size > 32768) portion_size = 32768; // Try to send some data int bytes = Send(out_queue->data_ptr + bytes_sent, (VCard)portion_size); if (bytes > 0) { bytes_sent += bytes; } else if (bytes < 0 && errno != EWOULDBLOCK) { return VFalse; } // Remove block if all its data has been sent if (bytes_sent == out_queue->data_size) { AIOBlock *sent = out_queue; out_queue = sent->next; bytes_sent = 0; delete sent; } return VTrue; } //////////////////////////// VInt VSocket::Read(char *buff, const VCard bufflen) { errno = 0; VInt bytes = recv(sock, buff, bufflen, 0); #ifdef __WIN32__ if (bytes < 0 && WSAGetLastError() == WSAEWOULDBLOCK) errno = EWOULDBLOCK; #endif return bytes; } //////////////////////////// VBool VSocket::ReadExact(char *buff, const VCard bufflen) { int bytes; VCard currlen = bufflen; struct fd_set read_fds, write_fds; struct timeval tm; int count; while (currlen > 0) { // Wait until some data can be read or sent do { FD_ZERO(&read_fds); FD_SET((unsigned int)sock, &read_fds); FD_ZERO(&write_fds); if (out_queue) FD_SET((unsigned int)sock, &write_fds); tm.tv_sec = 0; tm.tv_usec = 50; count = select(sock + 1, &read_fds, &write_fds, NULL, &tm); } while (count == 0); if (count < 0 || count > 2) { return VFalse; } if (FD_ISSET((unsigned int)sock, &write_fds)) { // Try to send some data if (!SendFromQueue()) return VFalse; } if (FD_ISSET((unsigned int)sock, &read_fds)) { // Try to read some data in bytes = Read(buff, currlen); if (bytes > 0) { // Adjust the buffer position and size buff += bytes; currlen -= bytes; } else if (bytes < 0 && errno != EWOULDBLOCK) { return VFalse; } else if (bytes == 0) { return VFalse; } } } return VTrue; }