~ubuntu-branches/ubuntu/precise/trousers/precise-proposed

« back to all changes in this revision

Viewing changes to src/tcsd/tcsd_threads.c

  • Committer: Bazaar Package Importer
  • Author(s): William Lima
  • Date: 2007-04-18 16:39:38 UTC
  • Revision ID: james.westby@ubuntu.com-20070418163938-opscl2mvvi76jiec
Tags: upstream-0.2.9.1
ImportĀ upstreamĀ versionĀ 0.2.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * Licensed Materials - Property of IBM
 
4
 *
 
5
 * trousers - An open source TCG Software Stack
 
6
 *
 
7
 * (C) Copyright International Business Machines Corp. 2004
 
8
 *
 
9
 */
 
10
 
 
11
 
 
12
#include <stdlib.h>
 
13
#include <stdio.h>
 
14
#include <syslog.h>
 
15
#include <pthread.h>
 
16
#include <errno.h>
 
17
#include <string.h>
 
18
#include <unistd.h>
 
19
 
 
20
#include "trousers/tss.h"
 
21
#include "trousers_types.h"
 
22
#include "tcs_int_literals.h"
 
23
#include "tcs_tsp.h"
 
24
#include "tcs_utils.h"
 
25
#include "tcsd_wrap.h"
 
26
#include "tcsd.h"
 
27
#include "tcslog.h"
 
28
 
 
29
struct tcsd_thread_mgr *tm = NULL;
 
30
 
 
31
TSS_RESULT
 
32
tcsd_threads_final()
 
33
{
 
34
        int rc;
 
35
        UINT32 i;
 
36
 
 
37
        pthread_mutex_lock(&(tm->lock));
 
38
 
 
39
        tm->shutdown = 1;
 
40
 
 
41
        pthread_mutex_unlock(&(tm->lock));
 
42
 
 
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);
 
48
                        }
 
49
                }
 
50
        }
 
51
 
 
52
        free(tm->thread_data);
 
53
        free(tm);
 
54
 
 
55
        return TSS_SUCCESS;
 
56
}
 
57
 
 
58
TSS_RESULT
 
59
tcsd_threads_init(void)
 
60
{
 
61
        /* allocate the thread mgmt structure */
 
62
        tm = calloc(1, sizeof(struct tcsd_thread_mgr));
 
63
        if (tm == NULL) {
 
64
                LogError("malloc of %zd bytes failed.", sizeof(struct tcsd_thread_mgr));
 
65
                return TCSERR(TSS_E_OUTOFMEMORY);
 
66
        }
 
67
 
 
68
        /* set the max threads variable from config */
 
69
        tm->max_threads = tcsd_options.num_threads;
 
70
 
 
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));
 
76
                free(tm);
 
77
                return TCSERR(TSS_E_OUTOFMEMORY);
 
78
        }
 
79
 
 
80
        return TSS_SUCCESS;
 
81
}
 
82
 
 
83
 
 
84
TSS_RESULT
 
85
tcsd_thread_create(int socket, char *hostname)
 
86
{
 
87
        UINT32 thread_num;
 
88
#ifndef TCSD_SINGLE_THREAD_DEBUG
 
89
        int rc;
 
90
        pthread_attr_t tcsd_thread_attr;
 
91
 
 
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);
 
96
        }
 
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);
 
101
        }
 
102
 
 
103
        pthread_mutex_lock(&(tm->lock));
 
104
#endif
 
105
        if (tm->num_active_threads == tm->max_threads) {
 
106
                close(socket);
 
107
                if (hostname != NULL) {
 
108
                        LogError("max number of connections reached (%d), new connection"
 
109
                                 " from %s refused.", tm->max_threads, hostname);
 
110
                } else {
 
111
                        LogError("max number of connections reached (%d), new connection"
 
112
                                 " refused.", tm->max_threads);
 
113
                }
 
114
                free(hostname);
 
115
                pthread_mutex_unlock(&(tm->lock));
 
116
                return TCSERR(TSS_E_CONNECTION_FAILED);
 
117
        }
 
118
 
 
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)
 
122
                        break;
 
123
        }
 
124
 
 
125
        DBG_ASSERT(thread_num != tm->max_threads);
 
126
 
 
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;
 
131
 
 
132
#ifdef TCSD_SINGLE_THREAD_DEBUG
 
133
        (void)tcsd_thread_run((void *)(&(tm->thread_data[thread_num])));
 
134
#else
 
135
        if ((rc = pthread_create(&(tm->thread_data[thread_num].thread_id),
 
136
                                 &tcsd_thread_attr,
 
137
                                 tcsd_thread_run,
 
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);
 
142
        }
 
143
 
 
144
        tm->num_active_threads++;
 
145
 
 
146
        pthread_mutex_unlock(&(tm->lock));
 
147
#endif
 
148
        return TSS_SUCCESS;
 
149
}
 
150
 
 
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.
 
155
 */
 
156
void
 
157
thread_signal_init()
 
158
{
 
159
        sigset_t thread_sigmask;
 
160
        int rc;
 
161
 
 
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());
 
165
                pthread_exit(NULL);
 
166
        }
 
167
 
 
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());
 
171
                pthread_exit(NULL);
 
172
        }
 
173
}
 
174
 
 
175
void *
 
176
tcsd_thread_run(void *v)
 
177
{
 
178
        struct tcsd_thread_data *data = (struct tcsd_thread_data *)v;
 
179
        BYTE *buffer;
 
180
        int recv_size, send_size;
 
181
        TSS_RESULT result;
 
182
        UINT64 offset;
 
183
#ifndef TCSD_SINGLE_THREAD_DEBUG
 
184
        int rc;
 
185
 
 
186
        thread_signal_init();
 
187
#endif
 
188
 
 
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)
 
196
                        break;
 
197
                buffer += sizeof(struct tcsd_packet_hdr);       /* increment the buffer pointer */
 
198
 
 
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);
 
204
                        break;
 
205
                }
 
206
 
 
207
                if (recv_size > data->comm.buf_size ) {
 
208
                        BYTE *new_buffer;
 
209
 
 
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);
 
214
                                break;
 
215
                        }
 
216
                        buffer = new_buffer + sizeof(struct tcsd_packet_hdr);
 
217
                        data->comm.buf_size = recv_size;
 
218
                        data->comm.buf = new_buffer;
 
219
                }
 
220
 
 
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)
 
224
                        break;
 
225
                LogDebug("Rx'd packet");
 
226
 
 
227
                /* create a platform version of the tcsd header */
 
228
                offset = 0;
 
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);
 
236
 
 
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().
 
242
                         */
 
243
                        /* set everything to zero, fill in what is non-zero */
 
244
                        memset(data->comm.buf, 0, data->comm.buf_size);
 
245
                        offset = 0;
 
246
                        /* load packet size */
 
247
                        LoadBlob_UINT32(&offset, sizeof(struct tcsd_packet_hdr), data->comm.buf, NULL);
 
248
                        /* load result */
 
249
                        LoadBlob_UINT32(&offset, result, data->comm.buf, NULL);
 
250
                }
 
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);
 
254
                if (send_size < 0)
 
255
                        break;
 
256
 
 
257
                /* check for shutdown */
 
258
                if (tm->shutdown) {
 
259
                        LogDebug("Thread %u exiting via shutdown signal!", (unsigned int)pthread_self());
 
260
                        break;
 
261
                }
 
262
        }
 
263
 
 
264
        LogDebug("Thread exiting.");
 
265
 
 
266
        /* Closing connection to TSP */
 
267
        close(data->sock);
 
268
        data->sock = -1;
 
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;
 
276
        }
 
277
 
 
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. */
 
283
        if (!tm->shutdown) {
 
284
                if ((rc = pthread_detach(data->thread_id))) {
 
285
                        LogError("pthread_detach failed (errno %d)."
 
286
                                 " Resources may not be properly released.", rc);
 
287
                }
 
288
        }
 
289
        free(data->hostname);
 
290
        data->hostname = NULL;
 
291
        data->thread_id = (pthread_t)0;
 
292
        pthread_mutex_unlock(&(tm->lock));
 
293
        pthread_exit(NULL);
 
294
#else
 
295
        return NULL;
 
296
#endif
 
297
}