4 * @brief Implementation of stroke_t.
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
24 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <sys/fcntl.h>
34 #include "stroke_interface.h"
39 #include <crypto/x509.h>
40 #include <queues/jobs/initiate_ike_sa_job.h>
45 static bool strict
= FALSE
;
47 struct sockaddr_un socket_addr
= { AF_UNIX
, STROKE_SOCKET
};
50 typedef struct private_stroke_t private_stroke_t
;
53 * Private data of an stroke_t object.
55 struct private_stroke_t
{
58 * Public part of stroke_t object.
63 * Assigned logger_t object in charon.
68 * Logger which logs to stroke
70 logger_t
*stroke_logger
;
73 * Unix socket to listen for strokes
78 * Thread which reads from the \ 1ocket
80 pthread_t assigned_thread
;
83 * Read from the socket and handle stroke messages
85 void (*stroke_receive
) (private_stroke_t
*this);
89 * Helper function which corrects the string pointers
90 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
91 * contains RELATIVE addresses (relative to the beginning of the
92 * stroke_msg). They must be corrected if they reach our address
95 static void pop_string(stroke_msg_t
*msg
, char **string
)
100 /* check for sanity of string pointer and string */
101 if (string
< (char**)msg
102 || string
> (char**)msg
+ sizeof(stroke_msg_t
)
103 || (u_int
)*string
< (u_int
)((char*)msg
->buffer
- (char*)msg
)
104 || (u_int
)*string
> msg
->length
)
106 *string
= "(invalid pointer in stroke msg)";
110 *string
= (char*)msg
+ (u_int
)*string
;
115 * Load end entitity certificate
117 static x509_t
* load_end_certificate(const char *filename
, identification_t
**idp
, logger_t
*logger
)
122 if (*filename
== '/')
124 /* absolute path name */
125 snprintf(path
, sizeof(path
), "%s", filename
);
129 /* relative path name */
130 snprintf(path
, sizeof(path
), "%s/%s", CERTIFICATE_DIR
, filename
);
133 cert
= x509_create_from_file(path
, "end entity certificate");
137 identification_t
*id
= *idp
;
138 identification_t
*subject
= cert
->get_subject(cert
);
140 err_t ugh
= cert
->is_valid(cert
, NULL
);
144 logger
->log(logger
, ERROR
, "warning: certificate %s", ugh
);
146 if (!id
->equals(id
, subject
) && !cert
->equals_subjectAltName(cert
, id
))
150 *idp
= id
->clone(id
);
152 return charon
->credentials
->add_end_certificate(charon
->credentials
, cert
);
158 * Add a connection to the configuration list
160 static void stroke_add_conn(private_stroke_t
*this, stroke_msg_t
*msg
)
162 connection_t
*connection
;
164 identification_t
*my_id
, *other_id
;
165 identification_t
*my_ca
= NULL
;
166 identification_t
*other_ca
= NULL
;
167 bool my_ca_same
= FALSE
;
168 bool other_ca_same
=FALSE
;
169 host_t
*my_host
, *other_host
, *my_subnet
, *other_subnet
;
170 proposal_t
*proposal
;
171 traffic_selector_t
*my_ts
, *other_ts
;
173 pop_string(msg
, &msg
->add_conn
.name
);
174 pop_string(msg
, &msg
->add_conn
.me
.address
);
175 pop_string(msg
, &msg
->add_conn
.other
.address
);
176 pop_string(msg
, &msg
->add_conn
.me
.subnet
);
177 pop_string(msg
, &msg
->add_conn
.other
.subnet
);
178 pop_string(msg
, &msg
->add_conn
.me
.id
);
179 pop_string(msg
, &msg
->add_conn
.other
.id
);
180 pop_string(msg
, &msg
->add_conn
.me
.cert
);
181 pop_string(msg
, &msg
->add_conn
.other
.cert
);
182 pop_string(msg
, &msg
->add_conn
.me
.ca
);
183 pop_string(msg
, &msg
->add_conn
.other
.ca
);
184 pop_string(msg
, &msg
->add_conn
.algorithms
.ike
);
185 pop_string(msg
, &msg
->add_conn
.algorithms
.esp
);
187 this->logger
->log(this->logger
, CONTROL
, "received stroke: add connection \"%s\"", msg
->add_conn
.name
);
189 my_host
= msg
->add_conn
.me
.address?
190 host_create(AF_INET
, msg
->add_conn
.me
.address
, IKE_PORT
) : NULL
;
193 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid host: %s", msg
->add_conn
.me
.address
);
197 other_host
= msg
->add_conn
.other
.address ?
198 host_create(AF_INET
, msg
->add_conn
.other
.address
, IKE_PORT
) : NULL
;
199 if (other_host
== NULL
)
201 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid host: %s", msg
->add_conn
.other
.address
);
202 my_host
->destroy(my_host
);
206 if (charon
->socket
->is_listening_on(charon
->socket
, other_host
))
208 stroke_end_t tmp_end
;
211 this->stroke_logger
->log(this->stroke_logger
, CONTROL
|LEVEL1
, "left is other host, swapping ends");
214 my_host
= other_host
;
215 other_host
= tmp_host
;
217 tmp_end
= msg
->add_conn
.me
;
218 msg
->add_conn
.me
= msg
->add_conn
.other
;
219 msg
->add_conn
.other
= tmp_end
;
221 else if (!charon
->socket
->is_listening_on(charon
->socket
, my_host
))
223 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "left nor right host is our side, aborting");
225 my_host
->destroy(my_host
);
226 other_host
->destroy(other_host
);
230 my_id
= identification_create_from_string(msg
->add_conn
.me
.id ?
231 msg
->add_conn
.me
.id
: msg
->add_conn
.me
.address
);
234 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid id: %s", msg
->add_conn
.me
.id
);
235 my_host
->destroy(my_host
);
236 other_host
->destroy(other_host
);
240 other_id
= identification_create_from_string(msg
->add_conn
.other
.id ?
241 msg
->add_conn
.other
.id
: msg
->add_conn
.other
.address
);
242 if (other_id
== NULL
)
244 my_host
->destroy(my_host
);
245 other_host
->destroy(other_host
);
246 my_id
->destroy(my_id
);
247 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid id: %s", msg
->add_conn
.other
.id
);
251 my_subnet
= host_create(AF_INET
, msg
->add_conn
.me
.subnet ?
252 msg
->add_conn
.me
.subnet
: msg
->add_conn
.me
.address
, IKE_PORT
);
253 if (my_subnet
== NULL
)
255 my_host
->destroy(my_host
);
256 other_host
->destroy(other_host
);
257 my_id
->destroy(my_id
);
258 other_id
->destroy(other_id
);
259 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid subnet: %s", msg
->add_conn
.me
.subnet
);
263 other_subnet
= host_create(AF_INET
, msg
->add_conn
.other
.subnet ?
264 msg
->add_conn
.other
.subnet
: msg
->add_conn
.other
.address
, IKE_PORT
);
265 if (other_subnet
== NULL
)
267 my_host
->destroy(my_host
);
268 other_host
->destroy(other_host
);
269 my_id
->destroy(my_id
);
270 other_id
->destroy(other_id
);
271 my_subnet
->destroy(my_subnet
);
272 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid subnet: %s", msg
->add_conn
.me
.subnet
);
276 my_ts
= traffic_selector_create_from_subnet(my_subnet
, msg
->add_conn
.me
.subnet ?
277 msg
->add_conn
.me
.subnet_mask
: 32);
278 my_subnet
->destroy(my_subnet
);
280 other_ts
= traffic_selector_create_from_subnet(other_subnet
, msg
->add_conn
.other
.subnet ?
281 msg
->add_conn
.other
.subnet_mask
: 32);
282 other_subnet
->destroy(other_subnet
);
284 if (msg
->add_conn
.me
.ca
)
286 if (streq(msg
->add_conn
.me
.ca
, "%same"))
292 my_ca
= identification_create_from_string(msg
->add_conn
.me
.ca
);
295 if (msg
->add_conn
.other
.ca
)
297 if (streq(msg
->add_conn
.other
.ca
, "%same"))
299 other_ca_same
= TRUE
;
303 other_ca
= identification_create_from_string(msg
->add_conn
.other
.ca
);
306 if (msg
->add_conn
.me
.cert
)
308 x509_t
*cert
= load_end_certificate(msg
->add_conn
.me
.cert
, &my_id
, this->stroke_logger
);
310 if (my_ca
== NULL
&& !my_ca_same
&& cert
)
312 identification_t
*issuer
= cert
->get_issuer(cert
);
314 my_ca
= issuer
->clone(issuer
);
317 if (msg
->add_conn
.other
.cert
)
319 x509_t
*cert
= load_end_certificate(msg
->add_conn
.other
.cert
, &other_id
, this->stroke_logger
);
321 if (other_ca
== NULL
&& !other_ca_same
&& cert
)
323 identification_t
*issuer
= cert
->get_issuer(cert
);
325 other_ca
= issuer
->clone(issuer
);
328 if (other_ca_same
&& my_ca
)
330 other_ca
= my_ca
->clone(my_ca
);
332 else if (my_ca_same
&& other_ca
)
334 my_ca
= other_ca
->clone(other_ca
);
338 my_ca
= identification_create_from_string("%any");
340 if (other_ca
== NULL
)
342 other_ca
= identification_create_from_string("%any");
344 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, " my ca: '%s'", my_ca
->get_string(my_ca
));
345 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, " other ca:'%s'", other_ca
->get_string(other_ca
));
347 connection
= connection_create(msg
->add_conn
.name
, msg
->add_conn
.ikev2
,
348 msg
->add_conn
.me
.sendcert
, msg
->add_conn
.other
.sendcert
,
350 RSA_DIGITAL_SIGNATURE
);
351 if (msg
->add_conn
.algorithms
.ike
)
353 char *proposal_string
;
354 char *strict
= msg
->add_conn
.algorithms
.ike
+ strlen(msg
->add_conn
.algorithms
.ike
) - 1;
363 while ((proposal_string
= strsep(&msg
->add_conn
.algorithms
.ike
, ",")))
365 proposal
= proposal_create_from_string(PROTO_IKE
, proposal_string
);
366 if (proposal
== NULL
)
368 this->logger
->log(this->logger
, ERROR
, "invalid IKE proposal string: %s", msg
->add_conn
.algorithms
.esp
);
369 my_id
->destroy(my_id
);
370 other_id
->destroy(other_id
);
371 my_ts
->destroy(my_ts
);
372 other_ts
->destroy(other_ts
);
373 my_ca
->destroy(my_ca
);
374 other_ca
->destroy(other_ca
);
375 connection
->destroy(connection
);
378 connection
->add_proposal(connection
, proposal
);
382 proposal
= proposal_create_default(PROTO_IKE
);
383 connection
->add_proposal(connection
, proposal
);
388 proposal
= proposal_create_default(PROTO_IKE
);
389 connection
->add_proposal(connection
, proposal
);
392 policy
= policy_create(msg
->add_conn
.name
, my_id
, other_id
,
393 msg
->add_conn
.rekey
.ipsec_lifetime
,
394 msg
->add_conn
.rekey
.ipsec_lifetime
- msg
->add_conn
.rekey
.margin
,
395 msg
->add_conn
.rekey
.margin
* msg
->add_conn
.rekey
.fuzz
/ 100);
396 policy
->add_my_traffic_selector(policy
, my_ts
);
397 policy
->add_other_traffic_selector(policy
, other_ts
);
398 policy
->add_authorities(policy
, my_ca
, other_ca
);
400 if (msg
->add_conn
.algorithms
.esp
)
402 char *proposal_string
;
403 char *strict
= msg
->add_conn
.algorithms
.esp
+ strlen(msg
->add_conn
.algorithms
.esp
) - 1;
413 while ((proposal_string
= strsep(&msg
->add_conn
.algorithms
.esp
, ",")))
415 proposal
= proposal_create_from_string(PROTO_ESP
, proposal_string
);
416 if (proposal
== NULL
)
418 this->logger
->log(this->logger
, ERROR
,
419 "invalid ESP proposal string: %s", msg
->add_conn
.algorithms
.esp
);
420 policy
->destroy(policy
);
421 connection
->destroy(connection
);
424 policy
->add_proposal(policy
, proposal
);
428 proposal
= proposal_create_default(PROTO_ESP
);
429 policy
->add_proposal(policy
, proposal
);
434 proposal
= proposal_create_default(PROTO_ESP
);
435 policy
->add_proposal(policy
, proposal
);
438 /* add to global connection list */
439 charon
->connections
->add_connection(charon
->connections
, connection
);
440 this->logger
->log(this->logger
, CONTROL
, "added connection \"%s\": %s[%s]...%s[%s]",
442 my_host
->get_address(my_host
),
443 my_id
->get_string(my_id
),
444 other_host
->get_address(other_host
),
445 other_id
->get_string(other_id
));
446 /* add to global policy list */
447 charon
->policies
->add_policy(charon
->policies
, policy
);
451 * Delete a connection from the list
453 static void stroke_del_conn(private_stroke_t
*this, stroke_msg_t
*msg
)
457 pop_string(msg
, &(msg
->del_conn
.name
));
458 this->logger
->log(this->logger
, CONTROL
, "received stroke: delete \"%s\"", msg
->del_conn
.name
);
460 status
= charon
->connections
->delete_connection(charon
->connections
,
462 charon
->policies
->delete_policy(charon
->policies
, msg
->del_conn
.name
);
463 if (status
== SUCCESS
)
465 this->stroke_logger
->log(this->stroke_logger
, CONTROL
,
466 "Deleted connection '%s'", msg
->del_conn
.name
);
470 this->stroke_logger
->log(this->stroke_logger
, ERROR
,
471 "No connection named '%s'", msg
->del_conn
.name
);
476 * initiate a connection by name
478 static void stroke_initiate(private_stroke_t
*this, stroke_msg_t
*msg
)
480 initiate_ike_sa_job_t
*job
;
481 connection_t
*connection
;
482 linked_list_t
*ike_sas
;
483 ike_sa_id_t
*ike_sa_id
;
485 pop_string(msg
, &(msg
->initiate
.name
));
486 this->logger
->log(this->logger
, CONTROL
, "received stroke: initiate \"%s\"", msg
->initiate
.name
);
487 connection
= charon
->connections
->get_connection_by_name(charon
->connections
, msg
->initiate
.name
);
488 if (connection
== NULL
)
490 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "no connection named \"%s\"", msg
->initiate
.name
);
492 /* only initiate if it is an IKEv2 connection, ignore IKEv1 */
493 else if (connection
->is_ikev2(connection
))
495 /* check for already set up IKE_SAs befor initiating */
496 ike_sas
= charon
->ike_sa_manager
->get_ike_sa_list_by_name(charon
->ike_sa_manager
, msg
->initiate
.name
);
497 if (ike_sas
->get_count(ike_sas
) == 0)
499 this->stroke_logger
->log(this->stroke_logger
, CONTROL
,
500 "initiating connection \"%s\" (see log)...", msg
->initiate
.name
);
501 job
= initiate_ike_sa_job_create(connection
);
502 charon
->job_queue
->add(charon
->job_queue
, (job_t
*)job
);
506 this->stroke_logger
->log(this->stroke_logger
, CONTROL
,
507 "connection \"%s\" already up", msg
->initiate
.name
);
509 while (ike_sas
->remove_last(ike_sas
, (void**)&ike_sa_id
) == SUCCESS
)
511 ike_sa_id
->destroy(ike_sa_id
);
513 ike_sas
->destroy(ike_sas
);
518 * terminate a connection by name
520 static void stroke_terminate(private_stroke_t
*this, stroke_msg_t
*msg
)
522 linked_list_t
*ike_sas
;
523 iterator_t
*iterator
;
527 pop_string(msg
, &(msg
->terminate
.name
));
528 this->logger
->log(this->logger
, CONTROL
, "received stroke: terminate \"%s\"", msg
->terminate
.name
);
530 /* we have to do tricky tricks to give the most comprehensive output to the user.
531 * There are different cases:
532 * 1. Connection is available, but IKEv1:
533 * => just ignore it, let pluto print it
534 * 2. Connection is not available, but instances of a deleted connection template:
535 * => terminate them, and print their termination
536 * 3. Connection is not available, and and no instances are there:
537 * => show error about bad connection name
538 * 4. An IKEv2 connection is available, and may contain instances:
539 * => terminate and print, simple
541 conn
= charon
->connections
->get_connection_by_name(charon
->connections
, msg
->terminate
.name
);
542 if (conn
== NULL
|| conn
->is_ikev2(conn
))
544 ike_sas
= charon
->ike_sa_manager
->get_ike_sa_list_by_name(charon
->ike_sa_manager
, msg
->terminate
.name
);
546 iterator
= ike_sas
->create_iterator(ike_sas
, TRUE
);
547 while (iterator
->has_next(iterator
))
549 ike_sa_id_t
*ike_sa_id
;
550 iterator
->current(iterator
, (void**)&ike_sa_id
);
551 charon
->ike_sa_manager
->delete(charon
->ike_sa_manager
, ike_sa_id
);
552 ike_sa_id
->destroy(ike_sa_id
);
555 iterator
->destroy(iterator
);
556 ike_sas
->destroy(ike_sas
);
557 if (conn
== NULL
&& instances
== 0)
559 this->stroke_logger
->log(this->stroke_logger
, CONTROL
,
560 "no connection named \"%s\"",
561 msg
->terminate
.name
);
565 this->stroke_logger
->log(this->stroke_logger
, CONTROL
,
566 "terminated %d instances of \"%s\"",
567 instances
, msg
->terminate
.name
);
577 * show status of (established) connections
579 static void stroke_status(private_stroke_t
*this, stroke_msg_t
*msg
)
581 if (msg
->status
.name
)
583 pop_string(msg
, &(msg
->status
.name
));
585 charon
->connections
->log_connections(charon
->connections
, this->stroke_logger
, msg
->status
.name
);
586 charon
->ike_sa_manager
->log_status(charon
->ike_sa_manager
, this->stroke_logger
, msg
->status
.name
);
590 * list various information
592 static void stroke_list(private_stroke_t
*this, stroke_msg_t
*msg
)
594 if (msg
->list
.flags
& LIST_CERTS
)
596 charon
->credentials
->log_certificates(charon
->credentials
, this->stroke_logger
, msg
->list
.utc
);
598 if (msg
->list
.flags
& LIST_CACERTS
)
600 charon
->credentials
->log_ca_certificates(charon
->credentials
, this->stroke_logger
, msg
->list
.utc
);
602 if (msg
->list
.flags
& LIST_CRLS
)
604 charon
->credentials
->log_crls(charon
->credentials
, this->stroke_logger
, msg
->list
.utc
);
609 * reread various information
611 static void stroke_reread(private_stroke_t
*this, stroke_msg_t
*msg
)
613 if (msg
->reread
.flags
& REREAD_CACERTS
)
615 charon
->credentials
->load_ca_certificates(charon
->credentials
);
617 if (msg
->reread
.flags
& REREAD_CRLS
)
619 charon
->credentials
->load_crls(charon
->credentials
);
623 logger_context_t
get_context(char *context
)
625 if (strcasecmp(context
, "ALL") == 0) return ALL_LOGGERS
;
626 else if (strcasecmp(context
, "PARSR") == 0) return PARSER
;
627 else if (strcasecmp(context
, "GNRAT") == 0) return GENERATOR
;
628 else if (strcasecmp(context
, "IKESA") == 0) return IKE_SA
;
629 else if (strcasecmp(context
, "SAMGR") == 0) return IKE_SA_MANAGER
;
630 else if (strcasecmp(context
, "CHDSA") == 0) return CHILD_SA
;
631 else if (strcasecmp(context
, "MESSG") == 0) return MESSAGE
;
632 else if (strcasecmp(context
, "TPOOL") == 0) return THREAD_POOL
;
633 else if (strcasecmp(context
, "WORKR") == 0) return WORKER
;
634 else if (strcasecmp(context
, "SCHED") == 0) return SCHEDULER
;
635 else if (strcasecmp(context
, "SENDR") == 0) return SENDER
;
636 else if (strcasecmp(context
, "RECVR") == 0) return RECEIVER
;
637 else if (strcasecmp(context
, "SOCKT") == 0) return SOCKET
;
638 else if (strcasecmp(context
, "TESTR") == 0) return TESTER
;
639 else if (strcasecmp(context
, "DAEMN") == 0) return DAEMON
;
640 else if (strcasecmp(context
, "CONFG") == 0) return CONFIG
;
641 else if (strcasecmp(context
, "ENCPL") == 0) return ENCRYPTION_PAYLOAD
;
642 else if (strcasecmp(context
, "PAYLD") == 0) return PAYLOAD
;
643 else if (strcasecmp(context
, "XFRM") == 0) return XFRM
;
648 * set the type of logged messages in a context
650 static void stroke_logtype(private_stroke_t
*this, stroke_msg_t
*msg
)
652 pop_string(msg
, &(msg
->logtype
.context
));
653 pop_string(msg
, &(msg
->logtype
.type
));
655 this->logger
->log(this->logger
, CONTROL
, "received stroke: logtype for %s", msg
->logtype
.context
);
658 logger_context_t context
= get_context(msg
->logtype
.context
);
661 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid context (%s)!", msg
->logtype
.context
);
665 if (strcasecmp(msg
->logtype
.type
, "CONTROL") == 0)
667 else if (strcasecmp(msg
->logtype
.type
, "ERROR") == 0)
669 else if (strcasecmp(msg
->logtype
.type
, "AUDIT") == 0)
671 else if (strcasecmp(msg
->logtype
.type
, "RAW") == 0)
673 else if (strcasecmp(msg
->logtype
.type
, "PRIVATE") == 0)
677 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid type (%s)!", msg
->logtype
.type
);
681 if (msg
->logtype
.enable
)
683 logger_manager
->enable_log_level(logger_manager
, context
, level
);
687 logger_manager
->disable_log_level(logger_manager
, context
, level
);
692 * set the verbosity of a logger
694 static void stroke_loglevel(private_stroke_t
*this, stroke_msg_t
*msg
)
697 logger_context_t context
;
699 pop_string(msg
, &(msg
->loglevel
.context
));
700 this->logger
->log(this->logger
, CONTROL
, "received stroke: loglevel for %s", msg
->loglevel
.context
);
702 context
= get_context(msg
->loglevel
.context
);
705 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid context (%s)!", msg
->loglevel
.context
);
709 if (msg
->loglevel
.level
== 0)
711 else if (msg
->loglevel
.level
== 1)
713 else if (msg
->loglevel
.level
== 2)
715 else if (msg
->loglevel
.level
== 3)
719 this->stroke_logger
->log(this->stroke_logger
, ERROR
, "invalid level (%d)!", msg
->loglevel
.level
);
723 logger_manager
->enable_log_level(logger_manager
, context
, level
);
727 * Implementation of private_stroke_t.stroke_receive.
729 static void stroke_receive(private_stroke_t
*this)
732 u_int16_t msg_length
;
733 struct sockaddr_un strokeaddr
;
734 int strokeaddrlen
= sizeof(strokeaddr
);
740 /* disable cancellation by default */
741 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
745 /* wait for connections, but allow thread to terminate */
746 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
747 strokefd
= accept(this->socket
, (struct sockaddr
*)&strokeaddr
, &strokeaddrlen
);
748 pthread_setcancelstate(oldstate
, NULL
);
752 this->logger
->log(this->logger
, ERROR
, "accepting stroke connection failed: %s", strerror(errno
));
756 /* peek the length */
757 bytes_read
= recv(strokefd
, &msg_length
, sizeof(msg_length
), MSG_PEEK
);
758 if (bytes_read
!= sizeof(msg_length
))
760 this->logger
->log(this->logger
, ERROR
, "reading lenght of stroke message failed");
766 msg
= malloc(msg_length
);
767 bytes_read
= recv(strokefd
, msg
, msg_length
, 0);
768 if (bytes_read
!= msg_length
)
770 this->logger
->log(this->logger
, ERROR
, "reading stroke message failed: %s");
775 strokefile
= fdopen(dup(strokefd
), "w");
776 if (strokefile
== NULL
)
778 this->logger
->log(this->logger
, ERROR
, "opening stroke output channel failed:", strerror(errno
));
784 /* setup a logger which writes status to the unix socket */
785 this->stroke_logger
= logger_create("", CONTROL
|ERROR
, FALSE
, strokefile
);
787 this->logger
->log_bytes(this->logger
, RAW
, "stroke message", (void*)msg
, msg_length
);
792 stroke_initiate(this, msg
);
795 stroke_terminate(this, msg
);
798 stroke_status(this, msg
);
801 this->stroke_logger
->enable_level(this->stroke_logger
, LEVEL1
);
802 stroke_status(this, msg
);
805 stroke_add_conn(this, msg
);
808 stroke_del_conn(this, msg
);
811 stroke_logtype(this, msg
);
814 stroke_loglevel(this, msg
);
817 stroke_list(this, msg
);
820 stroke_reread(this, msg
);
823 this->logger
->log(this->logger
, ERROR
, "received invalid stroke");
825 this->stroke_logger
->destroy(this->stroke_logger
);
833 * Implementation of stroke_t.destroy.
835 static void destroy(private_stroke_t
*this)
838 pthread_cancel(this->assigned_thread
);
839 pthread_join(this->assigned_thread
, NULL
);
842 unlink(socket_addr
.sun_path
);
848 * Described in header-file
850 stroke_t
*stroke_create()
852 private_stroke_t
*this = malloc_thing(private_stroke_t
);
855 /* public functions */
856 this->public.destroy
= (void (*)(stroke_t
*))destroy
;
858 /* private functions */
859 this->stroke_receive
= stroke_receive
;
861 this->logger
= logger_manager
->get_logger(logger_manager
, CONFIG
);
863 /* set up unix socket */
864 this->socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
865 if (this->socket
== -1)
867 this->logger
->log(this->logger
, ERROR
, "could not create whack socket");
872 old
= umask(~S_IRWXU
);
873 if (bind(this->socket
, (struct sockaddr
*)&socket_addr
, sizeof(socket_addr
)) < 0)
875 this->logger
->log(this->logger
, ERROR
, "could not bind stroke socket: %s", strerror(errno
));
882 if (listen(this->socket
, 0) < 0)
884 this->logger
->log(this->logger
, ERROR
, "could not listen on stroke socket: %s", strerror(errno
));
886 unlink(socket_addr
.sun_path
);
891 /* start a thread reading from the socket */
892 if (pthread_create(&(this->assigned_thread
), NULL
, (void*(*)(void*))this->stroke_receive
, this) != 0)
894 this->logger
->log(this->logger
, ERROR
, "Could not spawn stroke thread");
896 unlink(socket_addr
.sun_path
);
901 return (&this->public);