Last active
April 18, 2018 16:11
-
-
Save danintel/a15fa70e94b28dee96a77c9d1bb70387 to your computer and use it in GitHub Desktop.
Patch to add IPv6 Support to the Microsoft/IBM TPM 2.0 Simulator on SourceForge
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- src/TcpServerPosix.c.ori 2016-11-16 10:31:54.000000000 -0800 | |
+++ src/TcpServerPosix.c 2018-04-18 09:10:00.000000000 -0700 | |
@@ -82,6 +82,9 @@ | |
#include "TcpServerPosix_fp.h" | |
#include "Simulator_fp.h" | |
+#define IPVER(len) ((len) == sizeof(struct sockaddr_in6) ? 6 : \ | |
+ ((len) == sizeof(struct sockaddr_in) ? 4 : 0)) | |
+ | |
#ifndef __IGNORE_STATE__ | |
static UINT32 ServerVersion = 1; | |
#define MAX_BUFFER 1048576 | |
@@ -104,28 +107,57 @@ | |
static int | |
CreateSocket( | |
int PortNumber, | |
- SOCKET *listenSocket | |
+ SOCKET *listenSocket, | |
+ socklen_t *addr_len, | |
+ int domain // AF_INET or AF_INET6 | |
) | |
{ | |
- struct sockaddr_in MyAddress; | |
+ struct sockaddr_storage MyAddress; | |
int opt; | |
int res; | |
// create listening socket | |
- *listenSocket = socket(PF_INET, SOCK_STREAM, 0); | |
+ *listenSocket = socket(domain, SOCK_STREAM, 0); | |
if(*listenSocket == -1) | |
{ | |
- printf("Cannot create server listen socket. Erroris %d %s\n", | |
- errno, strerror(errno)); | |
+ printf("Cannot create server listen %s socket. Error is %d %s\n", | |
+ domain == AF_INET6 ? "IPv6" : | |
+ (domain == AF_INET) ? "IPv4" : "?", errno, strerror(errno)); | |
return -1; | |
} | |
- // bind the listening socket to the specified port | |
+ // bind the listening socket to the specified port, any address (0s) | |
memset((char *)&MyAddress, 0, sizeof(MyAddress)); | |
- MyAddress.sin_port=htons((short) PortNumber); | |
- MyAddress.sin_family=AF_INET; | |
- MyAddress.sin_addr.s_addr = htonl(INADDR_ANY); /* host to network byte order for long */ | |
+ MyAddress.ss_family = domain; | |
+ switch (domain) { | |
+ case AF_INET: | |
+ ((struct sockaddr_in *)&MyAddress)->sin_port = | |
+ htons((short) PortNumber); | |
+ if (addr_len != NULL) | |
+ *addr_len = sizeof(struct sockaddr_in); | |
+ break; | |
+ case AF_INET6: | |
+ ((struct sockaddr_in6 *)&MyAddress)->sin6_port = | |
+ htons((short) PortNumber); | |
+ if (addr_len != NULL) | |
+ *addr_len = sizeof(struct sockaddr_in6); | |
+ | |
+ opt = 1; | |
+ // Set IPPROTO_IPV6 so that it's just for IPv6 and not both IPv4/IPv6. | |
+ res = setsockopt(*listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, &opt, | |
+ sizeof(opt)); | |
+ if (res != 0) { | |
+ printf("setsockopt IPV6_V6ONLY error. Error is %d %s\n", errno, | |
+ strerror(errno)); | |
+ return -1; | |
+ } | |
+ break; | |
+ default: | |
+ printf("Address family %d not supported\n", domain); | |
+ return -1; | |
+ } | |
+ | |
opt = 1; | |
/* Set SO_REUSEADDR before calling bind() for servers that bind to a fixed port number. */ | |
res = setsockopt(*listenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); | |
@@ -253,43 +285,79 @@ | |
) | |
{ | |
int PortNumber = *(int *)port; | |
- SOCKET listenSocket, serverSocket; | |
- struct sockaddr_in HerAddress; | |
- int res; | |
- socklen_t length; | |
+ SOCKET listenSocket[2], maxListenSocket, serverSocket; | |
+ struct sockaddr_storage HerAddress; | |
+ fd_set sockSet; | |
+ int res, i; | |
+ int nSock = 0; | |
+ socklen_t length[2]; | |
BOOL continueServing; | |
- | |
- res = CreateSocket(PortNumber, &listenSocket); | |
- if(res != 0) | |
- { | |
+ | |
+ if (CreateSocket(PortNumber, &listenSocket[nSock], &length[nSock], | |
+ AF_INET) == 0) { | |
+ nSock++; | |
+ | |
+ } | |
+ if (CreateSocket(PortNumber, &listenSocket[nSock], &length[nSock], | |
+ AF_INET6) == 0) { | |
+ nSock++; | |
+ } | |
+ if (nSock == 0) { | |
printf("Create platform service socket fail\n"); | |
- return res; | |
+ return -1; | |
} | |
+ maxListenSocket = listenSocket[0]; | |
+ if (nSock == 2 && listenSocket[1] > maxListenSocket) { | |
+ maxListenSocket = listenSocket[1]; | |
+ } | |
// Loop accepting connections one-by-one until we are killed or asked to stop | |
// Note the platform service is single-threaded so we don't listen for a new | |
// connection until the prior connection drops. | |
do | |
{ | |
- printf("Platform server listening on port %d\n", PortNumber); | |
- | |
- // blocking accept | |
- length = sizeof(HerAddress); | |
- serverSocket = accept(listenSocket, | |
- (struct sockaddr*) &HerAddress, | |
- &length); | |
- if(serverSocket < 0) | |
- { | |
- printf("Accept error. Error is %d %s\n", errno, strerror(errno)); | |
- return -1; | |
- }; | |
- printf("Client accepted\n"); | |
+ | |
+ printf("Platform server listening on port %d\n", PortNumber); | |
+ | |
+ // Select both IPv4 and IPv6 sockets or whatever is available | |
+ FD_ZERO(&sockSet); | |
+ FD_SET(listenSocket[0], &sockSet); | |
+ if (nSock == 2) | |
+ FD_SET(listenSocket[1], &sockSet); | |
+ do { | |
+ res = select(maxListenSocket + 1, &sockSet, NULL, NULL, NULL); | |
+ } while ((res == -1) && (errno == EINTR)); | |
+ if (res == -1) { | |
+ printf("Platform server select error. Error is %d %s\n", errno, | |
+ strerror(errno)); | |
+ return -1; | |
+ } | |
+ | |
+ for (i = 0; i < nSock; i++) { | |
+ int ipver = IPVER(length[i]); | |
+ | |
+ if (!FD_ISSET(listenSocket[i], &sockSet)) | |
+ { | |
+ continue; | |
+ } | |
+ // blocking accept | |
+ serverSocket = accept(listenSocket[i], | |
+ (struct sockaddr*) &HerAddress, | |
+ &length[i]); | |
+ if(serverSocket < 0) | |
+ { | |
+ printf("Platform server IPv%d Accept error. Error is %d %s\n", | |
+ ipver, errno, strerror(errno)); | |
+ return -1; | |
+ }; | |
+ printf("Platform IPv%d client accepted\n", ipver); | |
- // normal behavior on client disconnection is to wait for a new client | |
- // to connect | |
- continueServing = PlatformServer(serverSocket); | |
- close(serverSocket); | |
- serverSocket = -1; | |
+ // normal behavior on client disconnection is to wait for a new | |
+ // client to connect | |
+ continueServing = PlatformServer(serverSocket); | |
+ close(serverSocket); | |
+ serverSocket = -1; | |
+ } | |
} | |
while(continueServing); | |
@@ -348,45 +416,78 @@ | |
int *PortNumber | |
) | |
{ | |
- SOCKET listenSocket; | |
+ SOCKET listenSocket[2], maxListenSocket; | |
SOCKET serverSocket; | |
- struct sockaddr_in HerAddress; | |
- | |
- int res; | |
- socklen_t length; | |
+ struct sockaddr_storage HerAddress; | |
+ fd_set sockSet; | |
+ int res, i; | |
+ int nSock = 0; | |
+ socklen_t length[2]; | |
BOOL continueServing; | |
- | |
- res = CreateSocket(*PortNumber, &listenSocket); | |
- if(res != 0) | |
- { | |
- printf("Create platform service socket fail\n"); | |
- return res; | |
- } | |
+ | |
+ if (CreateSocket(*PortNumber, &listenSocket[nSock], &length[nSock], | |
+ AF_INET) == 0) { | |
+ nSock++; | |
+ | |
+ } | |
+ if (CreateSocket(*PortNumber, &listenSocket[nSock], &length[nSock], | |
+ AF_INET6) == 0) { | |
+ nSock++; | |
+ } | |
+ if (nSock == 0) { | |
+ printf("Create TPM command service socket fail\n"); | |
+ return -1; | |
+ } | |
+ maxListenSocket = listenSocket[0]; | |
+ if (nSock == 2 && listenSocket[1] > maxListenSocket) { | |
+ maxListenSocket = listenSocket[1]; | |
+ } | |
// Loop accepting connections one-by-one until we are killed or asked to stop | |
// Note the TPM command service is single-threaded so we don't listen for | |
// a new connection until the prior connection drops. | |
do | |
{ | |
- printf("TPM command server listening on port %d\n", *PortNumber); | |
- | |
- // blocking accept | |
- length = sizeof(HerAddress); | |
- serverSocket = accept(listenSocket, | |
- (struct sockaddr*) &HerAddress, | |
- &length); | |
- if(serverSocket < 0) | |
- { | |
- printf("Accept error. Error is %d %s\n", errno, strerror(errno)); | |
- return -1; | |
- }; | |
- printf("Client accepted\n"); | |
+ | |
+ printf("TPM command server listening on port %d\n", *PortNumber); | |
+ | |
+ // Select both IPv4 and IPv6 sockets or whatever is available | |
+ FD_ZERO(&sockSet); | |
+ FD_SET(listenSocket[0], &sockSet); | |
+ if (nSock == 2) | |
+ FD_SET(listenSocket[1], &sockSet); | |
+ do { | |
+ res = select(maxListenSocket + 1, &sockSet, NULL, NULL, NULL); | |
+ } while ((res == -1) && (errno == EINTR)); | |
+ if (res == -1) { | |
+ printf("TPM command server select error. Error is %d %s\n", errno, | |
+ strerror(errno)); | |
+ return -1; | |
+ } | |
+ | |
+ for (i = 0; i < nSock; i++) { | |
+ int ipver = IPVER(length[i]); | |
+ | |
+ if (!FD_ISSET(listenSocket[i], &sockSet)) | |
+ continue; | |
+ // blocking accept | |
+ serverSocket = accept(listenSocket[i], | |
+ (struct sockaddr*) &HerAddress, | |
+ &length[i]); | |
+ if(serverSocket < 0) | |
+ { | |
+ printf("TPM server IPv%d Accept error. Error is %d %s\n", | |
+ ipver, errno, strerror(errno)); | |
+ return -1; | |
+ }; | |
+ printf("Command IPv%d client accepted\n", ipver); | |
- // normal behavior on client disconnection is to wait for a new client | |
- // to connect | |
- continueServing = TpmServer(serverSocket); | |
- close(serverSocket); | |
- serverSocket = -1; | |
+ // normal behavior on client disconnection is to wait for a new | |
+ // client to connect | |
+ continueServing = TpmServer(serverSocket); | |
+ close(serverSocket); | |
+ serverSocket = -1; | |
+ } | |
} | |
while(continueServing); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment