2 * Copyright (C) 2011-2013 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "stroke_socket.h"
20 #include <sys/types.h>
22 #include <sys/socket.h>
29 #include "stroke_config.h"
30 #include "stroke_control.h"
31 #include "stroke_cred.h"
32 #include "stroke_ca.h"
33 #include "stroke_attribute.h"
34 #include "stroke_handler.h"
35 #include "stroke_list.h"
36 #include "stroke_counter.h"
39 * To avoid clogging the thread pool with (blocking) jobs, we limit the number
40 * of concurrently handled stroke commands.
42 #define MAX_CONCURRENT_DEFAULT 4
44 typedef struct stroke_job_context_t stroke_job_context_t
;
45 typedef struct private_stroke_socket_t private_stroke_socket_t
;
48 * private data of stroke_socket
50 struct private_stroke_socket_t
{
55 stroke_socket_t
public;
58 * Service accepting stroke connections
60 stream_service_t
*service
;
63 * configuration backend
65 stroke_config_t
*config
;
70 stroke_attribute_t
*attribute
;
73 * attribute handler (requests only)
75 stroke_handler_t
*handler
;
78 * controller to control daemon
80 stroke_control_t
*control
;
93 * status information logging
98 * Counter values for IKE events
100 stroke_counter_t
*counter
;
103 * TRUE if log level changes are not allowed
105 bool prevent_loglevel_changes
;
109 * Helper macro to log configuration options, but only if they are defined.
111 #define DBG_OPT(...) VA_ARGS_DISPATCH(DBG_OPT, __VA_ARGS__)(__VA_ARGS__)
112 #define DBG_OPT2(fmt, val) ({ \
113 typeof(val) _val = val; \
114 if (_val) { DBG2(DBG_CFG, fmt, _val); } \
116 #define DBG_OPT3(fmt, label, val) ({ \
117 typeof(val) _val = val; \
118 if (_val) { DBG2(DBG_CFG, fmt, label, _val); } \
122 * Helper function which corrects the string pointers
123 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
124 * contains RELATIVE addresses (relative to the beginning of the
125 * stroke_msg). They must be corrected if they reach our address
128 static void pop_string(stroke_msg_t
*msg
, char **string
)
135 /* check for sanity of string pointer and string */
136 if (string
< (char**)msg
||
137 string
> (char**)((char*)msg
+ sizeof(stroke_msg_t
)) ||
138 (unsigned long)*string
< (unsigned long)((char*)msg
->buffer
- (char*)msg
) ||
139 (unsigned long)*string
> msg
->length
)
141 *string
= "(invalid pointer in stroke msg)";
145 *string
= (char*)msg
+ (unsigned long)*string
;
150 * Pop the strings of a stroke_end_t struct and log them for debugging purposes
152 static void pop_end(stroke_msg_t
*msg
, const char* label
, stroke_end_t
*end
)
154 pop_string(msg
, &end
->address
);
155 pop_string(msg
, &end
->subnets
);
156 pop_string(msg
, &end
->sourceip
);
157 pop_string(msg
, &end
->dns
);
158 pop_string(msg
, &end
->auth
);
159 pop_string(msg
, &end
->auth2
);
160 pop_string(msg
, &end
->id
);
161 pop_string(msg
, &end
->id2
);
162 pop_string(msg
, &end
->rsakey
);
163 pop_string(msg
, &end
->cert
);
164 pop_string(msg
, &end
->cert2
);
165 pop_string(msg
, &end
->ca
);
166 pop_string(msg
, &end
->ca2
);
167 pop_string(msg
, &end
->groups
);
168 pop_string(msg
, &end
->groups2
);
169 pop_string(msg
, &end
->cert_policy
);
170 pop_string(msg
, &end
->updown
);
172 DBG_OPT(" %s=%s", label
, end
->address
);
173 DBG_OPT(" %ssubnet=%s", label
, end
->subnets
);
174 DBG_OPT(" %ssourceip=%s", label
, end
->sourceip
);
175 DBG_OPT(" %sdns=%s", label
, end
->dns
);
176 DBG_OPT(" %sauth=%s", label
, end
->auth
);
177 DBG_OPT(" %sauth2=%s", label
, end
->auth2
);
178 DBG_OPT(" %sid=%s", label
, end
->id
);
179 DBG_OPT(" %sid2=%s", label
, end
->id2
);
180 DBG_OPT(" %srsakey=%s", label
, end
->rsakey
);
181 DBG_OPT(" %scert=%s", label
, end
->cert
);
182 DBG_OPT(" %scert2=%s", label
, end
->cert2
);
183 DBG_OPT(" %sca=%s", label
, end
->ca
);
184 DBG_OPT(" %sca2=%s", label
, end
->ca2
);
185 DBG_OPT(" %sgroups=%s", label
, end
->groups
);
186 DBG_OPT(" %sgroups2=%s", label
, end
->groups2
);
187 DBG_OPT(" %supdown=%s", label
, end
->updown
);
191 * Add a connection to the configuration list
193 static void stroke_add_conn(private_stroke_socket_t
*this, stroke_msg_t
*msg
)
195 pop_string(msg
, &msg
->add_conn
.name
);
196 DBG1(DBG_CFG
, "received stroke: add connection '%s'", msg
->add_conn
.name
);
198 DBG2(DBG_CFG
, "conn %s", msg
->add_conn
.name
);
199 pop_end(msg
, "left", &msg
->add_conn
.me
);
200 pop_end(msg
, "right", &msg
->add_conn
.other
);
201 pop_string(msg
, &msg
->add_conn
.eap_identity
);
202 pop_string(msg
, &msg
->add_conn
.aaa_identity
);
203 pop_string(msg
, &msg
->add_conn
.xauth_identity
);
204 pop_string(msg
, &msg
->add_conn
.algorithms
.ike
);
205 pop_string(msg
, &msg
->add_conn
.algorithms
.esp
);
206 pop_string(msg
, &msg
->add_conn
.algorithms
.ah
);
207 pop_string(msg
, &msg
->add_conn
.ikeme
.mediated_by
);
208 pop_string(msg
, &msg
->add_conn
.ikeme
.peerid
);
209 DBG_OPT(" eap_identity=%s", msg
->add_conn
.eap_identity
);
210 DBG_OPT(" aaa_identity=%s", msg
->add_conn
.aaa_identity
);
211 DBG_OPT(" xauth_identity=%s", msg
->add_conn
.xauth_identity
);
212 DBG_OPT(" ike=%s", msg
->add_conn
.algorithms
.ike
);
213 DBG_OPT(" esp=%s", msg
->add_conn
.algorithms
.esp
);
214 DBG_OPT(" ah=%s", msg
->add_conn
.algorithms
.ah
);
215 DBG_OPT(" dpddelay=%d", msg
->add_conn
.dpd
.delay
);
216 DBG_OPT(" dpdtimeout=%d", msg
->add_conn
.dpd
.timeout
);
217 DBG_OPT(" dpdaction=%d", msg
->add_conn
.dpd
.action
);
218 DBG_OPT(" closeaction=%d", msg
->add_conn
.close_action
);
219 DBG_OPT(" sha256_96=%s", msg
->add_conn
.sha256_96 ?
"yes" : "no");
220 DBG_OPT(" mediation=%s", msg
->add_conn
.ikeme
.mediation ?
"yes" : "no");
221 DBG_OPT(" mediated_by=%s", msg
->add_conn
.ikeme
.mediated_by
);
222 DBG_OPT(" me_peerid=%s", msg
->add_conn
.ikeme
.peerid
);
223 DBG_OPT(" keyexchange=ikev%u", msg
->add_conn
.version
);
225 this->config
->add(this->config
, msg
);
226 this->attribute
->add_dns(this->attribute
, msg
);
227 this->handler
->add_attributes(this->handler
, msg
);
231 * Delete a connection from the list
233 static void stroke_del_conn(private_stroke_socket_t
*this, stroke_msg_t
*msg
)
235 pop_string(msg
, &msg
->del_conn
.name
);
236 DBG1(DBG_CFG
, "received stroke: delete connection '%s'", msg
->del_conn
.name
);
238 this->config
->del(this->config
, msg
);
239 this->attribute
->del_dns(this->attribute
, msg
);
240 this->handler
->del_attributes(this->handler
, msg
);
244 * initiate a connection by name
246 static void stroke_initiate(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
248 pop_string(msg
, &msg
->initiate
.name
);
249 DBG1(DBG_CFG
, "received stroke: initiate '%s'", msg
->initiate
.name
);
251 this->control
->initiate(this->control
, msg
, out
);
255 * terminate a connection by name
257 static void stroke_terminate(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
259 pop_string(msg
, &msg
->terminate
.name
);
260 DBG1(DBG_CFG
, "received stroke: terminate '%s'", msg
->terminate
.name
);
262 this->control
->terminate(this->control
, msg
, out
);
266 * terminate a connection by peers virtual IP
268 static void stroke_terminate_srcip(private_stroke_socket_t
*this,
269 stroke_msg_t
*msg
, FILE *out
)
271 pop_string(msg
, &msg
->terminate_srcip
.start
);
272 pop_string(msg
, &msg
->terminate_srcip
.end
);
273 DBG1(DBG_CFG
, "received stroke: terminate-srcip %s-%s",
274 msg
->terminate_srcip
.start
, msg
->terminate_srcip
.end
);
276 this->control
->terminate_srcip(this->control
, msg
, out
);
280 * rekey a connection by name/id
282 static void stroke_rekey(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
284 pop_string(msg
, &msg
->terminate
.name
);
285 DBG1(DBG_CFG
, "received stroke: rekey '%s'", msg
->rekey
.name
);
287 this->control
->rekey(this->control
, msg
, out
);
291 * route a policy (install SPD entries)
293 static void stroke_route(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
295 pop_string(msg
, &msg
->route
.name
);
296 DBG1(DBG_CFG
, "received stroke: route '%s'", msg
->route
.name
);
298 this->control
->route(this->control
, msg
, out
);
304 static void stroke_unroute(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
306 pop_string(msg
, &msg
->terminate
.name
);
307 DBG1(DBG_CFG
, "received stroke: unroute '%s'", msg
->route
.name
);
309 this->control
->unroute(this->control
, msg
, out
);
313 * Add a ca information record to the cainfo list
315 static void stroke_add_ca(private_stroke_socket_t
*this,
316 stroke_msg_t
*msg
, FILE *out
)
318 pop_string(msg
, &msg
->add_ca
.name
);
319 DBG1(DBG_CFG
, "received stroke: add ca '%s'", msg
->add_ca
.name
);
321 pop_string(msg
, &msg
->add_ca
.cacert
);
322 pop_string(msg
, &msg
->add_ca
.crluri
);
323 pop_string(msg
, &msg
->add_ca
.crluri2
);
324 pop_string(msg
, &msg
->add_ca
.ocspuri
);
325 pop_string(msg
, &msg
->add_ca
.ocspuri2
);
326 pop_string(msg
, &msg
->add_ca
.certuribase
);
327 DBG2(DBG_CFG
, "ca %s", msg
->add_ca
.name
);
328 DBG_OPT(" cacert=%s", msg
->add_ca
.cacert
);
329 DBG_OPT(" crluri=%s", msg
->add_ca
.crluri
);
330 DBG_OPT(" crluri2=%s", msg
->add_ca
.crluri2
);
331 DBG_OPT(" ocspuri=%s", msg
->add_ca
.ocspuri
);
332 DBG_OPT(" ocspuri2=%s", msg
->add_ca
.ocspuri2
);
333 DBG_OPT(" certuribase=%s", msg
->add_ca
.certuribase
);
335 this->ca
->add(this->ca
, msg
);
339 * Delete a ca information record from the cainfo list
341 static void stroke_del_ca(private_stroke_socket_t
*this,
342 stroke_msg_t
*msg
, FILE *out
)
344 pop_string(msg
, &msg
->del_ca
.name
);
345 DBG1(DBG_CFG
, "received stroke: delete ca '%s'", msg
->del_ca
.name
);
347 this->ca
->del(this->ca
, msg
);
352 * show status of daemon
354 static void stroke_status(private_stroke_socket_t
*this,
355 stroke_msg_t
*msg
, FILE *out
, bool all
, bool wait
)
357 pop_string(msg
, &(msg
->status
.name
));
359 this->list
->status(this->list
, msg
, out
, all
, wait
);
363 * list various information
365 static void stroke_list(private_stroke_socket_t
*this, stroke_msg_t
*msg
,
368 if (msg
->list
.flags
& LIST_CAINFOS
)
370 this->ca
->list(this->ca
, msg
, out
);
372 this->list
->list(this->list
, msg
, out
);
376 * reread various information
378 static void stroke_reread(private_stroke_socket_t
*this,
379 stroke_msg_t
*msg
, FILE *out
)
381 this->cred
->reread(this->cred
, msg
, out
);
385 * purge various information
387 static void stroke_purge(private_stroke_socket_t
*this,
388 stroke_msg_t
*msg
, FILE *out
)
390 if (msg
->purge
.flags
& PURGE_OCSP
)
392 lib
->credmgr
->flush_cache(lib
->credmgr
, CERT_X509_OCSP_RESPONSE
);
394 if (msg
->purge
.flags
& PURGE_CRLS
)
396 lib
->credmgr
->flush_cache(lib
->credmgr
, CERT_X509_CRL
);
398 if (msg
->purge
.flags
& PURGE_CERTS
)
400 lib
->credmgr
->flush_cache(lib
->credmgr
, CERT_X509
);
402 if (msg
->purge
.flags
& PURGE_IKE
)
404 this->control
->purge_ike(this->control
, msg
, out
);
409 * Print a certificate in PEM to out
411 static void print_pem_cert(FILE *out
, certificate_t
*cert
)
415 if (cert
->get_encoding(cert
, CERT_PEM
, &encoded
))
417 fprintf(out
, "%.*s", (int)encoded
.len
, encoded
.ptr
);
423 * Export in-memory credentials
425 static void stroke_export(private_stroke_socket_t
*this,
426 stroke_msg_t
*msg
, FILE *out
)
428 pop_string(msg
, &msg
->export
.selector
);
430 if (msg
->export
.flags
& EXPORT_X509
)
432 enumerator_t
*enumerator
;
433 identification_t
*id
;
436 id
= identification_create_from_string(msg
->export
.selector
);
437 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
438 CERT_X509
, KEY_ANY
, id
, FALSE
);
439 while (enumerator
->enumerate(enumerator
, &cert
))
441 print_pem_cert(out
, cert
);
443 enumerator
->destroy(enumerator
);
447 if (msg
->export
.flags
& (EXPORT_CONN_CERT
| EXPORT_CONN_CHAIN
))
449 enumerator_t
*sas
, *auths
, *certs
;
455 sas
= charon
->ike_sa_manager
->create_enumerator(
456 charon
->ike_sa_manager
, TRUE
);
457 while (sas
->enumerate(sas
, &ike_sa
))
459 if (streq(msg
->export
.selector
, ike_sa
->get_name(ike_sa
)))
461 auths
= ike_sa
->create_auth_cfg_enumerator(ike_sa
, FALSE
);
462 while (auths
->enumerate(auths
, &auth
))
464 bool got_subject
= FALSE
;
466 certs
= auth
->create_enumerator(auth
);
467 while (certs
->enumerate(certs
, &rule
, &cert
))
471 case AUTH_RULE_CA_CERT
:
472 case AUTH_RULE_IM_CERT
:
473 if (msg
->export
.flags
& EXPORT_CONN_CHAIN
)
475 print_pem_cert(out
, cert
);
478 case AUTH_RULE_SUBJECT_CERT
:
481 print_pem_cert(out
, cert
);
489 certs
->destroy(certs
);
491 auths
->destroy(auths
);
501 static void stroke_leases(private_stroke_socket_t
*this,
502 stroke_msg_t
*msg
, FILE *out
)
504 pop_string(msg
, &msg
->leases
.pool
);
505 pop_string(msg
, &msg
->leases
.address
);
507 this->list
->leases(this->list
, msg
, out
);
511 * Callback function for usage report
513 static void report_usage(FILE *out
, int count
, size_t bytes
,
514 backtrace_t
*bt
, bool detailed
)
516 fprintf(out
, "%zu bytes total, %d allocations, %zu bytes average:\n",
517 bytes
, count
, bytes
/ count
);
518 bt
->log(bt
, out
, detailed
);
522 * Callback function for memusage summary
524 static void sum_usage(FILE *out
, int count
, size_t bytes
, int whitelisted
)
526 fprintf(out
, "Total memory usage: %zu\n", bytes
);
532 static void stroke_memusage(private_stroke_socket_t
*this,
533 stroke_msg_t
*msg
, FILE *out
)
535 if (lib
->leak_detective
)
537 lib
->leak_detective
->usage(lib
->leak_detective
,
538 (leak_detective_report_cb_t
)report_usage
,
539 (leak_detective_summary_cb_t
)sum_usage
, out
);
544 * Set username and password for a connection
546 static void stroke_user_creds(private_stroke_socket_t
*this,
547 stroke_msg_t
*msg
, FILE *out
)
549 pop_string(msg
, &msg
->user_creds
.name
);
550 pop_string(msg
, &msg
->user_creds
.username
);
551 pop_string(msg
, &msg
->user_creds
.password
);
553 DBG1(DBG_CFG
, "received stroke: user-creds '%s'", msg
->user_creds
.name
);
555 this->config
->set_user_credentials(this->config
, msg
, out
);
559 * Print stroke counter values
561 static void stroke_counters(private_stroke_socket_t
*this,
562 stroke_msg_t
*msg
, FILE *out
)
564 pop_string(msg
, &msg
->counters
.name
);
566 if (msg
->counters
.reset
)
568 this->counter
->reset(this->counter
, msg
->counters
.name
);
572 this->counter
->print(this->counter
, out
, msg
->counters
.name
);
577 * set the verbosity debug output
579 static void stroke_loglevel(private_stroke_socket_t
*this,
580 stroke_msg_t
*msg
, FILE *out
)
584 pop_string(msg
, &(msg
->loglevel
.type
));
585 DBG1(DBG_CFG
, "received stroke: loglevel %d for %s",
586 msg
->loglevel
.level
, msg
->loglevel
.type
);
588 if (this->prevent_loglevel_changes
)
590 DBG1(DBG_CFG
, "prevented log level change");
591 fprintf(out
, "command not allowed!\n");
594 if (!enum_from_name(debug_names
, msg
->loglevel
.type
, &group
))
596 fprintf(out
, "unknown type '%s'!\n", msg
->loglevel
.type
);
599 charon
->set_level(charon
, group
, msg
->loglevel
.level
);
603 * set various config options
605 static void stroke_config(private_stroke_socket_t
*this,
606 stroke_msg_t
*msg
, FILE *out
)
608 this->cred
->cachecrl(this->cred
, msg
->config
.cachecrl
);
612 * process a stroke request
614 static bool on_accept(private_stroke_socket_t
*this, stream_t
*stream
)
621 if (!stream
->read_all(stream
, &len
, sizeof(len
)))
623 if (errno
!= EWOULDBLOCK
)
625 DBG1(DBG_CFG
, "reading length of stroke message failed: %s",
630 if (len
< offsetof(stroke_msg_t
, buffer
))
632 DBG1(DBG_CFG
, "invalid stroke message length %d", len
);
636 /* read message (we need an additional byte to terminate the buffer) */
637 msg
= malloc(len
+ 1);
639 if (!stream
->read_all(stream
, (char*)msg
+ sizeof(len
), len
- sizeof(len
)))
641 if (errno
!= EWOULDBLOCK
)
643 DBG1(DBG_CFG
, "reading stroke message failed: %s", strerror(errno
));
648 /* make sure even incorrectly unterminated strings don't extend over the
649 * message boundaries */
650 ((char*)msg
)[len
] = '\0';
652 DBG3(DBG_CFG
, "stroke message %b", (void*)msg
, len
);
654 out
= stream
->get_file(stream
);
657 DBG1(DBG_CFG
, "creating stroke output stream failed");
664 stroke_initiate(this, msg
, out
);
667 stroke_route(this, msg
, out
);
670 stroke_unroute(this, msg
, out
);
673 stroke_terminate(this, msg
, out
);
675 case STR_TERMINATE_SRCIP
:
676 stroke_terminate_srcip(this, msg
, out
);
679 stroke_rekey(this, msg
, out
);
682 stroke_status(this, msg
, out
, FALSE
, TRUE
);
685 stroke_status(this, msg
, out
, TRUE
, TRUE
);
687 case STR_STATUS_ALL_NOBLK
:
688 stroke_status(this, msg
, out
, TRUE
, FALSE
);
691 stroke_add_conn(this, msg
);
694 stroke_del_conn(this, msg
);
697 stroke_add_ca(this, msg
, out
);
700 stroke_del_ca(this, msg
, out
);
703 stroke_loglevel(this, msg
, out
);
706 stroke_config(this, msg
, out
);
709 stroke_list(this, msg
, out
);
712 stroke_reread(this, msg
, out
);
715 stroke_purge(this, msg
, out
);
718 stroke_export(this, msg
, out
);
721 stroke_leases(this, msg
, out
);
724 stroke_memusage(this, msg
, out
);
727 stroke_user_creds(this, msg
, out
);
730 stroke_counters(this, msg
, out
);
733 DBG1(DBG_CFG
, "received unknown stroke");
741 METHOD(stroke_socket_t
, destroy
, void,
742 private_stroke_socket_t
*this)
744 DESTROY_IF(this->service
);
745 lib
->credmgr
->remove_set(lib
->credmgr
, &this->ca
->set
);
746 lib
->credmgr
->remove_set(lib
->credmgr
, &this->cred
->set
);
747 charon
->backends
->remove_backend(charon
->backends
, &this->config
->backend
);
748 charon
->attributes
->remove_provider(charon
->attributes
,
749 &this->attribute
->provider
);
750 charon
->attributes
->remove_handler(charon
->attributes
,
751 &this->handler
->handler
);
752 this->cred
->destroy(this->cred
);
753 this->ca
->destroy(this->ca
);
754 this->config
->destroy(this->config
);
755 this->attribute
->destroy(this->attribute
);
756 this->handler
->destroy(this->handler
);
757 this->control
->destroy(this->control
);
758 this->list
->destroy(this->list
);
759 this->counter
->destroy(this->counter
);
766 stroke_socket_t
*stroke_socket_create()
768 private_stroke_socket_t
*this;
776 .prevent_loglevel_changes
= lib
->settings
->get_bool(lib
->settings
,
777 "%s.plugins.stroke.prevent_loglevel_changes", FALSE
, lib
->ns
),
780 this->ca
= stroke_ca_create();
781 this->cred
= stroke_cred_create(this->ca
);
782 this->attribute
= stroke_attribute_create();
783 this->handler
= stroke_handler_create();
784 this->config
= stroke_config_create(this->ca
, this->cred
, this->attribute
);
785 this->control
= stroke_control_create();
786 this->list
= stroke_list_create(this->attribute
);
787 this->counter
= stroke_counter_create();
789 lib
->credmgr
->add_set(lib
->credmgr
, &this->ca
->set
);
790 lib
->credmgr
->add_set(lib
->credmgr
, &this->cred
->set
);
791 charon
->backends
->add_backend(charon
->backends
, &this->config
->backend
);
792 charon
->attributes
->add_provider(charon
->attributes
,
793 &this->attribute
->provider
);
794 charon
->attributes
->add_handler(charon
->attributes
,
795 &this->handler
->handler
);
798 max_concurrent
= lib
->settings
->get_int(lib
->settings
,
799 "%s.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT
,
801 uri
= lib
->settings
->get_str(lib
->settings
,
802 "%s.plugins.stroke.socket", "unix://" STROKE_SOCKET
, lib
->ns
);
803 this->service
= lib
->streams
->create_service(lib
->streams
, uri
, 10);
806 DBG1(DBG_CFG
, "creating stroke socket failed");
810 this->service
->on_accept(this->service
, (stream_service_cb_t
)on_accept
,
811 this, JOB_PRIO_CRITICAL
, max_concurrent
);
813 return &this->public;