143dcd69150ff1198492f48ab546d38d6314d3fa
[strongswan.git] / Source / charon / threads / stroke_interface.c
1 /**
2 * @file stroke.c
3 *
4 * @brief Implementation of stroke_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <sys/fcntl.h>
29 #include <unistd.h>
30 #include <dirent.h>
31 #include <errno.h>
32 #include <pthread.h>
33
34 #include "stroke_interface.h"
35
36 #include <stroke.h>
37 #include <types.h>
38 #include <daemon.h>
39 #include <crypto/x509.h>
40 #include <queues/jobs/initiate_ike_sa_job.h>
41
42
43 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
44
45 typedef struct connection_entry_t connection_entry_t;
46
47 /**
48 * A connection entry combines a connection name with a connection.
49 */
50 struct connection_entry_t {
51
52 /**
53 * connection name.
54 */
55 char *name;
56
57 /**
58 * Configuration for IKE_SA_INIT exchange.
59 */
60 connection_t *connection;
61 };
62
63
64 typedef struct private_stroke_t private_stroke_t;
65
66 /**
67 * Private data of an stroke_t object.
68 */
69 struct private_stroke_t {
70
71 /**
72 * Public part of stroke_t object.
73 */
74 stroke_t public;
75
76 /**
77 * Holding all connections as connection_entry_t's.
78 */
79 linked_list_t *connections;
80
81 /**
82 * Assigned logger_t object in charon.
83 */
84 logger_t *logger;
85
86 /**
87 * Logger which logs to stroke
88 */
89 logger_t *stroke_logger;
90
91 /**
92 * Unix socket to listen for strokes
93 */
94 int socket;
95
96 /**
97 * Thread which reads from the socket
98 */
99 pthread_t assigned_thread;
100
101 /**
102 * Read from the socket and handle stroke messages
103 */
104 void (*stroke_receive) (private_stroke_t *this);
105
106 /**
107 * find a connection in the config list by name
108 */
109 connection_t *(*get_connection_by_name) (private_stroke_t *this, char *name);
110 };
111
112 /**
113 * Helper function which corrects the string pointers
114 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
115 * contains RELATIVE addresses (relative to the beginning of the
116 * stroke_msg). They must be corrected if they reach our address
117 * space...
118 */
119 static void pop_string(stroke_msg_t *msg, char **string)
120 {
121 /* check for sanity of string pointer and string */
122 if (*string == NULL)
123 {
124 *string = "";
125 }
126 else if (string < (char**)msg ||
127 string > (char**)msg + sizeof(stroke_msg_t) ||
128 *string < (char*)msg->buffer - (u_int)msg ||
129 *string > (char*)(u_int)msg->length)
130 {
131 *string = "(invalid char* in stroke msg)";
132 }
133 else
134 {
135 *string = (char*)msg + (u_int)*string;
136 }
137 }
138
139 /**
140 * Add a connection to the configuration list
141 */
142 static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
143 {
144 connection_t *connection;
145 policy_t *policy;
146 identification_t *my_id, *other_id;
147 host_t *my_host, *other_host, *my_subnet, *other_subnet;
148 proposal_t *proposal;
149 traffic_selector_t *my_ts, *other_ts;
150 connection_entry_t *entry;
151 x509_t *cert;
152
153 pop_string(msg, &msg->add_conn.name);
154 pop_string(msg, &msg->add_conn.me.address);
155 pop_string(msg, &msg->add_conn.other.address);
156 pop_string(msg, &msg->add_conn.me.id);
157 pop_string(msg, &msg->add_conn.other.id);
158 pop_string(msg, &msg->add_conn.me.cert);
159 pop_string(msg, &msg->add_conn.other.cert);
160 pop_string(msg, &msg->add_conn.me.subnet);
161 pop_string(msg, &msg->add_conn.other.subnet);
162
163 this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
164
165 my_host = host_create(AF_INET, msg->add_conn.me.address, 500);
166 if (my_host == NULL)
167 {
168 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
169 return;
170 }
171 other_host = host_create(AF_INET, msg->add_conn.other.address, 500);
172 if (other_host == NULL)
173 {
174 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
175 my_host->destroy(my_host);
176 return;
177 }
178 my_id = identification_create_from_string(*msg->add_conn.me.id ?
179 msg->add_conn.me.id : msg->add_conn.me.address);
180 if (my_id == NULL)
181 {
182 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
183 my_host->destroy(my_host);
184 other_host->destroy(other_host);
185 return;
186 }
187 other_id = identification_create_from_string(*msg->add_conn.other.id ?
188 msg->add_conn.other.id : msg->add_conn.other.address);
189 if (other_id == NULL)
190 {
191 my_host->destroy(my_host);
192 other_host->destroy(other_host);
193 my_id->destroy(my_id);
194 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
195 return;
196 }
197
198 my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500);
199 if (my_subnet == NULL)
200 {
201 my_host->destroy(my_host);
202 other_host->destroy(other_host);
203 my_id->destroy(my_id);
204 other_id->destroy(other_id);
205 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
206 return;
207 }
208
209 other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500);
210 if (other_subnet == NULL)
211 {
212 my_host->destroy(my_host);
213 other_host->destroy(other_host);
214 my_id->destroy(my_id);
215 other_id->destroy(other_id);
216 my_subnet->destroy(my_subnet);
217 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
218 return;
219 }
220
221 my_ts = traffic_selector_create_from_subnet(my_subnet, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32);
222 my_subnet->destroy(my_subnet);
223 other_ts = traffic_selector_create_from_subnet(other_subnet, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32);
224 other_subnet->destroy(other_subnet);
225
226 if (charon->socket->is_listening_on(charon->socket, other_host))
227 {
228 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, switching");
229
230 host_t *tmp_host = my_host;
231 identification_t *tmp_id = my_id;
232 traffic_selector_t *tmp_ts = my_ts;
233 char *tmp_cert = msg->add_conn.me.cert;
234
235 my_host = other_host;
236 other_host = tmp_host;
237 my_id = other_id;
238 other_id = tmp_id;
239 my_ts = other_ts;
240 other_ts = tmp_ts;
241 msg->add_conn.me.cert = msg->add_conn.other.cert;
242 msg->add_conn.other.cert = tmp_cert;
243 }
244 else if (charon->socket->is_listening_on(charon->socket, my_host))
245 {
246 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is own host, not switching");
247 }
248 else
249 {
250 this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our, aborting");
251
252 my_host->destroy(my_host);
253 other_host->destroy(other_host);
254 my_id->destroy(my_id);
255 other_id->destroy(other_id);
256 my_ts->destroy(my_ts);
257 other_ts->destroy(other_ts);
258 return;
259 }
260
261 if (msg->add_conn.me.cert)
262 {
263 char file[128];
264 snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.me.cert);
265 cert = x509_create_from_file(file);
266 if (cert)
267 {
268 my_id->destroy(my_id);
269 my_id = cert->get_subject(cert);
270 my_id = my_id->clone(my_id);
271 cert->destroy(cert);
272 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
273 "defined a valid certificate, using its ID \"%s\"",
274 my_id->get_string(my_id));
275 }
276 }
277 if (msg->add_conn.other.cert)
278 {
279 char file[128];
280 snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.other.cert);
281 cert = x509_create_from_file(file);
282 if (cert)
283 {
284 other_id->destroy(other_id);
285 other_id = cert->get_subject(cert);
286 other_id = other_id->clone(other_id);
287 cert->destroy(cert);
288 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
289 "defined a valid certificate, using its ID \"%s\"",
290 other_id->get_string(other_id));
291 }
292 }
293
294 connection = connection_create(my_host, other_host, my_id->clone(my_id), other_id->clone(other_id),
295 RSA_DIGITAL_SIGNATURE);
296 proposal = proposal_create(1);
297 proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
298 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
299 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
300 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
301 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
302 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
303 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
304 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
305 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
306 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
307 connection->add_proposal(connection, proposal);
308 /* add in our list, so we can manipulate the connection further via name */
309 entry = malloc_thing(connection_entry_t);
310 entry->name = strdup(msg->add_conn.name);
311 entry->connection = connection;
312 this->connections->insert_last(this->connections, entry);
313 /* add to global connection list */
314 charon->connections->add_connection(charon->connections, connection);
315
316 policy = policy_create(my_id, other_id);
317 proposal = proposal_create(1);
318 proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
319 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
320 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
321 policy->add_proposal(policy, proposal);
322 policy->add_my_traffic_selector(policy, my_ts);
323 policy->add_other_traffic_selector(policy, other_ts);
324 /* add to global policy list */
325 charon->policies->add_policy(charon->policies, policy);
326
327 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "connection \"%s\" added", msg->add_conn.name);
328 }
329
330 /**
331 * initiate a connection by name
332 */
333 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
334 {
335 initiate_ike_sa_job_t *job;
336 connection_t *connection;
337
338 pop_string(msg, &(msg->initiate.name));
339 this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
340 connection = this->get_connection_by_name(this, msg->initiate.name);
341 if (connection == NULL)
342 {
343 this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name);
344 }
345 else
346 {
347 job = initiate_ike_sa_job_create(connection->clone(connection));
348 charon->job_queue->add(charon->job_queue, (job_t*)job);
349 }
350 }
351
352 /**
353 * terminate a connection by name
354 */
355 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
356 {
357 connection_t *connection;
358 ike_sa_t *ike_sa;
359 host_t *my_host, *other_host;
360 status_t status;
361
362 pop_string(msg, &(msg->terminate.name));
363 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
364 connection = this->get_connection_by_name(this, msg->terminate.name);
365
366 if (connection)
367 {
368 my_host = connection->get_my_host(connection);
369 other_host = connection->get_other_host(connection);
370
371 status = charon->ike_sa_manager->checkout_by_hosts(charon->ike_sa_manager,
372 my_host, other_host, &ike_sa);
373
374 if (status == SUCCESS)
375 {
376 this->stroke_logger->log(this->stroke_logger, CONTROL, "deleting IKE SA between %s - %s",
377 my_host->get_address(my_host), other_host->get_address(other_host));
378
379 charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
380 }
381 else
382 {
383 this->stroke_logger->log(this->stroke_logger, ERROR, "no active connection found between %s - %s",
384 my_host->get_address(my_host), other_host->get_address(other_host));
385 }
386 }
387 else
388 {
389 this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->terminate.name);
390 }
391
392 }
393
394 /**
395 * show status of (established) connections
396 */
397 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
398 {
399 linked_list_t *list;
400 iterator_t *iterator;
401 status_t status;
402
403
404 list = charon->ike_sa_manager->get_ike_sa_list(charon->ike_sa_manager);
405 iterator = list->create_iterator(list, TRUE);
406 while (iterator->has_next(iterator))
407 {
408 ike_sa_id_t *ike_sa_id;
409 ike_sa_t *ike_sa;
410 iterator->current(iterator, (void**)&ike_sa_id);
411 /* TODO: A log_status method (as in IKE_SA/CHILD_SA) would be better than checking
412 * out every single IKE...
413 */
414 status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa);
415 if (status == SUCCESS)
416 {
417 ike_sa->log_status(ike_sa, this->stroke_logger);
418 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
419 }
420 ike_sa_id->destroy(ike_sa_id);
421 }
422 iterator->destroy(iterator);
423 list->destroy(list);
424 }
425
426 logger_context_t get_context(char *context)
427 {
428 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
429 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
430 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
431 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
432 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
433 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
434 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
435 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
436 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
437 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
438 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
439 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
440 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
441 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
442 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
443 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
444 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
445 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
446 else return -2;
447 }
448
449 /**
450 * set the type of logged messages in a context
451 */
452 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
453 {
454 pop_string(msg, &(msg->logtype.context));
455 pop_string(msg, &(msg->logtype.type));
456
457 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
458
459 log_level_t level;
460 logger_context_t context = get_context(msg->logtype.context);
461 if (context == -2)
462 {
463 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
464 return;
465 }
466
467 if (strcasecmp(msg->logtype.type, "CONTROL") == 0) level = CONTROL;
468 else if (strcasecmp(msg->logtype.type, "ERROR") == 0) level = ERROR;
469 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0) level = AUDIT;
470 else if (strcasecmp(msg->logtype.type, "RAW") == 0) level = RAW;
471 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0) level = PRIVATE;
472 else
473 {
474 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
475 return;
476 }
477
478 if (msg->logtype.enable)
479 {
480 logger_manager->enable_log_level(logger_manager, context, level);
481 }
482 else
483 {
484 logger_manager->disable_log_level(logger_manager, context, level);
485 }
486 }
487
488 /**
489 * set the verbosity of a logger
490 */
491 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
492 {
493 pop_string(msg, &(msg->loglevel.context));
494
495 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
496
497 log_level_t level;
498 logger_context_t context = get_context(msg->loglevel.context);
499
500 if (context == -2)
501 {
502 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
503 return;
504 }
505
506 if (msg->loglevel.level == 0)
507 {
508 level = LEVEL0;
509 }
510 else if (msg->loglevel.level == 1)
511 {
512 level = LEVEL1;
513 }
514 else if (msg->loglevel.level == 2)
515 {
516 level = LEVEL2;
517 }
518 else if (msg->loglevel.level == 3)
519 {
520 level = LEVEL3;
521 }
522 else
523 {
524 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
525 return;
526 }
527
528 logger_manager->enable_log_level(logger_manager, context, level);
529 }
530
531 /**
532 * Implementation of private_stroke_t.stroke_receive.
533 */
534 static void stroke_receive(private_stroke_t *this)
535 {
536 stroke_msg_t *msg;
537 u_int16_t msg_length;
538 struct sockaddr_un strokeaddr;
539 int strokeaddrlen = sizeof(strokeaddr);
540 ssize_t bytes_read;
541 int strokefd;
542 FILE *strokefile;
543 int oldstate;
544
545 /* disable cancellation by default */
546 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
547
548 while (1)
549 {
550 /* wait for connections, but allow thread to terminate */
551 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
552 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
553 pthread_setcancelstate(oldstate, NULL);
554
555 if (strokefd < 0)
556 {
557 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
558 continue;
559 }
560
561 /* peek the length */
562 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
563 if (bytes_read != sizeof(msg_length))
564 {
565 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
566 close(strokefd);
567 continue;
568 }
569
570 /* read message */
571 msg = malloc(msg_length);
572 bytes_read = recv(strokefd, msg, msg_length, 0);
573 if (bytes_read != msg_length)
574 {
575 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
576 close(strokefd);
577 continue;
578 }
579
580 strokefile = fdopen(dup(strokefd), "w");
581 if (strokefile == NULL)
582 {
583 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
584 close(strokefd);
585 free(msg);
586 continue;
587 }
588
589 this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile);
590
591 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
592
593 switch (msg->type)
594 {
595 case STR_INITIATE:
596 {
597 stroke_initiate(this, msg);
598 break;
599 }
600 case STR_TERMINATE:
601 {
602 stroke_terminate(this, msg);
603 break;
604 }
605 case STR_STATUS:
606 {
607 stroke_status(this, msg);
608 break;
609 }
610 case STR_ADD_CONN:
611 {
612 stroke_add_conn(this, msg);
613 break;
614 }
615 case STR_LOGTYPE:
616 {
617 stroke_logtype(this, msg);
618 break;
619 }
620 case STR_LOGLEVEL:
621 {
622 stroke_loglevel(this, msg);
623 break;
624 }
625 default:
626 this->logger->log(this->logger, ERROR, "received invalid stroke");
627 }
628 this->stroke_logger->destroy(this->stroke_logger);
629 fclose(strokefile);
630 close(strokefd);
631 free(msg);
632 }
633 }
634
635
636 /**
637 * Implementation of private_stroke_t.get_connection_by_name.
638 */
639 static connection_t *get_connection_by_name(private_stroke_t *this, char *name)
640 {
641 iterator_t *iterator;
642 connection_t *found = NULL;
643
644 iterator = this->connections->create_iterator(this->connections, TRUE);
645 while (iterator->has_next(iterator))
646 {
647 connection_entry_t *entry;
648 iterator->current(iterator,(void **) &entry);
649
650 if (strcmp(entry->name,name) == 0)
651 {
652 /* found configuration */
653 found = entry->connection;
654 break;
655 }
656 }
657 iterator->destroy(iterator);
658
659 return found;
660 }
661
662 /**
663 * Implementation of stroke_t.destroy.
664 */
665 static void destroy(private_stroke_t *this)
666 {
667 connection_entry_t *entry;
668
669 pthread_cancel(this->assigned_thread);
670 pthread_join(this->assigned_thread, NULL);
671
672 while (this->connections->remove_first(this->connections, (void **)&entry) == SUCCESS)
673 {
674 /* connection is destroyed by global list */
675 free(entry->name);
676 free(entry);
677 }
678 this->connections->destroy(this->connections);
679
680 close(this->socket);
681 unlink(socket_addr.sun_path);
682 free(this);
683 }
684
685
686 /*
687 * Described in header-file
688 */
689 stroke_t *stroke_create()
690 {
691 private_stroke_t *this = malloc_thing(private_stroke_t);
692 mode_t old;
693
694 /* public functions */
695 this->public.destroy = (void (*)(stroke_t*))destroy;
696
697 /* private functions */
698 this->stroke_receive = stroke_receive;
699 this->get_connection_by_name = get_connection_by_name;
700
701 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
702
703 /* set up unix socket */
704 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
705 if (this->socket == -1)
706 {
707 this->logger->log(this->logger, ERROR, "could not create whack socket");
708 free(this);
709 return NULL;
710 }
711
712 old = umask(~S_IRWXU);
713 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
714 {
715 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
716 close(this->socket);
717 free(this);
718 return NULL;
719 }
720 umask(old);
721
722 if (listen(this->socket, 0) < 0)
723 {
724 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
725 close(this->socket);
726 unlink(socket_addr.sun_path);
727 free(this);
728 return NULL;
729 }
730
731 /* start a thread reading from the socket */
732 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
733 {
734 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
735 close(this->socket);
736 unlink(socket_addr.sun_path);
737 free(this);
738 return NULL;
739 }
740
741 /* private variables */
742 this->connections = linked_list_create();
743
744 return (&this->public);
745 }