3
* Licensed Materials - Property of IBM
5
* trousers - An open source TCG Software Stack
7
* (C) Copyright International Business Machines Corp. 2004
20
#include "trousers/tss.h"
21
#include "trousers_types.h"
22
#include "tcs_int_literals.h"
24
#include "tcs_utils.h"
25
#include "tcsd_wrap.h"
29
struct tcsd_thread_mgr *tm = NULL;
37
pthread_mutex_lock(&(tm->lock));
41
pthread_mutex_unlock(&(tm->lock));
43
/* wait for all currently running threads to exit */
44
for (i = 0; i < tm->max_threads; i++) {
45
if (tm->thread_data[i].thread_id != (pthread_t)0) {
46
if ((rc = pthread_join(tm->thread_data[i].thread_id, NULL))) {
47
LogError("pthread_join() failed: error: %d", rc);
52
free(tm->thread_data);
59
tcsd_threads_init(void)
61
/* allocate the thread mgmt structure */
62
tm = calloc(1, sizeof(struct tcsd_thread_mgr));
64
LogError("malloc of %zd bytes failed.", sizeof(struct tcsd_thread_mgr));
65
return TCSERR(TSS_E_OUTOFMEMORY);
68
/* set the max threads variable from config */
69
tm->max_threads = tcsd_options.num_threads;
71
/* allocate each thread's data structure */
72
tm->thread_data = calloc(tcsd_options.num_threads, sizeof(struct tcsd_thread_data));
73
if (tm->thread_data == NULL) {
74
LogError("malloc of %zu bytes failed.",
75
tcsd_options.num_threads * sizeof(struct tcsd_thread_data));
77
return TCSERR(TSS_E_OUTOFMEMORY);
85
tcsd_thread_create(int socket, char *hostname)
88
#ifndef TCSD_SINGLE_THREAD_DEBUG
90
pthread_attr_t tcsd_thread_attr;
92
/* init the thread attribute */
93
if ((rc = pthread_attr_init(&tcsd_thread_attr))) {
94
LogError("pthread_attr_init failed: error=%d: %s", rc, strerror(rc));
95
return TCSERR(TSS_E_INTERNAL_ERROR);
97
/* make all threads joinable */
98
if ((rc = pthread_attr_setdetachstate(&tcsd_thread_attr, PTHREAD_CREATE_JOINABLE))) {
99
LogError("pthread_attr_init failed: error=%d: %s", rc, strerror(rc));
100
return TCSERR(TSS_E_INTERNAL_ERROR);
103
pthread_mutex_lock(&(tm->lock));
105
if (tm->num_active_threads == tm->max_threads) {
107
if (hostname != NULL) {
108
LogError("max number of connections reached (%d), new connection"
109
" from %s refused.", tm->max_threads, hostname);
111
LogError("max number of connections reached (%d), new connection"
112
" refused.", tm->max_threads);
115
pthread_mutex_unlock(&(tm->lock));
116
return TCSERR(TSS_E_CONNECTION_FAILED);
119
/* search for an open slot to store the thread data in */
120
for (thread_num = 0; thread_num < tm->max_threads; thread_num++) {
121
if (tm->thread_data[thread_num].thread_id == (pthread_t)0)
125
DBG_ASSERT(thread_num != tm->max_threads);
127
tm->thread_data[thread_num].sock = socket;
128
tm->thread_data[thread_num].context = NULL_TCS_HANDLE;
129
if (hostname != NULL)
130
tm->thread_data[thread_num].hostname = hostname;
132
#ifdef TCSD_SINGLE_THREAD_DEBUG
133
(void)tcsd_thread_run((void *)(&(tm->thread_data[thread_num])));
135
if ((rc = pthread_create(&(tm->thread_data[thread_num].thread_id),
138
(void *)(&(tm->thread_data[thread_num]))))) {
139
LogError("pthread_create() failed: %d", rc);
140
pthread_mutex_unlock(&(tm->lock));
141
return TCSERR(TSS_E_INTERNAL_ERROR);
144
tm->num_active_threads++;
146
pthread_mutex_unlock(&(tm->lock));
151
/* since we don't want any of the worker threads to catch any signals,
152
* we must mask off any potential signals here after creating the threads. If any of
153
* the created threads catch a signal, they'd eventually call pthread_join() on
154
* themselves, causing a deadlock.
159
sigset_t thread_sigmask;
162
if ((rc = sigfillset(&thread_sigmask))) {
163
LogError("sigfillset failed: error=%d: %s", rc, strerror(rc));
164
LogError("worker thread %u is exiting prematurely", (unsigned int)pthread_self());
168
if ((rc = pthread_sigmask(SIG_BLOCK, &thread_sigmask, NULL))) {
169
LogError("pthread_sigmask failed: error=%d: %s", rc, strerror(rc));
170
LogError("worker thread %u is exiting prematurely", (unsigned int)pthread_self());
176
tcsd_thread_run(void *v)
178
struct tcsd_thread_data *data = (struct tcsd_thread_data *)v;
180
int recv_size, send_size;
183
#ifndef TCSD_SINGLE_THREAD_DEBUG
186
thread_signal_init();
189
data->comm.buf_size = TCSD_INIT_TXBUF_SIZE;
190
data->comm.buf = calloc(1, data->comm.buf_size);
191
while (data->comm.buf) {
192
/* get the packet header to get the size of the incoming packet */
193
buffer = data->comm.buf;
194
recv_size = sizeof(struct tcsd_packet_hdr);
195
if ((recv_size = recv_from_socket(data->sock, buffer, recv_size)) < 0)
197
buffer += sizeof(struct tcsd_packet_hdr); /* increment the buffer pointer */
199
/* check the packet size */
200
recv_size = Decode_UINT32(data->comm.buf);
201
if (recv_size < (int)sizeof(struct tcsd_packet_hdr)) {
202
LogError("Packet to receive from socket %d is too small (%d bytes)",
203
data->sock, recv_size);
207
if (recv_size > data->comm.buf_size ) {
210
LogDebug("Increasing communication buffer to %d bytes.", recv_size);
211
new_buffer = realloc(data->comm.buf, recv_size);
212
if (new_buffer == NULL) {
213
LogError("realloc of %d bytes failed.", recv_size);
216
buffer = new_buffer + sizeof(struct tcsd_packet_hdr);
217
data->comm.buf_size = recv_size;
218
data->comm.buf = new_buffer;
221
/* get the rest of the packet */
222
recv_size -= sizeof(struct tcsd_packet_hdr); /* already received the header */
223
if ((recv_size = recv_from_socket(data->sock, buffer, recv_size)) < 0)
225
LogDebug("Rx'd packet");
227
/* create a platform version of the tcsd header */
229
UnloadBlob_UINT32(&offset, &data->comm.hdr.packet_size, data->comm.buf, NULL);
230
UnloadBlob_UINT32(&offset, &data->comm.hdr.u.result, data->comm.buf, NULL);
231
UnloadBlob_UINT32(&offset, &data->comm.hdr.num_parms, data->comm.buf, NULL);
232
UnloadBlob_UINT32(&offset, &data->comm.hdr.type_size, data->comm.buf, NULL);
233
UnloadBlob_UINT32(&offset, &data->comm.hdr.type_offset, data->comm.buf, NULL);
234
UnloadBlob_UINT32(&offset, &data->comm.hdr.parm_size, data->comm.buf, NULL);
235
UnloadBlob_UINT32(&offset, &data->comm.hdr.parm_offset, data->comm.buf, NULL);
237
if ((result = getTCSDPacket(data)) != TSS_SUCCESS) {
238
/* something internal to the TCSD went wrong in preparing the packet
239
* to return to the TSP. Use our already allocated buffer to return a
240
* TSS_E_INTERNAL_ERROR return code to the TSP. In the non-error path,
241
* these LoadBlob's are done in getTCSDPacket().
243
/* set everything to zero, fill in what is non-zero */
244
memset(data->comm.buf, 0, data->comm.buf_size);
246
/* load packet size */
247
LoadBlob_UINT32(&offset, sizeof(struct tcsd_packet_hdr), data->comm.buf, NULL);
249
LoadBlob_UINT32(&offset, result, data->comm.buf, NULL);
251
send_size = Decode_UINT32(data->comm.buf);
252
LogDebug("Sending 0x%X bytes back", send_size);
253
send_size = send_to_socket(data->sock, data->comm.buf, send_size);
257
/* check for shutdown */
259
LogDebug("Thread %u exiting via shutdown signal!", (unsigned int)pthread_self());
264
LogDebug("Thread exiting.");
266
/* Closing connection to TSP */
269
free(data->comm.buf);
270
data->comm.buf = NULL;
271
data->comm.buf_size = -1;
272
/* If the connection was not shut down cleanly, free TCS resources here */
273
if (data->context != NULL_TCS_HANDLE) {
274
TCS_CloseContext_Internal(data->context);
275
data->context = NULL_TCS_HANDLE;
278
#ifndef TCSD_SINGLE_THREAD_DEBUG
279
pthread_mutex_lock(&(tm->lock));
280
tm->num_active_threads--;
281
/* if we're not in shutdown mode, then nobody is waiting to join this thread, so
282
* detach it so that its resources are free at pthread_exit() time. */
284
if ((rc = pthread_detach(data->thread_id))) {
285
LogError("pthread_detach failed (errno %d)."
286
" Resources may not be properly released.", rc);
289
free(data->hostname);
290
data->hostname = NULL;
291
data->thread_id = (pthread_t)0;
292
pthread_mutex_unlock(&(tm->lock));