--- vnc-4.0b5-unixsrc/rfb/SConnection.cxx.managed 2004-06-18 10:59:02.988470250 +0100 +++ vnc-4.0b5-unixsrc/rfb/SConnection.cxx 2004-06-18 11:12:50.863599682 +0100 @@ -99,6 +99,29 @@ state_ = RFBSTATE_PROTOCOL_VERSION; } +void SConnection::initialiseProtocol(ConnParams* params) +{ + cp.majorVersion = params->majorVersion; + cp.minorVersion = params->minorVersion; + versionReceived(); + + /* FIXME: check that the width and height are the same as ours + * and send a DesktopSize update if needed + * Hmm, only do it if the client supports the DesktopSize + * encoding .. but what the hell do we do if it doesn't? + */ + cp.width = params->width; + cp.height = params->height; + + cp.setPF(params->pf()); + state_ = RFBSTATE_NORMAL; + + reader_ = new SMsgReaderV3(this, is); + writer_ = new SMsgWriterV3(&cp, os); + + // framebufferUpdateRequest(Rect(0, 0, cp.width, cp.height), false); +} + void SConnection::processMsg() { switch (state_) { --- vnc-4.0b5-unixsrc/rfb/VNCSConnectionST.h.managed 2004-05-18 17:16:52.000000000 +0100 +++ vnc-4.0b5-unixsrc/rfb/VNCSConnectionST.h 2004-06-18 11:12:50.999578657 +0100 @@ -50,10 +50,19 @@ // returns false, and close() will have been called. bool init(); + // a variant of init for an already initialised protocol stream. + // ConnParams contains the state of the initialised stream + bool init(ConnParams* params); + // close() shuts down the socket to the client and deletes the // SConnectionST object. void close(const char* reason); + // Syncs the client's state. The server should immediately stop processing + // messages from the client and complete any outstanding replies. All + // protocol stream state is flushed. + void sync() { /* FIXME: implement */ }; + // processMessages() processes incoming messages from the client, invoking // various callbacks as a result. It continues to process messages until // reading might block. Returns true if the client is still valid & @@ -103,6 +112,10 @@ void approveConnectionOrClose(bool accept, const char* reason); + int getID() { return cnx_id; } + + virtual void framebufferUpdateRequest(const Rect& r, bool incremental); + private: // SConnection callbacks @@ -118,7 +131,6 @@ virtual void setPixelFormat(const PixelFormat& pf); virtual void pointerEvent(int x, int y, int buttonMask); virtual void keyEvent(rdr::U32 key, bool down); - virtual void framebufferUpdateRequest(const Rect& r, bool incremental); virtual void clientCutText(const char* str, int len); virtual void setInitialColourMap(); virtual void supportsLocalCursor(); @@ -163,6 +175,10 @@ AccessRights accessRights; CharArray closeReason; + + /* allocate each client an id */ + int cnx_id; + static int last_cnx_id; }; } #endif --- vnc-4.0b5-unixsrc/rfb/HTTPServer.cxx.managed 2004-05-18 17:16:51.000000000 +0100 +++ vnc-4.0b5-unixsrc/rfb/HTTPServer.cxx 2004-06-18 11:12:50.826605402 +0100 @@ -300,7 +300,7 @@ // -=- SocketServer interface implementation -void +int HTTPServer::addClient(network::Socket* sock) { Session* s = new Session(*sock, *this); if (!s) { @@ -310,6 +310,9 @@ sock->outStream().setTimeout(rfb::Server::clientWaitTimeMillis); sessions.push_front(s); } + + /* FIXME: lame */ + return 0; } bool --- vnc-4.0b5-unixsrc/rfb/VNCServerST.h.managed 2004-05-18 17:16:52.000000000 +0100 +++ vnc-4.0b5-unixsrc/rfb/VNCServerST.h 2004-06-18 11:12:51.035573091 +0100 @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace rfb { @@ -57,7 +58,7 @@ // protocol. // NB: The server assumes ownership of the Socket object. - virtual void addClient(network::Socket* sock); + virtual int addClient(network::Socket* sock); // - Process an input event on a particular Socket // The platform-specific side of the server implementation calls @@ -108,8 +109,29 @@ // a listening client. Reverse connections are not authenticated and are // always shared (unless the NeverShared parameter is set). - void addClient(network::Socket* sock, bool reverse); + int addClient(network::Socket* sock, bool reverse); + // addClient() with an extra parameter which contains the state of an + // already initialised protocol stream + + int addClient(network::Socket* sock, ConnParams* params); + + // Syncs and returns a given client's state. The server will immediately + // stop processing messages from the client and complete any outstanding + // replies. All protocol stream state is flushed. Returns the connection + // paramaters for the given client. + ConnParams* syncClient(int client_id); + + // Close a particular VNCSConnection as specified by the client_id + // returned by addClient() + + void closeClient(int client_id, const char *reason); + + // processSocketEvent() with an extra arg to return the client's ID + // If the socket is associated with a particular client connection, + // and then clientID will contain the ID of that client + + virtual bool processSocketEvent(network::Socket* sock, int* client_id); // getSockets() gets a list of sockets. This can be used to generate an // fd_set for calling select(). --- vnc-4.0b5-unixsrc/rfb/VNCServerST.cxx.managed 2004-05-18 17:16:52.000000000 +0100 +++ vnc-4.0b5-unixsrc/rfb/VNCServerST.cxx 2004-06-18 11:12:51.001578347 +0100 @@ -114,12 +114,12 @@ // SocketServer methods -void VNCServerST::addClient(network::Socket* sock) +int VNCServerST::addClient(network::Socket* sock) { - addClient(sock, false); + return addClient(sock, false); } -void VNCServerST::addClient(network::Socket* sock, bool reverse) +int VNCServerST::addClient(network::Socket* sock, bool reverse) { // - Check the connection isn't black-marked // *** do this in getSecurity instead? @@ -134,7 +134,7 @@ } sock->shutdown(); closingSockets.push_back(sock); - return; + return -1; } VNCSConnectionST* client = new VNCSConnectionST(this, sock, reverse); @@ -142,16 +142,43 @@ if (!client->init()) { // client->init() has already shutdown() the socket closingSockets.push_back(sock); - return; + return -1; } + + return client->getID(); +} + +int VNCServerST::addClient(network::Socket* sock, ConnParams* params) +{ + VNCSConnectionST* client = new VNCSConnectionST(this, sock, false); + + if (!client->init(params)) { + // client->init() has already shutdown() the socket + closingSockets.push_back(sock); + return -1; + } + + client->pixelBufferChange(); + client->framebufferUpdateRequest(Rect(0, 0, params->width, params->height), false); + + return client->getID(); } bool VNCServerST::processSocketEvent(network::Socket* sock) { + return processSocketEvent(sock, NULL); +} + +bool VNCServerST::processSocketEvent(network::Socket* sock, int *client_id) +{ + if (client_id) + *client_id = 0; // - Find the appropriate VNCSConnectionST and process the event std::list::iterator ci; for (ci = clients.begin(); ci != clients.end(); ci++) { if ((*ci)->getSock() == sock) { + if (client_id) + *client_id = (*ci)->getID(); if ((*ci)->processMessages()) return true; // processMessages failed, so delete the client @@ -324,6 +351,34 @@ } } +ConnParams* VNCServerST::syncClient(int client_id) +{ + std::list::iterator i, next_i; + for (i=clients.begin(); i!=clients.end(); i=next_i) { + next_i = i; next_i++; + if ((*i)->getID() == client_id) { + (*i)->sync(); + return &(*i)->cp; + } + } + return 0; +} + +void VNCServerST::closeClient(int client_id, const char* reason) +{ + std::list::iterator i, next_i; + for (i=clients.begin(); i!=clients.end(); i=next_i) { + next_i = i; next_i++; + if ((*i)->getID() == client_id) { + // FIXME: this is wrong + network::Socket* sock = (*i)->getSock(); + (*i)->close(reason); + delete *(i); + delete sock; + } + } +} + void VNCServerST::getSockets(std::list* sockets) { sockets->clear(); --- vnc-4.0b5-unixsrc/rfb/HTTPServer.h.managed 2004-05-18 17:16:51.000000000 +0100 +++ vnc-4.0b5-unixsrc/rfb/HTTPServer.h 2004-06-18 11:12:50.827605247 +0100 @@ -31,7 +31,7 @@ #include #include #include -#include +#include namespace rfb { @@ -53,7 +53,7 @@ // supplied socket. // The socket will be closed if protocol initialisation // fails. - virtual void addClient(network::Socket* sock); + virtual int addClient(network::Socket* sock); // -=- Event processing methods --- vnc-4.0b5-unixsrc/rfb/VNCSConnectionST.cxx.managed 2004-06-18 10:59:03.126448977 +0100 +++ vnc-4.0b5-unixsrc/rfb/VNCSConnectionST.cxx 2004-06-18 11:12:50.934588705 +0100 @@ -27,6 +27,7 @@ using namespace rfb; +int VNCSConnectionST::last_cnx_id = 0; static LogWriter vlog("VNCSConnST"); VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, @@ -65,6 +66,8 @@ } #endif + cnx_id = ++last_cnx_id; + server->clients.push_front(this); } @@ -89,6 +92,17 @@ // Methods called from VNCServerST +bool VNCSConnectionST::init(ConnParams* params) +{ + try { + initialiseProtocol(params); + } catch (rdr::Exception& e) { + close(e.str()); + return false; + } + return true; +} + bool VNCSConnectionST::init() { try { --- vnc-4.0b5-unixsrc/rfb/SConnection.h.managed 2004-06-18 10:59:03.093454064 +0100 +++ vnc-4.0b5-unixsrc/rfb/SConnection.h 2004-06-18 11:12:50.898594271 +0100 @@ -62,6 +62,10 @@ // there is data to read on the InStream. void initialiseProtocol(); + // a variant of initialiseProtocol() for an already initialised protocol + // stream. ConnParams contains the state of the initialised stream + void initialiseProtocol(ConnParams* params); + // processMsg() should be called whenever there is data to read on the // InStream. You must have called initialiseProtocol() first. void processMsg(); --- vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/XserverDesktop.cc.managed 2004-06-18 10:53:00.459693046 +0100 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/XserverDesktop.cc 2004-06-18 11:12:51.072567371 +0100 @@ -34,6 +34,7 @@ #include #include #include "XserverDesktop.h" +#include "XvncManager.h" #include "vncExtInit.h" extern "C" { @@ -130,10 +131,11 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, network::TcpListener* listener_, network::TcpListener* httpListener_, + int managerFd, const char* name, void* fbptr) : pScreen(pScreen_), deferredUpdateTimer(0), dummyTimer(0), server(0), httpServer(0), - listener(listener_), httpListener(httpListener_), + listener(listener_), httpListener(httpListener_), manager(0), cmap(0), deferredUpdateTimerSet(false), grabbing(false), ignoreHooks_(false), directFbptr(fbptr != 0), oldButtonMask(0), cursorX(0), cursorY(0), @@ -189,6 +191,11 @@ if (httpListener) httpServer = new MyHTTPServer(this); + + if (managerFd != -1) { + manager = new XvncManager (managerFd, this); + manager->sendDisplay(display); + } } XserverDesktop::~XserverDesktop() @@ -467,6 +474,8 @@ FD_SET(listener->getFd(), fds); if (httpListener) FD_SET(httpListener->getFd(), fds); + if (manager) + FD_SET(manager->getFd(), fds); std::list sockets; server->getSockets(&sockets); @@ -498,7 +507,7 @@ if (FD_ISSET(listener->getFd(), fds)) { FD_CLR(listener->getFd(), fds); Socket* sock = listener->accept(); - server->addClient(sock); + addClient(sock, false); vlog.debug("new client, sock %d",sock->getFd()); } } @@ -512,16 +521,27 @@ } } + if (manager) { + if (FD_ISSET(manager->getFd(), fds)) { + FD_CLR(manager->getFd(), fds); + manager->processMessages(); + } + } + std::list sockets; server->getSockets(&sockets); std::list::iterator i; for (i = sockets.begin(); i != sockets.end(); i++) { int fd = (*i)->getFd(); if (FD_ISSET(fd, fds)) { + int client_id; FD_CLR(fd, fds); - if (!server->processSocketEvent(*i)) { + if (!server->processSocketEvent(*i, &client_id)) { vlog.debug("client gone, sock %d",fd); - vncClientGone(fd); + if (!manager) + vncClientGone(fd); + else + manager->sendClientGone(client_id); } } } @@ -556,8 +576,41 @@ void XserverDesktop::addClient(Socket* sock, bool reverse) { - vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse); - server->addClient(sock, reverse); + int id; + + if ((id = server->addClient(sock, reverse)) == -1) { + vlog.error("failed to add new client with sock %d", sock->getFd()); + return; + } + if (manager) + manager->sendNewClient(id); + + vlog.debug("new client (%d), sock %d reverse %d", id, sock->getFd(), reverse); +} + +void XserverDesktop::addClient(Socket* sock, ConnParams* params) +{ + int id; + + if ((id = server->addClient(sock, params)) == -1) { + vlog.error("failed to add initialised client with sock %d", sock->getFd()); + return; + } + + if (manager) + manager->sendNewClient(id); + + vlog.debug("new initialised client (%d), sock %d", id, sock->getFd()); +} + +ConnParams* XserverDesktop::syncClient(int client_id) +{ + return server->syncClient(client_id); +} + +void XserverDesktop::disconnectClient(int client_id, const char *reason) +{ + server->closeClient(client_id, reason); } void XserverDesktop::disconnectClients() --- vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/XserverDesktop.h.managed 2004-03-18 17:37:37.000000000 +0000 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/XserverDesktop.h 2004-06-18 11:12:51.106562115 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include extern "C" { @@ -40,6 +41,7 @@ namespace network { class TcpListener; class Socket; } class MyHTTPServer; +class XvncManager; class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, public rfb::ColourMap, public rdr::Substitutor { @@ -47,6 +49,7 @@ XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener, network::TcpListener* httpListener_, + int managerFd, const char* name, void* fbptr); virtual ~XserverDesktop(); @@ -64,6 +67,9 @@ void blockHandler(fd_set* fds); void wakeupHandler(fd_set* fds, int nfds); void addClient(network::Socket* sock, bool reverse); + void addClient(network::Socket* sock, rfb::ConnParams* params); + rfb::ConnParams* syncClient(int client_id); + void disconnectClient(int client_id, const char *reason); void disconnectClients(); // rfb::SDesktop callbacks @@ -91,6 +97,7 @@ MyHTTPServer* httpServer; network::TcpListener* listener; network::TcpListener* httpListener; + XvncManager* manager; ColormapPtr cmap; bool deferredUpdateTimerSet; bool grabbing; --- /dev/null 2004-02-23 21:02:56.000000000 +0000 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/XvncManager.h 2004-06-18 11:12:51.143556394 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2004 Red Hat Inc. + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __XVNCMANAGER_H__ +#define __XVNCMANAGER_H__ + +#include +#include "XserverDesktop.h" +#include + +class XvncManager +{ + public: + + XvncManager (int fd, XserverDesktop *s); + virtual ~XvncManager (); + + int getFd() { return sockfd; } + void sendDisplay (const char *display); + void sendNewClient (int client_id); + void sendClientGone (int client_id); + void processMessages (); + + private: + + void sendMessage (const char *format, ...); + void sendClientStateStart (int client_id); + void sendClientStateEnd (); + void sendRfbVersion (int majorVersion, int minorVersion); + void sendEncodings (int nEncodings, const rdr::U32* encodings); + void sendPixelFormat (const rfb::PixelFormat& pf); + void sendGeometry (int width, int height); + void sendColorMapEntries (); + + void endClient (int client_id); + char *readMessage (); + + int sockfd; + XserverDesktop *server; + char buffer[256]; + char *buf_current; + char *buf_end; + std::list ancillary_fds; + bool reading_state; + rfb::ConnParams cp; + + struct + { + int depth; + int bpp; + + bool big_endian; + bool true_colour; + + unsigned long red_mask; + unsigned long green_mask; + unsigned long blue_mask; + } s; +}; + +#endif /* __XVNCMANAGER_H__ */ --- vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/Xvnc/xvnc.cc.managed 2004-03-18 17:37:37.000000000 +0000 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/Xvnc/xvnc.cc 2004-06-18 11:12:51.215545263 +0100 @@ -235,6 +235,7 @@ ErrorF("-depth D set screen 0's depth\n"); ErrorF("-pixelformat fmt set pixel format (rgbNNN or bgrNNN)\n"); ErrorF("-inetd has been launched from inetd\n"); + ErrorF("-managed is being managed by a display manager\n"); ErrorF("\nVNC parameters:\n"); fprintf(stderr,"\n" @@ -265,6 +266,24 @@ return true; } +static bool displayNumFromSock(int sock) +{ + int port = network::TcpSocket::getSockPort(sock); + int displayNum = port - 5900; + if (displayNum < 0 || displayNum > 99 || !displayNumFree(displayNum)) { + for (displayNum = 1; displayNum < 100; displayNum++) + if (displayNumFree(displayNum)) break; + + if (displayNum == 100) + return false; + } + + display = displayNumStr; + sprintf(displayNumStr, "%d", displayNum); + + return true; +} + int ddxProcessArgument(int argc, char *argv[], int i) { static Bool firstTime = TRUE; @@ -447,25 +466,36 @@ if (strcmp(argv[i], "-inetd") == 0) { + if (vncInetdSock != -1) { + ErrorF("-inetd may not be used with -managed"); + UseMsg(); + } + dup2(0,3); vncInetdSock = 3; close(2); - if (!displaySpecified) { - int port = network::TcpSocket::getSockPort(vncInetdSock); - int displayNum = port - 5900; - if (displayNum < 0 || displayNum > 99 || !displayNumFree(displayNum)) { - for (displayNum = 1; displayNum < 100; displayNum++) - if (displayNumFree(displayNum)) break; - - if (displayNum == 100) - FatalError("Xvnc error: no free display number for -inetd"); - } + if (!displaySpecified && !displayNumFromSock(vncInetdSock)) + FatalError("Xvnc error: no free display number for -inetd"); + + return 1; + } - display = displayNumStr; - sprintf(displayNumStr, "%d", displayNum); + if (strcmp(argv[i], "-managed") == 0) + { + if (vncInetdSock != -1) { + ErrorF("-managed may not be used with -inetd"); + UseMsg(); } + dup2(0,3); + vncInetdSock = 3; + dup2(1,4); + managerSock = 4; + + if (!displaySpecified && !displayNumFromSock(vncInetdSock)) + FatalError("Xvnc error: no free display number for -managed"); + return 1; } --- /dev/null 2004-02-23 21:02:56.000000000 +0000 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/XvncManager.cc 2004-06-18 11:12:51.142556549 +0100 @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2004 Red Hat Inc. + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "XvncManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static rfb::LogWriter vlog ("XvncManager"); + +XvncManager::XvncManager(int fd, XserverDesktop* s) + : sockfd (fd), + buf_current (buffer), buf_end (buffer + sizeof (buffer)), + server (s) +{ + if (fcntl (sockfd, F_SETFL, O_NONBLOCK) < 0) + { + FatalError ("Unable to make socket non-blocking: %s", strerror (errno)); + } + + /* FIXME: hack */ + { + rdr::U32 encodings[] = { rfb::encodingRaw }; + cp.setEncodings (1, encodings); + } + + /* FIXME: initialize the rest of the members */ +} + +XvncManager::~XvncManager() +{ + std::list::iterator iter; + + for (iter = ancillary_fds.begin (); iter != ancillary_fds.end (); iter++) + close (*iter); + + close (sockfd); +} + +void +XvncManager::sendMessage (const char *format, ...) +{ +#define BUF_SIZE 256 + char tmp [BUF_SIZE], *msg, *freeme = NULL; + va_list args; + int len; + + va_start (args, format); + + if ((len = vsnprintf (tmp, BUF_SIZE, format, args)) >= BUF_SIZE) + { + freeme = msg = new char [len + 1]; + vsnprintf (msg, len + 1, format, args); + } + else + { + msg = tmp; + } + + va_end (args); + + while (len > 0) + { + int n; + + if ((n = write (sockfd, msg, len)) == -1) + { + if (errno = EINTR || errno == EAGAIN) + continue; + + FatalError ("Error writing to manager socket: %s\n", + strerror (errno)); + GiveUp(0); + } + + len -= n; + msg += n; + } + + if (freeme) + delete msg; + +#undef BUF_SIZE +} + +void +XvncManager::sendDisplay (const char *display) +{ + sendMessage ("DISPLAY=%s\n", display); +} + +void +XvncManager::sendNewClient (int client_id) +{ + sendMessage ("CLIENT=%d\n", client_id); +} + +void +XvncManager::sendClientGone (int client_id) +{ + sendMessage ("CLIENT GONE=%d\n", client_id); +} + +void +XvncManager::sendClientStateStart (int client_id) +{ + sendMessage ("CLIENT STATE START=%d\n", client_id); +} + +void +XvncManager::sendClientStateEnd () +{ + sendMessage ("CLIENT STATE END\n"); +} + +void +XvncManager::sendRfbVersion (int majorVersion, + int minorVersion) +{ + sendMessage ("RFB VERSION=%d.%d\n", majorVersion, minorVersion); +} + +void +XvncManager::sendEncodings (int nEncodings, + const rdr::U32 *encodings) +{ + /* FIXME: implement */ +} + +void +XvncManager::sendPixelFormat (const rfb::PixelFormat &pf) +{ + sendMessage ("PIXEL FORMAT=%d,%d,%d,%d,0x%lx,0x%lx,0x%lx\n", + pf.bpp, pf.depth, + pf.bigEndian ? 1 : 0, + pf.trueColour ? 1 : 0, + (unsigned long) pf.redMax << pf.redShift, + (unsigned long) pf.greenMax << pf.greenShift, + (unsigned long) pf.blueMax << pf.blueShift); +} + +void +XvncManager::sendGeometry (int width, + int height) +{ + sendMessage ("GEOMETRY=%d,%d\n", width, height); +} + +void +XvncManager::sendColorMapEntries () +{ + /* FIXME: implement */ +} + +void +XvncManager::endClient (int client_id) +{ + rfb::ConnParams *cp; + + cp = server->syncClient (client_id); + if (cp) + { + sendClientStateStart (client_id); + sendRfbVersion (cp->majorVersion, cp->minorVersion); + sendGeometry (cp->width, cp->height); + sendPixelFormat (cp->pf ()); + sendEncodings (cp->nEncodings (), cp->encodings ()); + sendColorMapEntries (); + sendClientStateEnd (); + } + + server->disconnectClient (client_id, "Received END CLIENT from manager"); + + // FIXME: this is cheating + sendClientGone (client_id); +} + +char * +XvncManager::readMessage () +{ + union + { + struct cmsghdr cmsg; + char control [CMSG_SPACE (sizeof (int))]; + } msg_control; + struct msghdr msg; + struct iovec iov [1]; + struct cmsghdr *cmsg; + + iov [0].iov_base = buf_current; + iov [0].iov_len = buf_end - buf_current; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof (msg_control); + + try_again: + int n; + while ((n = recvmsg (sockfd, &msg, 0)) > 0) + { + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) + if (cmsg->cmsg_len == CMSG_LEN (sizeof (int)) && + cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) + { + ancillary_fds.push_back (*((int *) CMSG_DATA (cmsg))); + vlog.debug("Read fd %d from ancillary data\n", + ancillary_fds.back()); + } + + buf_current += n; + *buf_current = '\0'; + + if (buf_current == buf_end) + break; + + iov [0].iov_base = buf_current; + iov [0].iov_len = buf_end - buf_current - 1;; + msg.msg_flags = 0; + } + + if (n == -1 && errno == EINTR) + goto try_again; + + if (n = 0 || (n < 0 && errno != EAGAIN)) + { + if (n == 0) + { + vlog.debug ("Got EOF from manager ... exiting"); + GiveUp(0); + } + else + { + FatalError ("Error on manager socket: %s\n", + strerror (errno)); + } + } + + char *p; + if (!(p = strstr (buffer, "\n"))) + return NULL; + *p = '\0'; + + char *retval = new char [strlen (buffer) + 1]; + strcpy (retval, buffer); + + memmove (buffer, p + 1, buf_current - p); + buf_current -= p - buffer + 1; + + return retval; +} + +void +XvncManager::processMessages () +{ + char *message; + + while ((message = readMessage ())) + { + if (!strncmp (message, "END CLIENT=", strlen("END CLIENT="))) + { + int client_id; + + if (sscanf (message, "END CLIENT=%d", &client_id) == 1) + { + vlog.debug ("Got END CLIENT for client ID %d", client_id); + endClient (client_id); + } + else + { + vlog.error ("Incorrect END CLIENT format from VNC server: '%s'", message); + } + } + else if (!strcmp (message, "CLIENT STATE START")) + { + vlog.debug ("Got CLIENT STATE START"); + reading_state = true; + } + else if (!strcmp (message, "CLIENT STATE END")) + { + vlog.debug ("Got CLIENT STATE END"); + reading_state = false; + } + else if (!strncmp (message, "RFB VERSION=", strlen ("RFB VERSION="))) + { + int majorVersion, minorVersion; + + if (sscanf (message, "RFB VERSION=%d.%d", &majorVersion, &minorVersion) == 2) + { + vlog.debug ("Got RFB VERSION: %d.%d", majorVersion, minorVersion); + if (reading_state) + { + cp.majorVersion = majorVersion; + cp.minorVersion = minorVersion; + } + } + else + { + vlog.error ("Incorrect RFB VERSION format from VNC server: '%s'", message); + } + } + else if (!strncmp (message, "GEOMETRY=", strlen ("GEOMETRY="))) + { + int width, height; + + if (sscanf (message, "GEOMETRY=%d,%d", &width, &height) == 2) + { + vlog.debug ("Got GEOMETRY: %dx%d", width, height); + if (reading_state) + { + cp.width = width; + cp.height = height; + } + } + else + { + vlog.error ("Incorrect GEOMETRY format from VNC server: '%s'", message); + } + } + else if (!strncmp (message, "PIXEL FORMAT=", strlen ("PIXEL FORMAT="))) + { + int depth, bpp; + int big_endian, true_colour; + unsigned long red_mask, green_mask, blue_mask; + + if (sscanf (message, "PIXEL FORMAT=%d,%d,%d,%d,0x%lx,0x%lx,0x%lx", + &depth, &bpp, &big_endian, &true_colour, + &red_mask, &green_mask, &blue_mask) == 7) + { + vlog.debug ("Got PIXEL FORMAT: bpp=%d, depth=%d, bigEndian=%d, trueColour=%d, " + "red=0x%lx, green=0x%lx, blue=0x%lx", + depth, bpp, big_endian, true_colour, red_mask, green_mask, blue_mask); + if (reading_state) + { + int red_max, green_max, blue_max; + int red_shift, green_shift, blue_shift; + + red_shift = ffs (red_mask) - 1; + green_shift = ffs (green_mask) - 1; + blue_shift = ffs (blue_mask) - 1; + red_max = red_mask >> red_shift; + green_max = green_mask >> green_shift; + blue_max = blue_mask >> blue_shift; + + rfb::PixelFormat pf (depth, bpp, big_endian, true_colour, + red_max, green_max, blue_max, + red_shift, green_shift, blue_shift); + cp.setPF (pf); + } + } + else + { + vlog.error ("Incorrect PIXEL FORMAT format from VNC server: '%s'", message); + } + } + else if (!strcmp (message, "NEW CLIENT")) + { + vlog.debug ("Got NEW CLIENT"); + + if (!ancillary_fds.empty ()) + { + network::Socket* sock; + + vlog.debug ("Got fd = %d with NEW CLIENT", ancillary_fds.front ()); + + sock = new network::TcpSocket (ancillary_fds.front ()); + ancillary_fds.pop_front (); + + server->addClient (sock, &cp); + } + else + { + vlog.error ("No descriptor in ancillary data of NEW CLIENT"); + } + + } + else + { + vlog.error ("Unknown message from manager '%s'", message); + } + + delete message; + } +} --- vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/module/Imakefile.managed 2004-06-18 10:52:59.835790067 +0100 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/module/Imakefile 2004-06-18 11:12:51.250539852 +0100 @@ -8,8 +8,8 @@ #define IHaveModules #include - SRCS = vncExtInit.cc vncHooks.cc xf86vncModule.cc XserverDesktop.cc - OBJS = vncExtInit.o vncHooks.o xf86vncModule.o XserverDesktop.o + SRCS = vncExtInit.cc vncHooks.cc xf86vncModule.cc XserverDesktop.cc XvncManager.cc + OBJS = vncExtInit.o vncHooks.o xf86vncModule.o XserverDesktop.o XvncManager.o INCLUDES = -I.. -I../../include -I$(EXTINCSRC) -I$(XINCLUDESRC) \ -I$(FONTINCSRC) -I$(XF86COMSRC) \ $(VNCINCLUDE) @@ -19,6 +19,7 @@ LinkSourceFile(vncHooks.cc,..) LinkSourceFile(xf86vncModule.cc,..) LinkSourceFile(XserverDesktop.cc,..) +LinkSourceFile(XvncManager.cc,..) .CCsuf.Osuf: NormalSharedLibObjCplusplusCompile($(_NOOP_)) --- vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/vncExtInit.h.managed 2003-07-25 11:02:29.000000000 +0100 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/vncExtInit.h 2004-06-18 11:12:51.214545418 +0100 @@ -25,6 +25,7 @@ extern void vncBell(); extern void* vncFbptr[]; extern int vncInetdSock; +extern int managerSock; extern rfb::StringParameter httpDir; #endif --- vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/vncExtInit.cc.managed 2004-03-18 17:37:37.000000000 +0000 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/vncExtInit.cc 2004-06-18 11:12:51.178550984 +0100 @@ -101,6 +101,7 @@ static int vncEventBase = 0; static char* vncPasswdFile = 0; int vncInetdSock = -1; +int managerSock = -1; rfb::VncAuthPasswdFileParameter vncAuthPasswdFile; rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile", @@ -179,7 +180,7 @@ CharArray desktopNameStr(desktopName.getData()); desktop[scr] = new XserverDesktop(screenInfo.screens[scr], listener, - httpListener, + httpListener, managerSock, desktopNameStr.buf, vncFbptr[scr]); vlog.info("created VNC server for screen %d", scr); --- vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/Imakefile.managed 2004-06-18 10:52:59.836789911 +0100 +++ vnc-4.0b5-unixsrc/xc/programs/Xserver/vnc/Imakefile 2004-06-18 11:12:51.070567680 +0100 @@ -15,8 +15,8 @@ #if DoLoadableServer MODULE_SUBDIRS = module #endif - SRCS = vncExtInit.cc vncHooks.cc XserverDesktop.cc - OBJS = vncExtInit.o vncHooks.o XserverDesktop.o + SRCS = vncExtInit.cc vncHooks.cc XserverDesktop.cc XvncManager.cc + OBJS = vncExtInit.o vncHooks.o XserverDesktop.o XvncManager.o INCLUDES = -I../include -I$(EXTINCSRC) -I$(XINCLUDESRC) -I$(FONTINCSRC) \ -I../mfb -I../mi $(VNCINCLUDE) #if defined(XFree86Version) && XFree86Version >= 4000 --- vnc-4.0b5-unixsrc/network/Socket.h.managed 2004-03-18 17:37:36.000000000 +0000 +++ vnc-4.0b5-unixsrc/network/Socket.h 2004-06-18 11:12:50.753616688 +0100 @@ -102,7 +102,7 @@ // addClient() tells the server to manage the socket. // If the server can't manage the socket, it must shutdown() it. - virtual void addClient(network::Socket* sock) = 0; + virtual int addClient(network::Socket* sock) = 0; // processSocketEvent() tells the server there is a socket read event. // If there is an error, or the socket has been closed/shutdown then --- vnc-4.0b5-unixsrc/network/TcpSocket.cxx.managed 2004-06-18 10:53:00.086751041 +0100 +++ vnc-4.0b5-unixsrc/network/TcpSocket.cxx 2004-06-18 11:12:50.788611277 +0100 @@ -239,7 +239,7 @@ void TcpSocket::shutdown() { - ::shutdown(getFd(), 2); + // ::shutdown(getFd(), 2); } bool TcpSocket::isSocket(int sock) --- vnc-4.0b5-unixsrc/rdr/FdInStream.cxx.managed 2004-06-18 10:59:03.446399650 +0100 +++ vnc-4.0b5-unixsrc/rdr/FdInStream.cxx 2004-06-18 11:12:50.790610967 +0100 @@ -74,7 +74,10 @@ FdInStream::~FdInStream() { delete [] start; - if (closeWhenDone) close(fd); + if (closeWhenDone) { + fprintf (stderr, "FdInStream::~FdInStream: closing %d\n", fd); + close(fd); + } }