From 0797e42a4aaf8131ae71899faea2d682ed81cb59 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Wed, 29 Sep 2010 23:42:52 +0200 Subject: [PATCH] IP QoS support in libvncclient. This enables setting the DSCP/Traffic Class field of IP/IPv6 packets sent by a client. For example starting a client with -qosdscp 184 marks all outgoing traffic for expedited forwarding. Implementation for Win32 is still a TODO, though. See http://betelco.blogspot.com/2009/03/dscp-marking-under-windows-at.html for an overview of the Win32 QoS API mess... --- TODO | 1 + libvncclient/rfbproto.c | 3 +++ libvncclient/sockets.c | 49 ++++++++++++++++++++++++++++++++++++++++ libvncclient/vncviewer.c | 4 ++++ rfb/rfbclient.h | 4 ++++ 5 files changed, 61 insertions(+) diff --git a/TODO b/TODO index d9e2721..e8f7763 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,7 @@ java vncviewer doesn't do colour cursors? make corre work again (libvncclient or libvncserver?) teach SDLvncviewer about CopyRect... implement "-record" in libvncclient +implement QoS for Windows in libvncclient later: ------ diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c index df8eb2f..602594b 100644 --- a/libvncclient/rfbproto.c +++ b/libvncclient/rfbproto.c @@ -421,6 +421,9 @@ ConnectToRFBServer(rfbClient* client,const char *hostname, int port) return FALSE; } + if(client->QoS_DSCP && !SetDSCP(client->sock, client->QoS_DSCP)) + return FALSE; + return SetNonBlocking(client->sock); } diff --git a/libvncclient/sockets.c b/libvncclient/sockets.c index 28b0256..e9a4b53 100644 --- a/libvncclient/sockets.c +++ b/libvncclient/sockets.c @@ -566,6 +566,55 @@ SetNonBlocking(int sock) } + +/* + * SetDSCP sets a socket's IP QoS parameters aka Differentiated Services Code Point field + */ + +rfbBool +SetDSCP(int sock, int dscp) +{ +#ifdef WIN32 + rfbClientErr("Setting of QoS IP DSCP not implemented for Windows\n"); + return TRUE; +#else + int level, cmd; + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + + if(getsockname(sock, &addr, &addrlen) != 0) { + rfbClientErr("Setting socket QoS failed while getting socket address: %s\n",strerror(errno)); + return FALSE; + } + + switch(addr.sa_family) + { +#ifdef LIBVNCSERVER_IPv6 + case AF_INET6: + level = IPPROTO_IPV6; + cmd = IPV6_TCLASS; + break; +#endif + case AF_INET: + level = IPPROTO_IP; + cmd = IP_TOS; + break; + default: + rfbClientErr("Setting socket QoS failed: Not bound to IP address"); + return FALSE; + } + + if(setsockopt(sock, level, cmd, (void*)&dscp, sizeof(dscp)) != 0) { + rfbClientErr("Setting socket QoS failed: %s\n", strerror(errno)); + return FALSE; + } + + return TRUE; +#endif +} + + + /* * StringToIPAddr - convert a host string to an IP address. */ diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c index 6541c1d..1c5ea6e 100644 --- a/libvncclient/vncviewer.c +++ b/libvncclient/vncviewer.c @@ -186,6 +186,7 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel, client->Bell = Dummy; client->CurrentKeyboardLedState = 0; client->HandleKeyboardLedState = (HandleKeyboardLedStateProc)DummyPoint; + client->QoS_DSCP = 0; client->authScheme = 0; client->subAuthScheme = 0; @@ -288,6 +289,9 @@ 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], "-qosdscp") == 0) { + client->QoS_DSCP = atoi(argv[i+1]); + j+=2; } else if (i+1<*argc && strcmp(argv[i], "-repeaterdest") == 0) { char* colon=strchr(argv[i+1],':'); diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h index b38f335..34c8737 100644 --- a/rfb/rfbclient.h +++ b/rfb/rfbclient.h @@ -313,6 +313,9 @@ typedef struct _rfbClient { /* When the server is a repeater, this specifies the final destination */ char *destHost; int destPort; + + /* the QoS IP DSCP for this client */ + int QoS_DSCP; } rfbClient; /* cursor.c */ @@ -388,6 +391,7 @@ extern int ConnectClientToTcpAddr6(const char *hostname, int port); extern int ConnectClientToUnixSock(const char *sockFile); extern int AcceptTcpConnection(int listenSock); extern rfbBool SetNonBlocking(int sock); +extern rfbBool SetDSCP(int sock, int dscp); extern rfbBool StringToIPAddr(const char *str, unsigned int *addr); extern rfbBool SameMachine(int sock);