blob: c5c9be18ce55e9a89da59e6ea647c74ef2780c64 [file] [log] [blame]
/********************************************************************************/
/* */
/* Socket Transmit and Receive Utilities */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: tsssocket.c 1304 2018-08-20 18:31:45Z kgoldman $ */
/* */
/* (c) Copyright IBM Corporation 2015, 2018. */
/* */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright notice, */
/* this list of conditions and the following disclaimer. */
/* */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* Neither the names of the IBM Corporation nor the names of its */
/* contributors may be used to endorse or promote products derived from */
/* this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#ifndef TPM_NOSOCKET
/* TSS_SOCKET_FD encapsulates the differences between the Posix and Windows socket type */
#ifdef TPM_POSIX
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
#ifdef TPM_WINDOWS
#include <winsock2.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <ibmtss/Unmarshal_fp.h>
#include <ibmtss/tssresponsecode.h>
#include <ibmtss/tsserror.h>
#include <ibmtss/tssprint.h>
#include "tssproperties.h"
#include <ibmtss/tsstransmit.h>
#include "tsssocket.h"
/* local prototypes */
static uint32_t TSS_Socket_Open(TSS_CONTEXT *tssContext, short port);
static uint32_t TSS_Socket_SendCommand(TSS_CONTEXT *tssContext,
const uint8_t *buffer, uint16_t length,
const char *message);
static uint32_t TSS_Socket_SendPlatform(TSS_SOCKET_FD sock_fd, uint32_t command, const char *message);
static uint32_t TSS_Socket_ReceiveResponse(TSS_CONTEXT *tssContext, uint8_t *buffer, uint32_t *length);
static uint32_t TSS_Socket_ReceivePlatform(TSS_SOCKET_FD sock_fd);
static uint32_t TSS_Socket_ReceiveBytes(TSS_SOCKET_FD sock_fd, uint8_t *buffer, uint32_t nbytes);
static uint32_t TSS_Socket_SendBytes(TSS_SOCKET_FD sock_fd, const uint8_t *buffer, size_t length);
static uint32_t TSS_Socket_GetServerType(TSS_CONTEXT *tssContext,
int *mssim,
int *rawsingle);
#ifdef TPM_WINDOWS
static void TSS_Socket_PrintError(int err);
#endif
extern int tssVverbose;
extern int tssVerbose;
/* TSS_Socket_TransmitPlatform() transmits MS simulator platform administrative commands */
TPM_RC TSS_Socket_TransmitPlatform(TSS_CONTEXT *tssContext,
uint32_t command, const char *message)
{
TPM_RC rc = 0;
int mssim; /* boolean, true for MS simulator packet format, false for raw packet
format */
int rawsingle = FALSE; /* boolean, true for raw format with an open and close per
command */
/* open on first transmit */
if (tssContext->tssFirstTransmit) {
/* detect errors before starting, get the server packet type, MS sim or raw */
if (rc == 0) {
rc = TSS_Socket_GetServerType(tssContext, &mssim, &rawsingle);
}
/* the platform administrative commands can only work with the simulator */
if (rc == 0) {
if (!mssim) {
if (tssVerbose) printf("TSS_Socket_TransmitPlatform: server type %s unsupported\n",
tssContext->tssServerType);
rc = TSS_RC_INSUPPORTED_INTERFACE;
}
}
if (rc == 0) {
rc = TSS_Socket_Open(tssContext, tssContext->tssPlatformPort);
}
if (rc == 0) {
tssContext->tssFirstTransmit = FALSE;
}
}
if (rc == 0) {
rc = TSS_Socket_SendPlatform(tssContext->sock_fd, command, message);
}
if (rc == 0) {
rc = TSS_Socket_ReceivePlatform(tssContext->sock_fd);
}
return rc;
}
/* TSS_Socket_TransmitCommand() transmits MS simulator in band administrative commands */
TPM_RC TSS_Socket_TransmitCommand(TSS_CONTEXT *tssContext,
uint32_t command, const char *message)
{
TPM_RC rc = 0;
int mssim; /* boolean, true for MS simulator packet format, false for raw packet
format */
int rawsingle = FALSE; /* boolean, true for raw format with an open and close per
command */
/* open on first transmit */
if (tssContext->tssFirstTransmit) {
/* detect errors before starting, get the server packet type, MS sim or raw */
if (rc == 0) {
rc = TSS_Socket_GetServerType(tssContext, &mssim, &rawsingle);
}
/* the platform administrative commands can only work with the simulator */
if (rc == 0) {
if (!mssim) {
if (tssVerbose) printf("TSS_Socket_TransmitCommand: server type %s unsupported\n",
tssContext->tssServerType);
rc = TSS_RC_INSUPPORTED_INTERFACE;
}
}
if (rc == 0) {
rc = TSS_Socket_Open(tssContext, tssContext->tssCommandPort);
}
if (rc == 0) {
tssContext->tssFirstTransmit = FALSE;
}
}
if (message != NULL) {
if (tssVverbose) printf("TSS_Socket_TransmitCommand: %s\n", message);
}
if (rc == 0) {
uint32_t commandType = htonl(command); /* command type is network byte order */
rc = TSS_Socket_SendBytes(tssContext->sock_fd, (uint8_t *)&commandType, sizeof(uint32_t));
}
/* FIXME The only command currently supported is TPM_STOP, which has no response */
return rc;
}
/* TSS_Socket_Transmit() transmits the TPM command and receives the response.
It can return socket transmit and receive packet errors, but normally returns the TPM response
code.
*/
TPM_RC TSS_Socket_Transmit(TSS_CONTEXT *tssContext,
uint8_t *responseBuffer, uint32_t *read,
const uint8_t *commandBuffer, uint32_t written,
const char *message)
{
TPM_RC rc = 0;
int mssim; /* boolean, true for MS simulator packet format, false for raw packet
format */
int rawsingle = FALSE; /* boolean, true for raw packet format requiring an open and
close for each command */
/* open on first transmit */
if (tssContext->tssFirstTransmit) {
/* detect errors before starting, get the server packet type, MS sim or raw */
if (rc == 0) {
rc = TSS_Socket_GetServerType(tssContext, &mssim, &rawsingle);
}
if (rc == 0) {
rc = TSS_Socket_Open(tssContext, tssContext->tssCommandPort);
}
if (rc == 0) {
tssContext->tssFirstTransmit = FALSE;
}
}
/* send the command over the socket. Error if the socket send fails. */
if (rc == 0) {
rc = TSS_Socket_SendCommand(tssContext, commandBuffer, written, message);
}
/* receive the response over the socket. Returns socket errors, malformed response errors.
Else returns the TPM response code. */
if (rc == 0) {
rc = TSS_Socket_ReceiveResponse(tssContext, responseBuffer, read);
}
/* rawsingle flags a close after each command */
if (rawsingle) {
TPM_RC rc1;
rc1 = TSS_Socket_Close(tssContext);
if (rc == 0) {
rc = rc1;
}
tssContext->tssFirstTransmit = TRUE; /* force reopen on next command */
}
return rc;
}
/* TSS_Socket_GetServerType() gets the type of server packet format
Currently, the formats supported are:
mssim, raw, rawsingle
mssim TRUE - the MS simulator packet
mssim FALSE - raw TPM specification Part 3 packets
rawsingle is the same as mssim FALSE but forces an open and cose for each command
*/
static uint32_t TSS_Socket_GetServerType(TSS_CONTEXT *tssContext,
int *mssim,
int *rawsingle)
{
uint32_t rc = 0;
if (rc == 0) {
if ((strcmp(tssContext->tssServerType, "mssim") == 0)) {
*mssim = TRUE;
*rawsingle = FALSE;
}
else if ((strcmp(tssContext->tssServerType, "raw") == 0)) {
*mssim = FALSE;
*rawsingle = FALSE;
}
else if ((strcmp(tssContext->tssServerType, "rawsingle") == 0)) {
*mssim = FALSE;
*rawsingle = TRUE;
}
else {
if (tssVerbose) printf("TSS_Socket_GetServerType: server type %s unsupported\n",
tssContext->tssServerType);
rc = TSS_RC_INSUPPORTED_INTERFACE;
}
}
return rc;
}
/* TSS_Socket_Open() opens the socket to the TPM Host emulation to tssServerName:port
*/
static uint32_t TSS_Socket_Open(TSS_CONTEXT *tssContext, short port)
{
#ifdef TPM_WINDOWS
WSADATA wsaData;
int irc;
#endif
struct sockaddr_in serv_addr;
struct hostent *host = NULL;
if (tssVverbose) printf("TSS_Socket_Open: Opening %s:%hu-%s\n",
tssContext->tssServerName, port, tssContext->tssServerType);
/* create a socket */
#ifdef TPM_WINDOWS
if ((irc = WSAStartup(0x202, &wsaData)) != 0) { /* if not successful */
if (tssVerbose) printf("TSS_Socket_Open: Error, WSAStartup failed\n");
WSACleanup();
return TSS_RC_NO_CONNECTION;
}
if ((tssContext->sock_fd = socket(AF_INET,SOCK_STREAM, 0)) == INVALID_SOCKET) {
if (tssVerbose) printf("TSS_Socket_Open: client socket() error: %u\n", tssContext->sock_fd);
return TSS_RC_NO_CONNECTION;
}
#endif
#ifdef TPM_POSIX
if ((tssContext->sock_fd = socket(AF_INET,SOCK_STREAM, 0)) < 0) {
if (tssVerbose) printf("TSS_Socket_Open: client socket error: %d %s\n",
errno,strerror(errno));
return TSS_RC_NO_CONNECTION;
}
#endif
memset((char *)&serv_addr,0x0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
/* the server host name tssServerName came from the default or an environment variable */
/* first assume server is dotted decimal number and call inet_addr */
if ((int)(serv_addr.sin_addr.s_addr = inet_addr(tssContext->tssServerName)) == -1) {
/* if inet_addr fails, assume server is a name and call gethostbyname to look it up */
/* if gethostbyname also fails */
if ((host = gethostbyname(tssContext->tssServerName)) == NULL) {
if (tssVerbose) printf("TSS_Socket_Open: server name error, name %s\n",
tssContext->tssServerName);
return TSS_RC_NO_CONNECTION;
}
serv_addr.sin_family = host->h_addrtype;
memcpy(&serv_addr.sin_addr, host->h_addr, host->h_length);
}
/* establish the connection to the TPM server */
#ifdef TPM_POSIX
if (connect(tssContext->sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
if (tssVerbose) printf("TSS_Socket_Open: Error on connect to %s:%u\n",
tssContext->tssServerName, port);
if (tssVerbose) printf("TSS_Socket_Open: client connect: error %d %s\n",
errno,strerror(errno));
return TSS_RC_NO_CONNECTION;
}
#endif
#ifdef TPM_WINDOWS
if (connect(tssContext->sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) {
if (tssVerbose) {
int err;
printf("TSS_Socket_Open: Error on connect to %s:%u\n",
tssContext->tssServerName, port);
err = WSAGetLastError();
printf("TSS_Socket_Open: client connect: error %d\n", err);
TSS_Socket_PrintError(err);
}
return TSS_RC_NO_CONNECTION;
}
#endif
else {
/* printf("TSS_Socket_Open: client connect: success\n"); */
}
return 0;
}
/* TSS_Socket_SendCommand() sends the TPM command packet over the socket.
The MS simulator packet is of the form:
TPM_SEND_COMMAND
locality 0
length
TPM command packet (this is the raw packet format)
Returns an error if the socket send fails.
*/
static uint32_t TSS_Socket_SendCommand(TSS_CONTEXT *tssContext,
const uint8_t *buffer, uint16_t length,
const char *message)
{
uint32_t rc = 0;
int mssim; /* boolean, true for MS simulator packet format, false for raw packet
format */
int rawsingle;
if (message != NULL) {
if (tssVverbose) printf("TSS_Socket_SendCommand: %s\n", message);
}
/* trace the command packet */
if ((rc == 0) && tssVverbose) {
TSS_PrintAll("TSS_Socket_SendCommand",
buffer, length);
}
/* get the server packet type, MS sim or raw */
if (rc == 0) {
rc = TSS_Socket_GetServerType(tssContext, &mssim, &rawsingle);
}
/* MS simulator wants a command type, locality, length */
if ((rc == 0) && mssim) {
uint32_t commandType = htonl(TPM_SEND_COMMAND); /* command type is network byte order */
rc = TSS_Socket_SendBytes(tssContext->sock_fd, (uint8_t *)&commandType, sizeof(uint32_t));
}
if ((rc == 0) && mssim) {
uint8_t locality = 0;
rc = TSS_Socket_SendBytes(tssContext->sock_fd, &locality, sizeof(uint8_t));
}
if ((rc == 0) && mssim) {
uint32_t lengthNbo = htonl(length); /* length is network byte order */
rc = TSS_Socket_SendBytes(tssContext->sock_fd, (uint8_t *)&lengthNbo, sizeof(uint32_t));
}
/* all packet formats (types) send the TPM command packet */
if (rc == 0) {
rc = TSS_Socket_SendBytes(tssContext->sock_fd, buffer, length);
}
return rc;
}
/* TSS_Socket_SendPlatform() transmits MS simulator platform administrative commands. This function
should only be called if the TPM supports administrative commands.
Returns an error if the socket send fails.
*/
static uint32_t TSS_Socket_SendPlatform(TSS_SOCKET_FD sock_fd, uint32_t command, const char *message)
{
uint32_t rc = 0;
if (message != NULL) {
if (tssVverbose) printf("TSS_Socket_SendPlatform: %s\n", message);
}
if (tssVverbose) printf("TSS_Socket_SendPlatform: Command %08x\n", command);
/* MS simulator platform commands */
if (rc == 0) {
uint32_t commandNbo = htonl(command); /* command is network byte order */
rc = TSS_Socket_SendBytes(sock_fd, (uint8_t *)&commandNbo , sizeof(uint32_t));
}
return rc;
}
/* TSS_Socket_SendBytes() is the low level sent function that transmits the buffer over the socket.
It handles partial writes by looping.
*/
static uint32_t TSS_Socket_SendBytes(TSS_SOCKET_FD sock_fd, const uint8_t *buffer, size_t length)
{
int nwritten = 0;
size_t nleft = 0;
unsigned int offset = 0;
nleft = length;
while (nleft > 0) {
#ifdef TPM_POSIX
nwritten = write(sock_fd, &buffer[offset], nleft);
if (nwritten < 0) { /* error */
if (tssVerbose) printf("TSS_Socket_SendBytes: write error %d\n", (int)nwritten);
return TSS_RC_BAD_CONNECTION;
}
#endif
#ifdef TPM_WINDOWS
/* cast for winsock. Unix uses void * */
nwritten = send(sock_fd, (char *)(&buffer[offset]), nleft, 0);
if (nwritten == SOCKET_ERROR) { /* error */
if (tssVerbose) printf("TSS_Socket_SendBytes: write error %d\n", (int)nwritten);
return TSS_RC_BAD_CONNECTION;
}
#endif
nleft -= nwritten;
offset += nwritten;
}
return 0;
}
/* TSS_Socket_ReceiveResponse() reads a TPM response packet from the socket. 'buffer' must be at
least MAX_RESPONSE_SIZE bytes. The bytes read are returned in 'length'.
The MS simulator packet is of the form:
length
TPM response packet (this is the raw packet format)
acknowledgement uint32_t zero
If the receive succeeds, returns TPM packet error code.
Validates that the packet length and the packet responseSize match
*/
static uint32_t TSS_Socket_ReceiveResponse(TSS_CONTEXT *tssContext,
uint8_t *buffer, uint32_t *length)
{
uint32_t rc = 0;
uint32_t responseSize = 0;
uint32_t responseLength = 0;
uint8_t *bufferPtr = buffer; /* the moving buffer */
TPM_RC responseCode;
uint32_t size; /* dummy for unmarshal call */
int mssim; /* boolean, true for MS simulator packet format, false for raw
packet format */
int rawsingle;
TPM_RC acknowledgement; /* MS sim acknowledgement */
/* get the server packet type, MS sim or raw */
if (rc == 0) {
rc = TSS_Socket_GetServerType(tssContext, &mssim, &rawsingle);
}
/* read the length prepended by the simulator */
if ((rc == 0) && mssim) {
rc = TSS_Socket_ReceiveBytes(tssContext->sock_fd,
(uint8_t *)&responseLength, sizeof(uint32_t));
responseLength = ntohl(responseLength);
}
/* read the tag and responseSize */
if (rc == 0) {
rc = TSS_Socket_ReceiveBytes(tssContext->sock_fd,
bufferPtr, sizeof(TPM_ST) + sizeof(uint32_t));
}
/* extract the responseSize */
if (rc == 0) {
/* skip over tag to responseSize */
bufferPtr += sizeof(TPM_ST);
size = sizeof(uint32_t); /* dummy for call */
rc = TSS_UINT32_Unmarshalu(&responseSize, &bufferPtr, &size);
*length = responseSize; /* returned length */
/* check the response size, see TSS_CONTEXT structure */
if (responseSize > MAX_RESPONSE_SIZE) {
if (tssVerbose)
printf("TSS_Socket_ReceiveResponse: ERROR: responseSize %u greater than %u\n",
responseSize, MAX_RESPONSE_SIZE);
rc = TSS_RC_BAD_CONNECTION;
}
/* check that MS sim prepended length is the same as the response TPM packet
length parameter */
if (mssim && (responseSize != responseLength)) {
if (tssVerbose) printf("TSS_Socket_ReceiveResponse: "
"ERROR: responseSize %u not equal to responseLength %u\n",
responseSize, responseLength);
rc = TSS_RC_BAD_CONNECTION;
}
}
/* read the rest of the packet */
if (rc == 0) {
rc = TSS_Socket_ReceiveBytes(tssContext->sock_fd,
bufferPtr,
responseSize - (sizeof(TPM_ST) + sizeof(uint32_t)));
}
if ((rc == 0) && tssVverbose) {
TSS_PrintAll("TSS_Socket_ReceiveResponse",
buffer, responseSize);
}
/* read the MS sim acknowledgement */
if ((rc == 0) && mssim) {
rc = TSS_Socket_ReceiveBytes(tssContext->sock_fd,
(uint8_t *)&acknowledgement, sizeof(uint32_t));
}
/* extract the TPM return code from the packet */
if (rc == 0) {
/* skip to responseCode */
bufferPtr = buffer + sizeof(TPM_ST) + sizeof(uint32_t);
size = sizeof(TPM_RC); /* dummy for call */
rc = TSS_UINT32_Unmarshalu(&responseCode, &bufferPtr, &size);
}
/* if there is no other (receive or unmarshal) error, return the TPM response code */
if (rc == 0) {
rc = responseCode;
}
/* if there is no other (TPM response) error, return the MS simulator packet acknowledgement */
if ((rc == 0) && mssim) {
rc = ntohl(acknowledgement); /* should always be zero */
}
return rc;
}
/* TSS_Socket_ReceivePlatform reads MS simulator platform administrative responses. This function
should only be called if the TPM supports administrative commands.
The acknowledgement is a uint32_t zero.
*/
static uint32_t TSS_Socket_ReceivePlatform(TSS_SOCKET_FD sock_fd)
{
uint32_t rc = 0;
TPM_RC acknowledgement;
/* read the MS sim acknowledgement */
if (rc == 0) {
rc = TSS_Socket_ReceiveBytes(sock_fd, (uint8_t *)&acknowledgement, sizeof(uint32_t));
}
/* if there is no other error, return the MS simulator packet acknowledgement */
if (rc == 0) {
rc = ntohl(acknowledgement); /* should always be zero */
}
return rc;
}
/* TSS_Socket_ReceiveBytes() is the low level receive function that reads the buffer over the
socket. 'buffer' must be atleast 'nbytes'.
It handles partial reads by looping.
*/
static uint32_t TSS_Socket_ReceiveBytes(TSS_SOCKET_FD sock_fd,
uint8_t *buffer,
uint32_t nbytes)
{
int nread = 0;
int nleft = 0;
nleft = nbytes;
while (nleft > 0) {
#ifdef TPM_POSIX
nread = read(sock_fd, buffer, nleft);
if (nread < 0) { /* error */
if (tssVerbose) printf("TSS_Socket_ReceiveBytes: read error %d\n", nread);
return TSS_RC_BAD_CONNECTION;
}
#endif
#ifdef TPM_WINDOWS
/* cast for winsock. Unix uses void * */
nread = recv(sock_fd, (char *)buffer, nleft, 0);
if (nread == SOCKET_ERROR) { /* error */
if (tssVerbose) printf("TSS_Socket_ReceiveBytes: read error %d\n", nread);
return TSS_RC_BAD_CONNECTION;
}
#endif
else if (nread == 0) { /* EOF */
if (tssVerbose) printf("TSS_Socket_ReceiveBytes: read EOF\n");
return TSS_RC_BAD_CONNECTION;
}
nleft -= nread;
buffer += nread;
}
return 0;
}
/* TSS_Socket_Close() closes the socket.
It sends the TPM_SESSION_END required by the MS simulator.
*/
TPM_RC TSS_Socket_Close(TSS_CONTEXT *tssContext)
{
uint32_t rc = 0;
int mssim; /* boolean, true for MS simulator packet format, false for raw packet
format */
int rawsingle = TRUE; /* boolean, true for raw format with an open and close per
command. Initialized to suppress false gcc -O3
warning. */
if (tssVverbose) printf("TSS_Socket_Close: Closing %s-%s\n",
tssContext->tssServerName, tssContext->tssServerType);
/* get the server packet type, MS sim or raw */
if (rc == 0) {
rc = TSS_Socket_GetServerType(tssContext, &mssim, &rawsingle);
}
/* the MS simulator expects a TPM_SESSION_END command before close */
if ((rc == 0) && mssim) {
uint32_t commandType = htonl(TPM_SESSION_END);
rc = TSS_Socket_SendBytes(tssContext->sock_fd, (uint8_t *)&commandType, sizeof(uint32_t));
}
#ifdef TPM_POSIX
/* always attempt a close, even though rawsingle should already have closed the socket */
if (close(tssContext->sock_fd) != 0) {
if (!rawsingle) {
if (tssVerbose) printf("TSS_Socket_Close: close error\n");
rc = TSS_RC_BAD_CONNECTION;
}
}
#endif
#ifdef TPM_WINDOWS
/* gracefully shut down the socket */
/* always attempt a close, even though rawsingle should already have closed the socket */
{
int irc;
irc = shutdown(tssContext->sock_fd, SD_SEND);
if (!rawsingle) {
if (irc == SOCKET_ERROR) { /* error */
if (tssVerbose) printf("TSS_Socket_Close: shutdown error\n");
rc = TSS_RC_BAD_CONNECTION;
}
}
}
closesocket(tssContext->sock_fd);
WSACleanup();
#endif
return rc;
}
#endif /* TPM_NOSOCKET */
#ifdef TPM_WINDOWS
/* The Windows equivalent to strerror(). It also traces the error message.
*/
static void TSS_Socket_PrintError(int err)
{
DWORD rc;
char *buffer = NULL;
/* mingw seems to output UTF-8 for FormatMessage(). For Visual Studio, FormatMessage() outputs
UTF-16, which would require wprintf(). FormatMessageA() outputs UTF-8, permitting printf()
for both compilers. */
rc = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, /* formatting */
err,
0, /* language */
(LPSTR)&buffer,
0,
NULL);
if (rc != 0) {
printf("%s\n", buffer);
}
LocalFree(buffer);
return;
}
#endif