1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2015 - 2018 Intel Corporation
4 * All rights reserved.
5 */
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <inttypes.h>
13 #include <limits.h>
14 #include <string.h>
15 #include <stdio.h>
16
17 #ifndef _WIN32
18 #include <netdb.h>
19 #include <netinet/in.h>
20 #include <unistd.h>
21 #endif
22
23 #include "tss2_tpm2_types.h"
24
25 #include "io.h"
26 #define LOGMODULE tcti
27 #include "util/log.h"
28
29 #define MAX_PORT_STR_LEN sizeof("65535")
30 /*
31 * The 'read_all' function attempts to read all of the 'size' bytes requested
32 * from the 'fd' provided into the buffer 'data'. This function will continue
33 * to retry after temporary failures and "short reads". It will only stop
34 * once all of the requested data has been read, an error occurs, or EOF.
35 * On error or EOF, the number of bytes read (if any) will be returned.
36 */
37 ssize_t
read_all(SOCKET fd,uint8_t * data,size_t size)38 read_all (
39 SOCKET fd,
40 uint8_t *data,
41 size_t size)
42 {
43 ssize_t recvd;
44 size_t recvd_total = 0;
45
46 LOG_DEBUG ("reading %zu bytes from fd %d to buffer at 0x%" PRIxPTR,
47 size, fd, (uintptr_t)data);
48 do {
49 #ifdef _WIN32
50 TEMP_RETRY (recvd, recv (fd, (char *) &data [recvd_total], size, 0));
51 if (recvd < 0) {
52 LOG_WARNING ("read on fd %d failed with errno %d: %s",
53 fd, WSAGetLastError(), strerror (WSAGetLastError()));
54 return recvd_total;
55 }
56 #else
57 TEMP_RETRY (recvd, read (fd, &data [recvd_total], size));
58 if (recvd < 0) {
59 LOG_WARNING ("read on fd %d failed with errno %d: %s",
60 fd, errno, strerror (errno));
61 return recvd_total;
62 }
63 #endif
64 if (recvd == 0) {
65 LOG_WARNING ("Attempted read %zu bytes from fd %d, but EOF "
66 "returned", size, fd);
67 return recvd_total;
68 }
69 LOGBLOB_DEBUG (&data [recvd_total], recvd, "read %zd bytes from fd %d:", recvd, fd);
70 recvd_total += recvd;
71 size -= recvd;
72 } while (size > 0);
73
74 return recvd_total;
75 }
76
77 ssize_t
write_all(SOCKET fd,const uint8_t * buf,size_t size)78 write_all (
79 SOCKET fd,
80 const uint8_t *buf,
81 size_t size)
82 {
83 ssize_t written = 0;
84 size_t written_total = 0;
85
86 do {
87 LOG_DEBUG("writing %zu bytes starting at 0x%" PRIxPTR " to fd %d",
88 size - written_total,
89 (uintptr_t)(buf + written_total),
90 fd);
91 #ifdef _WIN32
92 TEMP_RETRY (written, send (fd,
93 (const char*)&buf [written_total],
94 size - written_total, 0));
95 #else
96 TEMP_RETRY (written, write (fd,
97 (const char*)&buf [written_total],
98 size - written_total));
99 #endif
100 if (written >= 0) {
101 LOG_DEBUG ("wrote %zd bytes to fd %d", written, fd);
102 written_total += (size_t)written;
103 } else {
104 #ifdef _WIN32
105 LOG_ERROR ("failed to write to fd %d: %s", fd, strerror (WSAGetLastError()));
106 #else
107 LOG_ERROR ("failed to write to fd %d: %s", fd, strerror (errno));
108 #endif
109 return written_total;
110 }
111 } while (written_total < size);
112
113 return (ssize_t)written_total;
114 }
115
116 ssize_t
socket_recv_buf(SOCKET sock,uint8_t * data,size_t size)117 socket_recv_buf (
118 SOCKET sock,
119 uint8_t *data,
120 size_t size)
121 {
122 return read_all (sock, data, size);
123 }
124
125 TSS2_RC
socket_xmit_buf(SOCKET sock,const void * buf,size_t size)126 socket_xmit_buf (
127 SOCKET sock,
128 const void *buf,
129 size_t size)
130 {
131 int ret;
132
133 LOGBLOB_DEBUG (buf, size, "Writing %zu bytes to socket %d:", size, sock);
134 ret = write_all (sock, buf, size);
135 if (ret < (ssize_t) size) {
136 #ifdef _WIN32
137 LOG_ERROR ("write to fd %d failed, errno %d: %s", sock, WSAGetLastError(), strerror (WSAGetLastError()));
138 #else
139 LOG_ERROR ("write to fd %d failed, errno %d: %s", sock, errno, strerror (errno));
140 #endif
141 return TSS2_TCTI_RC_IO_ERROR;
142 }
143 return TSS2_RC_SUCCESS;
144 }
145
146 TSS2_RC
socket_close(SOCKET * socket)147 socket_close (
148 SOCKET *socket)
149 {
150 int ret;
151
152 if (socket == NULL) {
153 return TSS2_TCTI_RC_BAD_REFERENCE;
154 }
155 if (*socket == INVALID_SOCKET) {
156 return TSS2_RC_SUCCESS;
157 }
158 #ifdef _WIN32
159 ret = closesocket (*socket);
160 WSACleanup();
161 if (ret == SOCKET_ERROR) {
162 LOG_WARNING ("Failed to close SOCKET %d. errno %d: %s",
163 *socket, WSAGetLastError(), strerror (WSAGetLastError()));
164 return TSS2_TCTI_RC_IO_ERROR;
165 }
166 #else
167 ret = close (*socket);
168 if (ret == SOCKET_ERROR) {
169 LOG_WARNING ("Failed to close SOCKET %d. errno %d: %s",
170 *socket, errno, strerror (errno));
171 return TSS2_TCTI_RC_IO_ERROR;
172 }
173 #endif
174 *socket = INVALID_SOCKET;
175
176 return TSS2_RC_SUCCESS;
177 }
178
179 TSS2_RC
socket_connect(const char * hostname,uint16_t port,SOCKET * sock)180 socket_connect (
181 const char *hostname,
182 uint16_t port,
183 SOCKET *sock)
184 {
185 static const struct addrinfo hints = { .ai_socktype = SOCK_STREAM,
186 .ai_family = AF_UNSPEC, .ai_protocol = IPPROTO_TCP};
187 struct addrinfo *retp = NULL;
188 struct addrinfo *p;
189 char port_str[MAX_PORT_STR_LEN];
190 int ret = 0;
191 #ifdef _WIN32
192 char host_buff[_HOST_NAME_MAX];
193 const char *h = hostname;
194 WSADATA wsaData;
195 int iResult;
196 iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
197 if (iResult != 0) {
198 LOG_WARNING("WSAStartup failed: %d", iResult);
199 return TSS2_TCTI_RC_IO_ERROR;
200 }
201 #else
202 char host_buff[_HOST_NAME_MAX] __attribute__((unused));
203 const char *h __attribute__((unused)) = hostname;
204 #endif
205
206 if (hostname == NULL || sock == NULL) {
207 return TSS2_TCTI_RC_BAD_REFERENCE;
208 }
209
210 ret = snprintf(port_str, sizeof(port_str), "%u", port);
211 if (ret < 0)
212 return TSS2_TCTI_RC_BAD_VALUE;
213
214
215 LOG_DEBUG ("Resolving host %s", hostname);
216 ret = getaddrinfo (hostname, port_str, &hints, &retp);
217 if (ret != 0) {
218 LOG_WARNING ("Host %s does not resolve to a valid address: %d: %s",
219 hostname, ret, gai_strerror(ret));
220 return TSS2_TCTI_RC_IO_ERROR;
221 }
222
223 for (p = retp; p != NULL; p = p->ai_next) {
224 *sock = socket (p->ai_family, SOCK_STREAM, 0);
225 void *sockaddr;
226
227 if (*sock == INVALID_SOCKET)
228 continue;
229
230 if (p->ai_family == AF_INET)
231 sockaddr = &((struct sockaddr_in*)p->ai_addr)->sin_addr;
232 else
233 sockaddr = &((struct sockaddr_in6*)p->ai_addr)->sin6_addr;
234
235 h = inet_ntop(p->ai_family, sockaddr, host_buff, sizeof(host_buff));
236
237 if (h == NULL)
238 h = hostname;
239
240 LOG_DEBUG ("Attempting TCP connection to host %s, port %s",
241 h, port_str);
242 if (connect (*sock, p->ai_addr, p->ai_addrlen) != SOCKET_ERROR)
243 break; /* socket connected OK */
244 socket_close (sock);
245 }
246 freeaddrinfo (retp);
247 if (p == NULL) {
248 #ifdef _WIN32
249 LOG_WARNING ("Failed to connect to host %s, port %s: errno %d: %s",
250 h, port_str, WSAGetLastError(), strerror (WSAGetLastError()));
251 #else
252 LOG_WARNING ("Failed to connect to host %s, port %s: errno %d: %s",
253 h, port_str, errno, strerror (errno));
254 #endif
255
256 return TSS2_TCTI_RC_IO_ERROR;
257 }
258
259 return TSS2_RC_SUCCESS;
260 }
261