diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c index 83cfbf9..8aa6348 100644 --- a/libvncclient/rfbproto.c +++ b/libvncclient/rfbproto.c @@ -415,6 +415,51 @@ ConnectToRFBServer(rfbClient* client,const char *hostname, int port) return SetNonBlocking(client->sock); } +/* + * ConnectToRFBRepeater. + */ + +rfbBool ConnectToRFBRepeater(rfbClient* client,const char *repeaterHost, int repeaterPort, const char *destHost, int destPort) +{ + unsigned int host; + rfbProtocolVersionMsg pv; + int major,minor; + char tmphost[250]; + + if (!StringToIPAddr(repeaterHost, &host)) { + rfbClientLog("Couldn't convert '%s' to host address\n", repeaterHost); + return FALSE; + } + + client->sock = ConnectClientToTcpAddr(host, repeaterPort); + + if (client->sock < 0) { + rfbClientLog("Unable to connect to VNC repeater\n"); + return FALSE; + } + + if (!SetNonBlocking(client->sock)) + return FALSE; + + if (!ReadFromRFBServer(client, pv, sz_rfbProtocolVersionMsg)) + return FALSE; + pv[sz_rfbProtocolVersionMsg] = 0; + + /* UltraVNC repeater always report version 000.000 to identify itself */ + if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2 || major != 0 || minor != 0) { + rfbClientLog("Not a valid VNC repeater (%s)\n",pv); + return FALSE; + } + + rfbClientLog("Connected to VNC repeater, using protocol version %d.%d\n", major, minor); + + snprintf(tmphost, sizeof(tmphost), "%s:%d", destHost, destPort); + if (!WriteToRFBServer(client, tmphost, sizeof(tmphost))) + return FALSE; + + return TRUE; +} + extern void rfbClientEncryptBytes(unsigned char* bytes, char* passwd); extern void rfbClientEncryptBytes2(unsigned char *where, const int length, unsigned char *key); diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c index 111a7f6..34de15d 100644 --- a/libvncclient/vncviewer.c +++ b/libvncclient/vncviewer.c @@ -119,6 +119,9 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel, client->programName=""; client->serverHost=strdup(""); client->serverPort=5900; + + client->destHost = NULL; + client->destPort = 5900; client->CurrentKeyboardLedState = 0; client->HandleKeyboardLedState = (HandleKeyboardLedStateProc)DummyPoint; @@ -202,8 +205,15 @@ static rfbBool rfbInitConnection(rfbClient* client) given VNC server */ if (!client->listenSpecified) { - if (!client->serverHost || !ConnectToRFBServer(client,client->serverHost,client->serverPort)) + if (!client->serverHost) return FALSE; + if (client->destHost) { + if (!ConnectToRFBRepeater(client,client->serverHost,client->serverPort,client->destHost,client->destPort)) + return FALSE; + } else { + if (!ConnectToRFBServer(client,client->serverHost,client->serverPort)) + return FALSE; + } } /* Initialise the VNC connection, including reading the password */ @@ -278,6 +288,19 @@ rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) { } else if (i+1<*argc && strcmp(argv[i], "-scale") == 0) { client->appData.scaleSetting = atoi(argv[i+1]); j+=2; + } else if (i+1<*argc && strcmp(argv[i], "-repeaterdest") == 0) { + char* colon=strchr(argv[i+1],':'); + + if(client->destHost) + free(client->destHost); + client->destPort = 5900; + + client->destHost = strdup(argv[i+1]); + if(colon) { + client->destHost[(int)(colon-argv[i+1])] = '\0'; + client->destPort = atoi(colon+1); + } + j+=2; } else { char* colon=strchr(argv[i],':'); @@ -285,14 +308,14 @@ rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) { free(client->serverHost); if(colon) { - client->serverHost=strdup(argv[i]); - client->serverHost[(int)(colon-argv[i])]='\0'; - client->serverPort=atoi(colon+1); + client->serverHost = strdup(argv[i]); + client->serverHost[(int)(colon-argv[i])] = '\0'; + client->serverPort = atoi(colon+1); } else { - client->serverHost=strdup(argv[i]); + client->serverHost = strdup(argv[i]); } - if(client->serverPort>=0 && client->serverPort<5900) - client->serverPort+=5900; + if(client->serverPort >= 0 && client->serverPort < 5900) + client->serverPort += 5900; } /* purge arguments */ if (j>i) { @@ -342,6 +365,8 @@ void rfbClientCleanup(rfbClient* client) { close(client->listenSock); free(client->desktopName); free(client->serverHost); + if (client->destHost) + free(client->destHost); if (client->clientAuthSchemes) free(client->clientAuthSchemes); free(client); diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h index a82ea22..bc4ec14 100644 --- a/rfb/rfbclient.h +++ b/rfb/rfbclient.h @@ -309,6 +309,10 @@ typedef struct _rfbClient { /* The 0-terminated security types supported by the client. * Set by function SetClientAuthSchemes() */ uint32_t *clientAuthSchemes; + + /* When the server is a repeater, this specifies the final destination */ + char *destHost; + int destPort; } rfbClient; /* cursor.c */ @@ -326,6 +330,7 @@ extern rfbBool rfbEnableClientLogging; typedef void (*rfbClientLogProc)(const char *format, ...); extern rfbClientLogProc rfbClientLog,rfbClientErr; extern rfbBool ConnectToRFBServer(rfbClient* client,const char *hostname, int port); +extern rfbBool ConnectToRFBRepeater(rfbClient* client,const char *repeaterHost, int repeaterPort, const char *destHost, int destPort); extern void SetClientAuthSchemes(rfbClient* client,const uint32_t *authSchemes, int size); extern rfbBool InitialiseRFBConnection(rfbClient* client); extern rfbBool SetFormatAndEncodings(rfbClient* client);