Path: blob/master/external/source/vncdll/winvnc/VSocket.cpp
24706 views
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.1// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.2//3// This file is part of the VNC system.4//5// The VNC system is free software; you can redistribute it and/or modify6// it under the terms of the GNU General Public License as published by7// the Free Software Foundation; either version 2 of the License, or8// (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,18// USA.19//20// TightVNC distribution homepage on the Web: http://www.tightvnc.com/21//22// If the source code for the VNC system is not available from the place23// whence you received this file, check http://www.uk.research.att.com/vnc or contact24// the authors on [email protected] for information on obtaining it.252627// VSocket.cpp2829// The VSocket class provides a platform-independent socket abstraction30// with the simple functionality required for an RFB server.3132class VSocket;3334////////////////////////////////////////////////////////35// System includes3637#include "stdhdrs.h"3839// Visual C++ .NET 2003 compatibility40#if (_MSC_VER>= 1300)41#include <iostream>42#else43#include <iostream.h>44#endif4546#include <stdio.h>47#ifdef __WIN32__48#include <io.h>49#include <winsock.h>50#else51#include <sys/types.h>52#include <sys/socket.h>53#include <arpa/inet.h>54#include <netinet/in.h>55#include <netdb.h>56#include <unistd.h>57#include <fcntl.h>58#include <errno.h>59#include <string.h>60#include <signal.h>61#endif62#include <sys/types.h>6364////////////////////////////////////////////////////////65// Custom includes6667#include "VTypes.h"6869////////////////////////////////////////////////////////70// *** Lovely hacks to make Win32 work. Hurrah!7172#if defined(__WIN32__) && !defined(EWOULDBLOCK)73#define EWOULDBLOCK WSAEWOULDBLOCK74#endif7576////////////////////////////////////////////////////////77// Socket implementation7879#include "VSocket.h"8081// The socket timeout value (currently 5 seconds, for no reason...)82// *** THIS IS NOT CURRENTLY USED ANYWHERE83const VInt rfbMaxClientWait = 5000;8485////////////////////////////86// Socket implementation initialisation8788static WORD winsockVersion = 0;8990VSocketSystem::VSocketSystem()91{92// Initialise the socket subsystem93// This is only provided for compatibility with Windows.9495#ifdef __WIN32__96// Initialise WinPoxySockets on Win3297WORD wVersionRequested;98WSADATA wsaData;99100wVersionRequested = MAKEWORD(2, 2);101if (WSAStartup(wVersionRequested, &wsaData) != 0)102{103m_status = VFalse;104return;105}106107winsockVersion = wsaData.wVersion;108109#else110// Disable the nasty read/write failure signals on UNIX111signal(SIGPIPE, SIG_IGN);112#endif113114// If successful, or if not required, then continue!115m_status = VTrue;116}117118VSocketSystem::~VSocketSystem()119{120/*if (m_status)121{122WSACleanup();123}*/124}125126////////////////////////////127128VSocket::VSocket()129{130// Clear out the internal socket fields131sock = -1;132hCloseEvent = NULL;133out_queue = NULL;134}135136VSocket::VSocket( WSAPROTOCOL_INFO * pSocketInfo, HANDLE hClose )137{138sock = (int)WSASocket( AF_INET, SOCK_STREAM, 0, pSocketInfo, 0, 0 );139if( sock == INVALID_SOCKET )140sock = -1;141//BREAK_ON_WSAERROR( "[VNCDLL] vncdll_run. WSASocketA failed" );142143// Clear out the internal socket fields144//sock = (int)socket;145hCloseEvent = hClose;146out_queue = NULL;147}148////////////////////////////149150VSocket::~VSocket()151{152// Close the socket153Close();154}155156////////////////////////////157158VBool159VSocket::Create()160{161const int one = 1;162163// Check that the old socket was closed164if (sock >= 0)165Close();166167// Create the socket168if ((sock = (int)socket(AF_INET, SOCK_STREAM, 0)) < 0)169{170return VFalse;171}172173// Set the socket options:174if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)))175{176return VFalse;177}178if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)))179{180return VFalse;181}182183return VTrue;184}185186////////////////////////////187188extern HANDLE hCloseEvent;189190VBool VSocket::Close()191{192if( sock >= 0 )193{194//shutdown(sock, SD_BOTH);195//closesocket(sock);196//CloseHandle( (HANDLE)sock );197sock = -1;198SetEvent( hCloseEvent );199}200201while (out_queue)202{203AIOBlock *next = out_queue->next;204delete out_queue;205out_queue = next;206}207208return VTrue;209}210211////////////////////////////212213VBool214VSocket::Shutdown()215{216/*if (sock >= 0)217{218shutdown(sock, SD_BOTH);219}*/220while (out_queue)221{222AIOBlock *next = out_queue->next;223delete out_queue;224out_queue = next;225}226227return VTrue;228}229230////////////////////////////231232VBool233VSocket::Bind(const VCard port, const VBool localOnly,234const VBool checkIfInUse)235{236return VFalse;237/*struct sockaddr_in addr;238239// Check that the socket is open!240if (sock < 0)241return VFalse;242243// If a specific port is being set then check it's not already used!244if (port != 0 && checkIfInUse)245{246VSocket dummy;247248if (dummy.Create())249{250// If we're able to connect then the port number is in use...251if (dummy.Connect("localhost", port))252return VFalse;253}254}255256// Set up the address to bind the socket to257addr.sin_family = AF_INET;258addr.sin_port = htons(port);259if (localOnly)260addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);261else262addr.sin_addr.s_addr = htonl(INADDR_ANY);263264// And do the binding265if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)266return VFalse;267268return VTrue;*/269}270271////////////////////////////272273VBool274VSocket::Connect(VStringConst address, const VCard port)275{276return VFalse;277/*278// Check the socket279if (sock < 0)280return VFalse;281282// Create an address structure and clear it283struct sockaddr_in addr;284memset(&addr, 0, sizeof(addr));285286// Fill in the address if possible287addr.sin_family = AF_INET;288addr.sin_addr.s_addr = inet_addr(address);289290// Was the string a valid IP address?291if (addr.sin_addr.s_addr == -1)292{293// No, so get the actual IP address of the host name specified294struct hostent *pHost;295pHost = gethostbyname(address);296if (pHost != NULL)297{298if (pHost->h_addr == NULL)299return VFalse;300addr.sin_addr.s_addr = ((struct in_addr *)pHost->h_addr)->s_addr;301}302else303return VFalse;304}305306// Set the port number in the correct format307addr.sin_port = htons(port);308309// Actually connect the socket310if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0)311return VFalse;312313// Put the socket into non-blocking mode314#ifdef __WIN32__315u_long arg = 1;316if (ioctlsocket(sock, FIONBIO, &arg) != 0)317return VFalse;318#else319if (fcntl(sock, F_SETFL, O_NDELAY) != 0)320return VFalse;321#endif322323return VTrue;*/324}325326////////////////////////////327328VBool329VSocket::Listen()330{331return VFalse;332/*333// Check socket334if (sock < 0)335return VFalse;336337// Set it to listen338if (listen(sock, 5) < 0)339return VFalse;340341return VTrue;*/342}343344////////////////////////////345346VSocket *347VSocket::Accept()348{349return VFalse;350/*351const int one = 1;352353int new_socket_id;354VSocket * new_socket;355356// Check this socket357if (sock < 0)358return NULL;359360// Accept an incoming connection361if ((new_socket_id = (int)accept(sock, NULL, 0)) < 0)362return NULL;363364// Create a new VSocket and return it365new_socket = new VSocket;366if (new_socket != NULL)367{368new_socket->sock = new_socket_id;369}370else371{372shutdown(new_socket_id, SD_BOTH);373closesocket(new_socket_id);374return NULL;375}376377// Attempt to set the new socket's options378setsockopt(new_socket->sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));379380// Put the socket into non-blocking mode381#ifdef __WIN32__382u_long arg = 1;383if (ioctlsocket(new_socket->sock, FIONBIO, &arg) != 0) {384delete new_socket;385new_socket = NULL;386}387#else388if (fcntl(new_socket->sock, F_SETFL, O_NDELAY) != 0) {389delete new_socket;390new_socket = NULL;391}392#endif393394return new_socket;*/395}396397////////////////////////////398399VBool400VSocket::TryAccept(VSocket **new_socket, long ms)401{402return VFalse;403/*404// Check this socket405if (sock < 0)406return NULL;407408struct fd_set fds;409struct timeval tm;410FD_ZERO(&fds);411FD_SET((unsigned int)sock, &fds);412tm.tv_sec = ms / 1000;413tm.tv_usec = (ms % 1000) * 1000;414int ready = select(sock + 1, &fds, NULL, NULL, &tm);415if (ready == 0) {416// Timeout417*new_socket = NULL;418return VTrue;419} else if (ready != 1) {420// Error421return VFalse;422}423// Ready to accept new connection424VSocket *s = Accept();425if (s == NULL)426return VFalse;427// Success428*new_socket = s;429return VTrue;*/430}431432////////////////////////////433434VString VSocket::GetPeerName()435{436return "<unavailable>";437}438439////////////////////////////440441VString VSocket::GetSockName()442{443return "<unavailable>";444}445446////////////////////////////447448VCard32449VSocket::Resolve(VStringConst address)450{451VCard32 addr;452453// Try converting the address as IP454addr = inet_addr(address);455456// Was it a valid IP address?457if (addr == 0xffffffff)458{459// No, so get the actual IP address of the host name specified460struct hostent *pHost;461pHost = gethostbyname(address);462if (pHost != NULL)463{464if (pHost->h_addr == NULL)465return 0;466addr = ((struct in_addr *)pHost->h_addr)->s_addr;467}468else469return 0;470}471472// Return the resolved IP address as an integer473return addr;474}475476////////////////////////////477478VBool479VSocket::SetTimeout(VCard32 secs)480{481//if (LOBYTE(winsockVersion) < 2)482// return VFalse;483int timeout=secs;484if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR)485{486return VFalse;487}488if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR)489{490return VFalse;491}492return VTrue;493}494495////////////////////////////496497VInt VSocket::Send(const char *buff, const VCard bufflen)498{499errno = 0;500501VInt bytes = send(sock, buff, bufflen, 0);502if (bytes < 0)503{504int wsa_error = WSAGetLastError();505#ifdef __WIN32__506if (wsa_error == WSAEWOULDBLOCK)507errno = EWOULDBLOCK;508#endif509}510511return bytes;512}513514////////////////////////////515516VBool517VSocket::SendExact(const char *buff, const VCard bufflen)518{519struct fd_set write_fds;520struct timeval tm;521int count;522523// Put the data into the queue524SendQueued(buff, bufflen);525526while (out_queue) {527// Wait until some data can be sent528do {529FD_ZERO(&write_fds);530FD_SET((unsigned int)sock, &write_fds);531tm.tv_sec = 1;532tm.tv_usec = 0;533count = select(sock + 1, NULL, &write_fds, NULL, &tm);534} while (count == 0);535if (count < 0 || count > 1) {536return VFalse;537}538// Actually send some data539if (FD_ISSET((unsigned int)sock, &write_fds)) {540if (!SendFromQueue())541return VFalse;542}543}544545return VTrue;546}547548////////////////////////////549550VBool551VSocket::SendQueued(const char *buff, const VCard bufflen)552{553omni_mutex_lock l(queue_lock);554555// Just append new bytes to the output queue556if (!out_queue) {557out_queue = new AIOBlock(bufflen, buff);558bytes_sent = 0;559} else {560AIOBlock *last = out_queue;561while (last->next)562last = last->next;563last->next = new AIOBlock(bufflen, buff);564}565566return VTrue;567}568569////////////////////////////570571VBool572VSocket::SendFromQueue()573{574omni_mutex_lock l(queue_lock);575576// Is there something to send?577if (!out_queue)578return VTrue;579580// Maximum data size to send at once581size_t portion_size = out_queue->data_size - bytes_sent;582if (portion_size > 32768)583portion_size = 32768;584585// Try to send some data586int bytes = Send(out_queue->data_ptr + bytes_sent, (VCard)portion_size);587if (bytes > 0) {588bytes_sent += bytes;589} else if (bytes < 0 && errno != EWOULDBLOCK) {590return VFalse;591}592593// Remove block if all its data has been sent594if (bytes_sent == out_queue->data_size) {595AIOBlock *sent = out_queue;596out_queue = sent->next;597bytes_sent = 0;598delete sent;599}600601return VTrue;602}603604////////////////////////////605606VInt607VSocket::Read(char *buff, const VCard bufflen)608{609errno = 0;610611VInt bytes = recv(sock, buff, bufflen, 0);612613#ifdef __WIN32__614if (bytes < 0 && WSAGetLastError() == WSAEWOULDBLOCK)615errno = EWOULDBLOCK;616#endif617618return bytes;619}620621////////////////////////////622623VBool624VSocket::ReadExact(char *buff, const VCard bufflen)625{626int bytes;627VCard currlen = bufflen;628struct fd_set read_fds, write_fds;629struct timeval tm;630int count;631632while (currlen > 0) {633// Wait until some data can be read or sent634do {635FD_ZERO(&read_fds);636FD_SET((unsigned int)sock, &read_fds);637FD_ZERO(&write_fds);638if (out_queue)639FD_SET((unsigned int)sock, &write_fds);640tm.tv_sec = 0;641tm.tv_usec = 50;642count = select(sock + 1, &read_fds, &write_fds, NULL, &tm);643} while (count == 0);644if (count < 0 || count > 2) {645return VFalse;646}647if (FD_ISSET((unsigned int)sock, &write_fds)) {648// Try to send some data649if (!SendFromQueue())650return VFalse;651}652if (FD_ISSET((unsigned int)sock, &read_fds)) {653// Try to read some data in654bytes = Read(buff, currlen);655if (bytes > 0) {656// Adjust the buffer position and size657buff += bytes;658currlen -= bytes;659} else if (bytes < 0 && errno != EWOULDBLOCK) {660return VFalse;661} else if (bytes == 0) {662return VFalse;663}664}665}666667return VTrue;668}669670671672